1335 Commits
2.4 ... 3.0

Author SHA1 Message Date
Nicholas Marriott
c22470bd14 3.0-rc3. 2019-06-14 16:17:34 +01:00
Nicholas Marriott
31cb95893e #{ is no longer special. 2019-06-14 16:10:27 +01:00
nicm
52b8274285 Do not crash if the environment variable is present but empty. 2019-06-14 16:06:12 +01:00
nicm
a924694820 Use the right client when working out where to save or load the buffer,
reported by kn@.
2019-06-14 16:04:57 +01:00
nicm
0a94dbe051 A couple of minor parser changes around conditions: 1) only treat #{
specially after a condition, otherwise as a comment (which is more as
most people expect) 2) allow formats to be quoted after a condition.
2019-06-14 16:04:52 +01:00
Nicholas Marriott
ebc9dcb3bb Add a bit to {}. 2019-06-14 12:40:35 +01:00
Nicholas Marriott
f31847db62 Improve description of #{. 2019-06-14 10:33:55 +01:00
nicm
e337c1ba7d Do not try to parse command when unsetting, GitHub issue 1788. 2019-06-11 15:51:30 +01:00
nicm
db5a7c1740 Need to increment the argument to skip the prefix earlier, fixes
repeated incremental search in copy mode, reported by Kaushal Modi in
GitHub issue 1780.
2019-06-05 21:06:06 +01:00
Nicholas Marriott
53914e50b9 RC2. 2019-06-05 15:09:42 +01:00
Nicholas Marriott
e252984993 If only one of -x or -y is given, use the calculated size for the
other. Also fix some warnings. Pointed out by Ben Boeckel.
2019-06-05 06:44:08 +01:00
nicm
17bc11bd15 yacc(1) copies its union so it is not a good place to store
TAILQ_HEADs. Allocate them instead. Found from a problem reported by
sthen@.
2019-06-02 10:52:32 +01:00
nicm
1a3a973bd0 Allow % strings that are all numbers or %s, and fix a double free. Both
reported by George Nachman, GitHub issues 1765 and 1766.
2019-05-31 15:18:25 +01:00
nicm
e4eec92852 No longer need to reduce line number by one. 2019-05-30 13:12:35 +01:00
nicm
75d112c484 The line number needs to be updated only after the \n is processed by
the parser, so store a flag and update it next time around. Also each
new line needs its own shared data.
2019-05-29 23:04:22 +01:00
Nicholas Marriott
a05c3a7aa6 Add command order test. 2019-05-29 20:43:11 +01:00
Nicholas Marriott
47795d1695 Update .travis.yml from master. 2019-05-29 14:40:41 +01:00
Nicholas Marriott
7cdb1cfc8d as -> and. 2019-05-29 12:13:46 +01:00
Nicholas Marriott
8827b7f9a6 Tweak {} text. 2019-05-29 11:25:07 +01:00
nicm
7eeb479705 Do not read past the end of the argument string if it is empty. 2019-05-28 21:04:41 +01:00
nicm
8d137233a9 Redraw status line if size changes, GitHub issue 1762. Also fix length
of target buffer when pasting into status line.
2019-05-28 21:04:35 +01:00
Nicholas Marriott
05d07413ff 3.0-rc. 2019-05-28 15:46:17 +01:00
Thomas Adam
b8360504f3 Merge branch 'obsd-master' 2019-05-28 15:02:26 +01:00
Nicholas Marriott
a062650d4b Tweak menu option. 2019-05-28 14:49:50 +01:00
Nicholas Marriott
f012db9be9 Add regress for conf files. 2019-05-28 13:21:19 +01:00
nicm
299d4f3aaa Exit 1 correctly if source-file fails. 2019-05-28 12:20:28 +00:00
Thomas Adam
eba6cf61c9 Merge branch 'obsd-master' 2019-05-28 13:02:27 +01:00
nicm
0ec410689c Allow source-file to take multiple arguments. 2019-05-28 11:46:30 +00:00
nicm
e0fd295054 Change the default right click pane to open the menu if not in a mode
and no application mouse.
2019-05-28 10:27:11 +00:00
nicm
99a8469ee4 Add key bindings to open the window and pane menus (C-m and M-m for now). 2019-05-28 10:05:24 +00:00
nicm
12255411f2 Allow menu items to be disabled by putting a - at the start of their
name, rather than just including #[dim] which still allowed them to be
chosen.
2019-05-28 09:50:54 +00:00
Thomas Adam
c0116b2c5b Merge branch 'obsd-master' 2019-05-28 09:02:26 +01:00
nicm
799a154b91 Change display-menu from taking a single string to a set of arguments,
which is much easier to work with. Based on a diff from Avi Halachmi.
2019-05-28 07:18:42 +00:00
Thomas Adam
793f4d89d6 Merge branch 'obsd-master' 2019-05-27 19:02:25 +01:00
nicm
90cd045cf3 Clarify newlines inside {} a little. 2019-05-27 16:22:32 +00:00
nicm
94f6488f0e Go less crazy with horizontal separators on default menus. 2019-05-27 15:29:46 +00:00
Thomas Adam
d4bf4bd7c7 Merge branch 'obsd-master' 2019-05-27 15:02:28 +01:00
Nicholas Marriott
522d1bd309 Add. 2019-05-27 14:39:44 +01:00
Nicholas Marriott
a21de4c483 Mention <><=>=. 2019-05-27 14:39:06 +01:00
Nicholas Marriott
714311a696 Add {}. 2019-05-27 14:37:47 +01:00
Nicholas Marriott
9f0904ce6f Remove unused fparseln compat code. 2019-05-27 14:28:05 +01:00
nicm
ae3eba6e08 Fix crash when killing the current window, reported by Jesus Rafael
Sanchez in GitHub issue 1760.
2019-05-27 12:48:52 +00:00
nicm
6b332127ca Add an additional {} syntax for defining strings in the configuration
file, making it much tidier to define commands that contain other tmux
or shell commands (like if-shell). Also tweak bind-key to expect a
string if it is only given one argument, so {} can be used with it as
well. From Avi Halachmi.
2019-05-27 12:16:27 +00:00
Thomas Adam
bd40d704e2 Merge branch 'obsd-master' 2019-05-27 09:02:26 +01:00
nicm
65e5e14561 Fix the intended ordering of items in buffer mode - it should not always
be tag 0 when the tree is empty. GitHub issue 1759.
2019-05-27 06:50:04 +00:00
Thomas Adam
103e44d936 Merge branch 'obsd-master' 2019-05-26 21:02:26 +01:00
nicm
097973e3d5 Add keys for new menu items. 2019-05-26 18:43:43 +00:00
nicm
5fef946df4 Always redraw overlay if it is on (so status line doesn't redraw over it). 2019-05-26 18:27:52 +00:00
nicm
023c2c5392 Do not accept choice unless mouse has actually moved before. 2019-05-26 18:19:52 +00:00
nicm
e90d4a6021 Add formats for word and line under the mouse and use them to add some
items to the pane menu.
2019-05-26 17:34:45 +00:00
Thomas Adam
2e84d1cf03 Merge branch 'obsd-master' 2019-05-26 15:02:25 +01:00
nicm
6431005169 Add a way to append or prepend to a format if the length has been limited. 2019-05-26 12:02:42 +00:00
Thomas Adam
9beb3eb593 Merge branch 'obsd-master' 2019-05-26 13:02:26 +01:00
nicm
6dee409981 Some other platforms doesn't support fmemopen(3) (not unexpectedly), so
don't use it - since we only use getc/ungetc on the file anyway it is
easy not to.
2019-05-26 10:08:50 +00:00
Thomas Adam
f3fc81b178 Merge branch 'master' of github.com:ThomasAdam/tmux 2019-05-25 18:50:05 +01:00
Thomas Adam
463bd8abb9 Merge branch 'obsd-master' 2019-05-25 18:41:51 +01:00
nicm
a65a6d62d1 Add <, >, <=, >= for formats, GitHub issue 1747. 2019-05-25 16:51:10 +00:00
nicm
207789dc2d Client name can actually be NULL, so use address in that case. 2019-05-25 10:46:55 +00:00
nicm
d7586d3d65 Use client name when logging command queue. 2019-05-25 10:44:09 +00:00
nicm
f8d3d247d8 Merge cmd_list_parse into cmd-parse.y so it can use the new alias
processing code.
2019-05-25 07:18:20 +00:00
nicm
6b0fa14470 Fix error handling in if-shell. 2019-05-25 07:15:53 +00:00
Nicholas Marriott
a69211aff5 Fix up regress test. 2019-05-25 08:09:23 +01:00
nicm
930245d7ff Make cmd_log_argv take a printf-like format for the prefix. 2019-05-25 06:58:10 +00:00
espie
0dc8b7d5d8 unbreak build, okay nicm@ 2019-05-23 21:36:42 +00:00
Thomas Adam
19a3a9ee20 Merge branch 'obsd-master' 2019-05-23 21:02:30 +01:00
nicm
f3e01ecc42 Fix line numbers - commands are added after the line ends so they need to
get line - 1.
2019-05-23 18:39:00 +00:00
nicm
6c260af56d Use the same argument escaping code for options as well. 2019-05-23 18:33:53 +00:00
Nicholas Marriott
e817821104 Mention \. 2019-05-23 19:27:41 +01:00
nicm
f006116bac Environment variables can start with { also. 2019-05-23 18:22:13 +00:00
Thomas Adam
43431e7e84 Merge branch 'obsd-master' 2019-05-23 17:02:25 +01:00
nicm
eb8b51effc Fix drawing of status-right when it is aligned to the centre, GitHub
issue 1754.
2019-05-23 14:44:33 +00:00
Nicholas Marriott
389cf63cbc Tweak text. 2019-05-23 15:18:20 +01:00
Thomas Adam
2148fe33cd CHANGES: remove note to packagers 2019-05-23 15:16:10 +01:00
Thomas Adam
1a6540fea0 CHANGES: remove note to packagers 2019-05-23 15:15:42 +01:00
nicm
7d702f3cef Don't remove group items for group 0 (no group). 2019-05-23 15:15:42 +01:00
nicm
d0c462f718 Fix length calculation for pasting UTF-8 characters in the status line,
GitHub issue 1753.
2019-05-23 15:15:42 +01:00
Thomas Adam
238d2aa870 CHANGES: mention yacc 2019-05-23 15:12:24 +01:00
Thomas Adam
6bb505eb73 CHANGES: mention yacc 2019-05-23 15:11:25 +01:00
Nicholas Marriott
83b9807370 Remove duplicate. 2019-05-23 15:11:25 +01:00
Nicholas Marriott
3e6e533779 Add yacc(1) bits. 2019-05-23 15:11:25 +01:00
nicm
27bfb56ad5 Break the argument escaping code into a separate function and use it to
escape key bindings in list-keys. Also escape ~ and ; and $ properly.
2019-05-23 14:03:44 +00:00
Thomas Adam
c49f2a0365 Merge branch 'obsd-master' 2019-05-23 15:02:28 +01:00
nicm
3e3eb1dd0f Don't remove group items for group 0 (no group). 2019-05-23 13:08:43 +00:00
nicm
a4fe7e81c8 Fix length calculation for pasting UTF-8 characters in the status line,
GitHub issue 1753.
2019-05-23 12:47:52 +00:00
Nicholas Marriott
4ce26b0393 Remove duplicate. 2019-05-23 13:32:18 +01:00
Thomas Adam
82bf0f4d48 configure.ac: add AC_PROC_YACC 2019-05-23 13:12:03 +01:00
Thomas Adam
8590ee65e6 TRAVIS: add bison to build deps 2019-05-23 13:12:03 +01:00
Thomas Adam
d67b99c7e4 configure.ac: add AC_PROC_YACC 2019-05-23 13:09:34 +01:00
Thomas Adam
092c7bfeb8 TRAVIS: add bison to build deps 2019-05-23 13:06:47 +01:00
Nicholas Marriott
bf2cf33fc6 Add yacc(1) bits. 2019-05-23 13:04:41 +01:00
Thomas Adam
75aeb733f2 Merge branch 'obsd-master' 2019-05-23 13:02:27 +01:00
nicm
723010ba72 Replace the split parser code (cfg.c and cmd-string.c) with a single
parser using yacc(1). This is a major change but is clearer and simpler
and allows some edge cases to be made more consistent, as well as
tidying up how aliases are handled. It will also allow some further
improvements later.

Entirely the same parser is now used for parsing the configuration file
and for string commands. This means that constructs previously only
available in .tmux.conf, such as %if, can now be used in string commands
(for example, those given to if-shell - not commands invoked from the
shell, they are still parsed by the shell itself).

The only syntax change I am aware of is that #{} outside quotes or a
comment is now considered a format and not a comment, so #{ is now a
syntax error (notably, if it is at the start of a line).

This also adds two new sections to the man page documenting the syntax
and outlining how parsing and command execution works.

Thanks to everyone who sent me test configs (they still all parse
without errors - but this doesn't mean they still work as intended!).

Thanks to Avi Halachmi for testing and man page improvements, also to
jmc@ for reviewing the man page changes.
2019-05-23 11:13:30 +00:00
Nicholas Marriott
7ca2e2fe88 Add a config. 2019-05-23 11:57:04 +01:00
Thomas Adam
9d450cc6d0 Merge branch 'obsd-master' 2019-05-22 21:02:28 +01:00
nicm
5571d7a21c Fix crash if window doesn't exist, GitHub issue 1751. 2019-05-22 18:58:31 +00:00
Nicholas Marriott
e353d0cab3 Another config. 2019-05-22 19:49:48 +01:00
Nicholas Marriott
282f7fbd37 Add a test config. 2019-05-22 13:31:20 +01:00
Nicholas Marriott
b68fc7f104 Two more configs. 2019-05-22 07:12:38 +01:00
Nicholas Marriott
54dfe36340 Another. 2019-05-21 17:07:08 +01:00
Thomas Adam
c4f4904f9b More configs 2019-05-21 16:43:34 +01:00
Nicholas Marriott
d769fec8d6 More configs. 2019-05-21 14:41:07 +01:00
Nicholas Marriott
f1ce611345 Add another one. 2019-05-21 11:28:12 +01:00
Thomas Adam
3856116069 Merge branch 'obsd-master' 2019-05-21 09:02:37 +01:00
Nicholas Marriott
afe231c94c Add a few test configs thanks to various people. 2019-05-21 08:02:17 +01:00
nicm
ae4cccb4f1 Fix a couple of Ta from Alphonse Mariya. 2019-05-21 07:01:14 +00:00
Thomas Adam
98ee93bde3 Merge branch 'obsd-master' 2019-05-20 15:02:40 +01:00
nicm
87d82170a6 Fix ordering of source-file with multiple files and add flags to load_cfg. 2019-05-20 13:23:32 +00:00
Thomas Adam
3a7e15511b Merge branch 'obsd-master' 2019-05-20 13:02:36 +01:00
nicm
e128c7fcd8 Replace the various identical error callbacks with a single one in cmd-queue.c. 2019-05-20 11:46:06 +00:00
nicm
8db89f8efb Add a helper to allocate a cmd_list. 2019-05-20 11:34:37 +00:00
Thomas Adam
c271cb9ff8 Merge branch 'obsd-master' 2019-05-20 07:02:36 +01:00
nicm
6e0c663a89 Fix the color space parameter in RGB SGR, from Brad Town. 2019-05-20 05:35:46 +00:00
Thomas Adam
56246c2936 README.md: mention TODO list on the tmux wiki 2019-05-19 13:31:09 +01:00
Thomas Adam
54da493476 Merge branch 'obsd-master' 2019-05-18 23:02:36 +01:00
nicm
82ebd98c5f Move the single command flag (CMD_CONTROL) into the shared flags. 2019-05-18 21:14:10 +00:00
Nicholas Marriott
831c67c2d8 Remove TODO, moving onto website. 2019-05-18 14:44:31 +01:00
Nicholas Marriott
d6f7be6345 Add to CHANGES. 2019-05-18 13:29:38 +01:00
Thomas Adam
eb064e8a62 Merge branch 'obsd-master' 2019-05-17 09:02:36 +01:00
nicm
9b83b1daa6 Change a couple of ACS characters to be more sensible and add a few
missing ones, reported by Ricardo Banffy.
2019-05-17 05:48:25 +00:00
nicm
4acd345c6a Initialize default size variables, from Thomas Adam. 2019-05-17 05:47:31 +00:00
Thomas Adam
d9ac0e7576 Merge branch 'obsd-master' 2019-05-15 22:50:42 +01:00
Nicholas Marriott
dcf0bc2cc9 Mention CONTRIBUTING. 2019-05-15 21:42:43 +01:00
nicm
cf4566b47b Fix dragging when in view mode rather than copy mode, GitHub issue 1740
from Brad Town.
2019-05-15 19:25:53 +00:00
Nicholas Marriott
50e77536fe Less headings. 2019-05-15 20:21:38 +01:00
Nicholas Marriott
cd4e467751 Kill tmux for logs. 2019-05-15 20:21:07 +01:00
Thomas Adam
9228fead48 Merge branch 'obsd-master' 2019-05-14 09:02:28 +01:00
nicm
38b8a198ba Fix sizing of main-vertical and main-horizontal layouts, GitHub issue 1736. 2019-05-14 07:37:50 +00:00
Thomas Adam
1eefbd28e8 Merge branch 'obsd-master' 2019-05-13 23:02:26 +01:00
nicm
1ee944a19d Add support for overline (SGR 53), from Ricardo Banffy. 2019-05-13 20:10:23 +00:00
nicm
1b0512aa7e Always include Lock in the menu. 2019-05-13 20:07:02 +00:00
Thomas Adam
b5b5d35eee Merge branch 'obsd-master' 2019-05-13 11:02:31 +01:00
nicm
c5f660e33a Fix column width for copy mode commands. 2019-05-13 08:56:07 +00:00
Nicholas Marriott
e1e520d741 Clarify a little. 2019-05-13 09:51:51 +01:00
Thomas Adam
699d9d2fac Merge branch 'obsd-master' 2019-05-12 21:02:27 +01:00
nicm
c3c3927c2b Oops, removed too much in last change. 2019-05-12 18:18:30 +00:00
nicm
00f19b7f91 Fix some indentation and dead assignments. 2019-05-12 18:16:33 +00:00
Thomas Adam
42da951edf README.md: avaailable -> available
Correct typo.
2019-05-12 18:37:32 +01:00
Thomas Adam
180bbab1fc Merge branch 'obsd-master' 2019-05-12 11:02:25 +01:00
Nicholas Marriott
69c59c52b6 Spelling error. 2019-05-12 10:06:42 +01:00
Nicholas Marriott
19370631ea Tweak text of menu CHANGES entry. 2019-05-12 10:05:10 +01:00
Nicholas Marriott
99c1853792 Scatter some `. 2019-05-12 10:00:31 +01:00
nicm
a131655235 Add simple menus to tree, client, buffer modes. 2019-05-12 08:58:09 +00:00
Thomas Adam
677bb168a9 Merge branch 'obsd-master' 2019-05-12 09:02:28 +01:00
nicm
c91323e4d6 Remove menu_create_from_items, I thought I would use it for some later
work but I don't need it.
2019-05-12 07:27:08 +00:00
Thomas Adam
50d1d04913 Merge branch 'obsd-master' 2019-05-11 09:02:29 +01:00
Nicholas Marriott
67e2f5869a Mention -vv. 2019-05-11 08:34:08 +01:00
Nicholas Marriott
3a9c199ae7 New ISSUE_TEMPLATE from Nicolas CARPi. 2019-05-11 08:23:14 +01:00
Nicholas Marriott
bd6d0b3101 Formatted README.md, from Nicolas CARPi. 2019-05-11 08:19:14 +01:00
Nicholas Marriott
f1dd65cbdf Another tweak. 2019-05-11 08:09:49 +01:00
Nicholas Marriott
c18d7c5fcb Update CONTRIBUTING.md, mostly from Nicolas CARPi. 2019-05-11 08:07:35 +01:00
Nicholas Marriott
0d64531f66 Tweaks to README, some from me, some from Nicolas CARPi. 2019-05-11 07:55:28 +01:00
Nicholas Marriott
f44dafd224 Add to CHANGES. 2019-05-11 07:43:18 +01:00
nicm
198b0a23a2 Don't use arguments with It and -enum, pointed out by jmc. 2019-05-11 06:40:01 +00:00
nicm
ad27b7decd Do not reduce window height by status line height for control mode
clients, from George Nachman.
2019-05-11 06:34:56 +00:00
Thomas Adam
fc00839adc Update CHANGES 2019-05-10 22:27:33 +01:00
Thomas Adam
aa13bd4016 Merge branch 'obsd-master' 2019-05-10 22:10:38 +01:00
nicm
d62fd78655 Fix a typo in previous (, -> :). 2019-05-10 18:09:51 +00:00
nicm
6dcca5fda4 Add support for simple menus usable with mouse or keyboard. New command
display-menu shows a menu (bound to the mouse on status line by default)
and a couple of extra formats for the default menus.
2019-05-10 18:04:06 +00:00
Thomas Adam
c5f6ea5c0d Merge branch 'obsd-master' 2019-05-10 17:02:27 +01:00
nicm
004a9b52f0 Add a function to draw a simple menu onto a screen. 2019-05-10 14:12:47 +00:00
Thomas Adam
e5f06d2cf6 Merge branch 'obsd-master' 2019-05-09 17:02:25 +01:00
nicm
cb10bfb8ef Save mouse buttons as well as position. 2019-05-09 14:09:32 +00:00
Thomas Adam
2e00d775e4 Merge branch 'obsd-master' 2019-05-09 15:02:26 +01:00
nicm
21d9750450 send-keys also needs to insert key commands in the right order. 2019-05-09 13:12:59 +00:00
Thomas Adam
f431e20f3d Merge branch 'obsd-master' 2019-05-09 11:02:25 +01:00
nicm
3c68e51609 Change swap-window -d to be the other way round (stay with src window),
so it works like swap-pane.
2019-05-09 08:39:09 +00:00
nicm
299b7289ea Add formats to show if pane is the marked pane and if any marked pane is set. 2019-05-09 08:38:13 +00:00
Thomas Adam
4bc45fc95a Merge branch 'obsd-master' 2019-05-08 21:02:25 +01:00
nicm
f9682d2e55 Add a flag to redraw only the overlay, and remove the overlay on resize. 2019-05-08 18:07:12 +00:00
nicm
a384245c5a Adjust how mouse targets are found so they always have a session, window
and pane.
2019-05-08 18:05:03 +00:00
Thomas Adam
b24d7d9c95 Merge branch 'obsd-master' 2019-05-07 23:02:30 +01:00
Thomas Adam
453a62c672 Merge branch 'obsd-master' 2019-05-07 21:02:25 +01:00
nicm
89db309e10 Move around the display-panes identify code to make it a bit more
generic and hide the display-panes specific bits into
cmd-display-panes.c.
2019-05-07 20:01:41 +00:00
nicm
d53d3bce59 Adjust the same bit to adjust the selection for history-top and
history-bottom as for cursor-up and cursor-down. GitHub issue 1723.
2019-05-07 19:46:17 +00:00
Thomas Adam
3439c02e9d Merge branch 'obsd-master' 2019-05-07 17:02:25 +01:00
schwarze
fcd0e3082b Rename the ENVIRONMENT section which was squatting on the standard
manual page section and create a new ENVIRONMENT with the expected
content.  Move some information that was misplaced below the -u
flag into that new section.
Feedback and OK nicm@ jmc@ tb@
2019-05-07 14:01:39 +00:00
Thomas Adam
d9767b8112 Merge branch 'obsd-master' 2019-05-07 13:02:27 +01:00
nicm
85a9c2f52b Treat keys in identify mode (display-panes) specially and handle them
immediately rather than queuing them (the command can block the queue
which means they were not being seen until it finished which was too
late). Reported by denis@ and solene@, ok solene@.
2019-05-07 11:24:03 +00:00
nicm
69440d19b7 Do not use evbuffer_add_buffer because it is destructive and doesn't
work in newer libevent.
2019-05-07 10:25:15 +00:00
Nicholas Marriott
eac30a86d7 -attr -> -style. 2019-05-06 21:57:32 +01:00
Thomas Adam
d4177e954c Merge branch 'obsd-master' 2019-05-03 23:02:28 +01:00
nicm
45ae9a8e35 Fix order of insertion in load_cfg. 2019-05-03 21:21:00 +00:00
nicm
9f75635596 Allow panes to be empty (no command), output can be piped to them with
split-window or display-message -I.
2019-05-03 20:44:24 +00:00
Thomas Adam
4d505574dc Merge branch 'obsd-master' 2019-05-03 21:02:26 +01:00
nicm
e8e4f4ec3e Insert after the right element on queue. 2019-05-03 18:59:58 +00:00
nicm
4097257bef Do not store the mouse position we calculate as the start of a drag back
into the mouse event that later code uses, it has been adjusted and they
should use the original position. GitHub issue 1710.
2019-05-03 18:42:40 +00:00
Thomas Adam
a14512e23e Merge branch 'obsd-master' 2019-05-03 19:02:27 +01:00
nicm
84e4652513 Use the right index for user-keys. 2019-05-03 18:00:19 +00:00
nicm
fc3d85e34b Fix mouse positioning when the pane is not entirely visible. 2019-05-03 16:51:29 +00:00
Nicholas Marriott
43656d4ea7 Sync up some tmux.1 bits. 2019-05-03 17:12:30 +01:00
Thomas Adam
fff85d854e Merge branch 'obsd-master' 2019-05-03 17:04:11 +01:00
nicm
cf6075fb29 Correct ordering when adding after an existing item. 2019-05-03 15:43:01 +00:00
nicm
33298d6df6 Instead of processing keys all together, put them up on the client
command queue so they are ordered correctly with the commands that they
execute.
2019-05-03 14:51:30 +00:00
nicm
4bb48998e0 Fix reverse attribute in status line, GitHub issue 1709. 2019-05-03 10:00:48 +00:00
nicm
5d9e591ae8 Fix up some bits about window-size that seem to have got lost. 2019-05-02 20:12:40 +00:00
Thomas Adam
4d16df9312 Merge branch 'obsd-master' 2019-05-01 09:02:27 +01:00
Nicholas Marriott
18e554aa61 Merge tag '2.9a'
2.9a
2019-05-01 07:29:23 +01:00
Nicholas Marriott
4cb13d95ba Add to CHANGES. 2019-05-01 07:16:20 +01:00
Nicholas Marriott
e36d6ee06a Version 2.9a. 2019-05-01 07:12:14 +01:00
nicm
901eed7b71 Do not loop forever if there is a nonprintable character in the format. 2019-05-01 07:12:02 +01:00
nicm
750d5830c2 Don't redraw control clients, from George Nachman. 2019-05-01 07:08:04 +01:00
nicm
e286178aa7 Unbreak main-vertical and main-horizontal layouts. 2019-05-01 07:07:52 +01:00
nicm
c176361788 Remove unused variable from Thomas Adam. 2019-05-01 06:07:14 +00:00
Thomas Adam
dc7e53897a Merge branch 'obsd-master' 2019-04-30 21:02:26 +01:00
nicm
429c4bc51b Fix user options after show-hooks merge, GitHub issue 1704. 2019-04-30 18:02:03 +00:00
Nicholas Marriott
1156d91cf8 Simple -C sanity test. 2019-04-30 18:39:07 +01:00
Thomas Adam
4c5b0fbbcc Merge branch 'obsd-master' 2019-04-30 09:02:29 +01:00
nicm
5a288b1efe Don't redraw control clients, from George Nachman. 2019-04-30 06:21:30 +00:00
nicm
82c789ee58 Fix memory leak in window tree search, from Amos Bird. 2019-04-30 06:19:51 +00:00
Nicholas Marriott
7e0f9ab3eb Don't think I will do this. 2019-04-29 21:48:15 +01:00
Nicholas Marriott
87bd8965c6 Add to CHANGES & remove from TODO. 2019-04-29 20:18:07 +01:00
Thomas Adam
2aa517c805 Merge branch 'obsd-master' 2019-04-29 09:02:25 +01:00
nicm
ec81bd2399 Add support for keys to jump between matching brackets - C-M-f and C-M-b
in emacs, % in vi. Suggested by and help from Chris Barber in GitHub
issue 1666.
2019-04-29 06:55:21 +00:00
Thomas Adam
3ab229da70 Merge branch 'obsd-master' 2019-04-28 23:02:30 +01:00
Nicholas Marriott
2cecabd75e Fix gseq use in RGB colour script. 2019-04-28 22:16:34 +01:00
nicm
c4b0da5513 Support multiple occurances of the same argument. Use this for a new
flag -e to new-window, split-window, respawn-window, respawn-pane to
pass environment variables into the newly created process. From Steffen
Christgau in GitHub issue 1697.
2019-04-28 20:05:50 +00:00
Thomas Adam
5489796737 Merge branch 'obsd-master' 2019-04-27 20:09:07 +01:00
Thomas Adam
85f09f9a4c Merge branch 'obsd-master' 2019-04-26 13:02:37 +01:00
Nicholas Marriott
293fd0d258 Update CHANGES and TODO. 2019-04-26 12:44:25 +01:00
nicm
dfb7bb6830 Merge hooks into options and make each one an array option. This allows
multiple commands to be easily bound to one hook. set-hook and
show-hooks remain but they are now variants of set-option and
show-options. show-options now has a -H flag to show hooks (by default
they are not shown).
2019-04-26 11:38:51 +00:00
nicm
f1e14f86c4 Destroy panes before options to avoid crash when forced into a mode by a
hook.
2019-04-26 10:24:26 +00:00
nicm
6644d209d2 Unbreak main-vertical and main-horizontal layouts. 2019-04-26 10:15:40 +00:00
Thomas Adam
7c4a2253e8 Merge branch 'obsd-master' 2019-04-25 21:02:43 +01:00
nicm
2d65bbd941 options_array_item_value cannot return NULL. 2019-04-25 19:36:59 +00:00
nicm
a609e6361a Need a fallback for -2 for aixterm colours. 2019-04-25 19:03:43 +00:00
nicm
32a81e197b Make options_tostring allocate its result instead of using a stack
buffer (needed for something in the future).
2019-04-25 18:18:55 +00:00
Thomas Adam
f2c0605d6d Merge branch 'obsd-master' 2019-04-25 17:02:37 +01:00
nicm
1677bb0dea Need to escape ]. 2019-04-25 15:35:07 +00:00
Nicholas Marriott
dddc544b8f Update CHANGES. 2019-04-25 13:00:32 +01:00
Thomas Adam
643eecde86 Merge branch 'obsd-master' 2019-04-25 09:02:36 +01:00
nicm
567d3e27ab Automatically scroll if dragging to create a selection with the mouse
and the cursor reaches the top or bottom line.
2019-04-25 06:34:57 +00:00
Nicholas Marriott
a2e08b587a Merge branch '2.9-rc' 2019-04-25 07:29:02 +01:00
Nicholas Marriott
cb75ec25c8 2.9 now. 2019-04-24 22:35:23 +01:00
nicm
7d06216289 Do not loop forever if there is a nonprintable character in the format. 2019-04-24 22:34:56 +01:00
Thomas Adam
4ab208ecc8 Merge branch 'obsd-master' 2019-04-24 22:09:57 +01:00
nicm
6aa0bedad2 Use bg not fg when adjusting for aixterm, from Ailin Nemui. 2019-04-24 20:32:31 +00:00
nicm
c6e39976c6 Do not loop forever if there is a nonprintable character in the format. 2019-04-24 20:27:52 +00:00
Thomas Adam
c869366133 Merge branch 'obsd-master' 2019-04-23 23:02:42 +01:00
nicm
b9022e33ea Somehow missed these bits in last commit. 2019-04-23 20:40:03 +00:00
nicm
772b3b7a06 Indicate an array option with a flag rather than a special type so that
in future will not have to be strings.
2019-04-23 20:36:55 +00:00
Thomas Adam
b0d7623b7e Merge branch 'obsd-master' 2019-04-23 13:02:37 +01:00
Thomas Adam
4a96f599f6 Merge branch 'obsd-master' 2019-04-23 11:02:36 +01:00
nicm
564e44adc6 Add -no-clear variants of copy-selection and copy-pipe which do not
clear the selection after copying. Make copy-pipe clear the selection by
default to be consistent with copy-selection. From Avi Halachmi.
2019-04-23 09:39:07 +00:00
nicm
6752f41c2a Do not try to resize if the parent cell is NULL, problem reported by
Sunil Nimmagadda.
2019-04-23 09:15:24 +00:00
Nicholas Marriott
51c09bf2b4 Merge branch '2.9-rc' 2019-04-18 22:14:55 +01:00
Nicholas Marriott
d24a44230a Update CHANGES for 2.9. 2019-04-18 22:12:15 +01:00
Nicholas Marriott
8d752f5aaa Update CHANGES. 2019-04-18 22:11:46 +01:00
Nicholas Marriott
e7827f8bc2 Remove duplicate entry. 2019-04-18 14:16:19 +01:00
Thomas Adam
f980e868dd Merge branch 'obsd-master' 2019-04-18 14:11:22 +01:00
Thomas Adam
3c1f0cfc34 Merge branch 'obsd-master' 2019-04-18 14:08:13 +01:00
nicm
5b9211d827 Copy the code to infer the option type to show-options and document it. 2019-04-18 12:22:07 +00:00
nicm
3f189945d8 Pass target client and session to load_cfg from source-file so formats
work. Reported by Thomas Sattler.
2019-04-18 11:07:28 +00:00
nicm
f3ab05e7cd Update session activity on focus event, from tafryn at gmail dot com. 2019-04-18 10:11:52 +00:00
jmc
2219f7cc73 mark up punctuation-as-macro-args properly; 2019-04-17 16:34:35 +00:00
nicm
1fd3b9ec1c Fix minimum size check on split and size of first cell on spread out
with a pane status line.
2019-04-17 14:44:33 +00:00
nicm
da31eddadc Rewrite main-vertical and horizontal to use the common spread out code
and to handle the case where the panes won't fit into the existing
window size.
2019-04-17 14:44:14 +00:00
nicm
c660e46149 Set the window size as well as the layout size when using the preset
layouts.
2019-04-17 14:43:49 +00:00
nicm
e3b1358bbc Do not let the size of the pane status screen go negative. 2019-04-17 14:41:08 +00:00
nicm
5943cd1907 Document that switch-client can change all of session,window,pane and
check for % in the target as well as ":.".
2019-04-17 14:39:37 +00:00
nicm
78287e27c8 Break new window and pane creation common code from various commands and
window.c into a separate file spawn.c.
2019-04-17 14:37:48 +00:00
Nicholas Marriott
82bc2c87a9 Add to TODO. 2019-04-17 09:10:23 +01:00
nicm
cd4c94f76b Current window style also needs to be tested for default. 2019-04-11 09:34:22 +01:00
Nicholas Marriott
bba1809eac Merge a number of fixes from master for layouts, mostly prompted by testing by
Thomas Sattler.
2019-04-11 09:26:34 +01:00
Nicholas Marriott
e6ee3e9504 Warning fixes from Carlo Marcelo Arenas Belón. 2019-04-10 19:27:09 +01:00
Nicholas Marriott
1c1ec84aa3 Fix minimum size check on split and size of first cell on spread out with a
pane status line.
2019-04-10 14:54:02 +01:00
Nicholas Marriott
f3fcf977e4 Use the right winlink pointer in new-window. 2019-04-10 11:40:59 +01:00
Nicholas Marriott
4a3ac3bd26 Remove unused variable. 2019-04-10 07:27:21 +01:00
Nicholas Marriott
3c5d3a3780 Add PATH_DEFPATH to compat.h from Carlo Marcelo Arenas Belón. 2019-04-09 21:31:50 +01:00
Nicholas Marriott
fe44f90e5b Do not let the size of the pane status screen go negative. 2019-04-09 21:30:03 +01:00
Nicholas Marriott
031e9bc854 Rewrite main-vertical and horizontal to use the common spread out code and to
handle the case where the panes won't fit into the existing window size.
2019-04-09 21:15:00 +01:00
Nicholas Marriott
0cbccc90ab Set the window size as well as the layout size when using the preset layouts
and calculate the sizes correctly.
2019-04-09 20:38:43 +01:00
Nicholas Marriott
71d90c11dd Solaris has no paths.h. 2019-04-09 07:52:54 +01:00
Thomas Adam
2546572e8e Merge branch 'obsd-master' 2019-04-08 21:02:37 +01:00
nicm
835ccbac46 select-word was missing from the command list, from pawel-slowik. 2019-04-08 17:55:51 +00:00
Nicholas Marriott
b5b67c5386 Document that switch-client can change all of session,window,pane and check for
% in the target as well as ":.".
2019-04-08 10:38:50 +01:00
Thomas Adam
fbe488e4de Merge branch 'obsd-master' 2019-04-07 23:02:37 +01:00
nicm
bb629f3be7 Current window style also needs to be tested for default. 2019-04-07 20:18:20 +00:00
Thomas Adam
883a428e27 Linux: remove include for util.h
Linux doesn't require this header.
2019-04-07 15:39:58 +01:00
Nicholas Marriott
e44e2c48dd Do not log NULL command. 2019-04-07 13:16:55 +01:00
Nicholas Marriott
ece737274e Forgot to add the file. 2019-04-07 13:11:55 +01:00
Nicholas Marriott
5ece386cdf Break new window and pane creation common code from various commands and
window.c into a separate file spawn.c.
2019-04-07 13:01:03 +01:00
Nicholas Marriott
7653328ce7 Remove from TODO one thing that I don't think is necessary and one that is
done.
2019-04-07 12:18:40 +01:00
Nicholas Marriott
fc111d2b12 Fix a duplicate entry in CHANGES and remove an item from TODO. 2019-04-07 12:07:26 +01:00
Thomas Adam
04402db616 Merge branch 'obsd-master' 2019-04-05 23:02:36 +01:00
nicm
1b5a8a0f09 Fix some warnings, from Thomas Adam. 2019-04-05 20:32:31 +00:00
Nicholas Marriott
e33b623f21 Merge branch '2.9-rc' 2019-04-04 18:31:54 +01:00
nicm
73b54a0e5f Fix size check for splitw -f and top level pane size for tiled layout,
problems reported by Thomas Sattler.
2019-04-04 18:31:35 +01:00
Thomas Adam
5a97af7961 Merge branch 'obsd-master' 2019-04-04 13:02:37 +01:00
nicm
f4aefb738e Fix size check for splitw -f and top level pane size for tiled layout,
problems reported by Thomas Sattler.
2019-04-04 10:25:35 +00:00
nicm
481c3f3f2e screen_write_fast_copy can no longer assume the target screen is default
(it isn't for the pane status lines).
2019-04-03 09:31:32 +01:00
Thomas Adam
cb039b986e Merge branch 'obsd-master' 2019-04-03 09:02:41 +01:00
nicm
f6c54f3f03 Do not load /etc/tmux.conf if given -f. 2019-04-03 06:43:19 +00:00
nicm
06d58b3b7b screen_write_fast_copy can no longer assume the target screen is default
(it isn't for the pane status lines).
2019-04-03 06:43:04 +00:00
nicm
8968acd678 Silence flag should use the same option as activity, reported by Thomas
Sattler.
2019-04-02 22:20:36 +01:00
Thomas Adam
c9ef144dca Merge branch 'obsd-master' 2019-04-02 21:02:37 +01:00
nicm
09f71ed1b2 Silence flag should use the same option as activity, reported by Thomas
Sattler.
2019-04-02 18:41:24 +00:00
Nicholas Marriott
f0ddc301b7 Add CHANGES. 2019-04-02 17:02:09 +01:00
Nicholas Marriott
916c4c499d Version RC2. 2019-04-02 11:12:24 +01:00
Nicholas Marriott
fac792dc27 Update regress from master. 2019-04-02 11:11:19 +01:00
nicm
bbcfee362f Store and restore cursor across reflow by working out a position based
on unwrapped lines, rather than a grid offset. Fixes problems reported
by Thomas Sattler and Paul de Weerd.
2019-04-02 11:11:12 +01:00
Thomas Adam
bfc1f0ca62 Merge branch 'obsd-master' 2019-04-02 11:02:44 +01:00
nicm
7bcc0d16f2 Add an argument to copy commands to set the prefix for the buffer name,
allows buffers for different sessions to be named separately.
2019-04-02 09:03:39 +00:00
Nicholas Marriott
f03776c262 Don't use a config file in tests. 2019-04-02 09:53:02 +01:00
nicm
ffa4d48967 Store and restore cursor across reflow by working out a position based
on unwrapped lines, rather than a grid offset. Fixes problems reported
by Thomas Sattler and Paul de Weerd.
2019-04-02 08:45:32 +00:00
Nicholas Marriott
79c3fd4f39 Add cursor regression tests. 2019-04-02 09:44:28 +01:00
nicm
6d071c468c Restore a check to stop scrolled lines becoming larger than total lines,
fixes a crash reported by Thomas Sattler.
2019-04-02 07:33:33 +01:00
Thomas Adam
294accea1b Merge branch 'obsd-master' 2019-04-01 21:02:37 +01:00
nicm
792fcb1dbf Restore a check to stop scrolled lines becoming larger than total lines,
fixes a crash reported by Thomas Sattler.
2019-04-01 19:33:38 +00:00
Nicholas Marriott
da359269cb Merge branch '2.9-rc' 2019-03-29 11:20:15 +00:00
nicm
92da105b58 Free old strings after they have been expanded in format_choose. 2019-03-29 11:19:55 +00:00
Thomas Adam
ecc5cea09b Merge branch 'obsd-master' 2019-03-29 10:02:36 +00:00
nicm
d68a17a1df Free old strings after they have been expanded in format_choose. 2019-03-29 09:33:24 +00:00
Nicholas Marriott
52cb7a6382 Merge branch '2.9-rc' 2019-03-29 07:05:50 +00:00
nicm
00fda57ddf Fix offset of list ranges. 2019-03-29 07:05:40 +00:00
Thomas Adam
405bb8435c Merge branch 'obsd-master' 2019-03-29 00:02:36 +00:00
nicm
c6c4960b35 Fix offset of list ranges. 2019-03-28 22:18:46 +00:00
Thomas Adam
2c4f2393ec Merge branch 'obsd-master' 2019-03-28 22:02:37 +00:00
nicm
08bc226527 Expand session and window formats for buffer filters. 2019-03-28 21:05:15 +00:00
Thomas Adam
6b38334b28 Merge branch 'obsd-master' 2019-03-27 14:02:36 +00:00
nicm
c1f0918f8a Fix stop-selection, from Avi Halachmi. 2019-03-27 13:25:11 +00:00
Thomas Adam
6861045d38 Merge branch 'obsd-master' 2019-03-26 22:02:36 +00:00
nicm
9f8d193b11 Break copy mode commands into individual functions instead of a big load
of if statements.
2019-03-26 21:01:19 +00:00
Nicholas Marriott
a13e57f701 Update TODO. 2019-03-26 17:04:47 +00:00
Nicholas Marriott
e722ba38e3 There is no examples directory anymore. 2019-03-26 15:10:05 +00:00
Nicholas Marriott
b1dc2b5353 Merge branch '2.9-rc' 2019-03-26 15:05:41 +00:00
Nicholas Marriott
e0e08fcd2d Update CHANGES & TODO. 2019-03-26 15:05:28 +00:00
Nicholas Marriott
0a913b09cf For 3.0. 2019-03-26 14:38:20 +00:00
Nicholas Marriott
4f7a5d1e40 2.9 bits. 2019-03-26 14:37:27 +00:00
Thomas Adam
6ac84585e6 Merge branch 'obsd-master' 2019-03-25 20:02:38 +00:00
nicm
d21f8ecc13 Add StatusDefault binding for the mouse on any otherwise unassigned
parts of the status line, from Avi Halachmi.
2019-03-25 18:59:55 +00:00
Thomas Adam
5e2150cf18 Merge branch 'obsd-master' 2019-03-25 16:00:36 +00:00
Thomas Adam
a07ad6b5a3 Merge branch 'obsd-master' 2019-03-25 15:57:47 +00:00
nicm
ff4d7d541f Fix columns of cursor_character format in list. 2019-03-25 14:29:36 +00:00
Nicholas Marriott
e8f4ca6a52 Tweaks to example config. 2019-03-25 12:05:58 +00:00
Nicholas Marriott
a084f2dcb7 Add to TODO. 2019-03-25 10:06:03 +00:00
nicm
517d673dbe Ignore mouse on status line which are not part of a range, GitHub issue 1649. 2019-03-25 09:22:09 +00:00
nicm
b4a301f8fe Clarify that styles can be space or comma separated, from Stephen Zapatka. 2019-03-22 10:45:17 +00:00
nicm
04a1fc9d36 I forgot to document resize-window, window-size and default-size;
reminded by okan@.
2019-03-22 09:33:04 +00:00
Thomas Adam
0292243b29 Merge branch 'obsd-master' 2019-03-20 20:02:37 +00:00
Nicholas Marriott
ef38a420b2 Update TODO. 2019-03-20 20:02:13 +00:00
Nicholas Marriott
7536d57b16 Update TODO. 2019-03-20 19:26:20 +00:00
nicm
9ee1a8f701 Improve cursor positioning after reflow by storing the position as an
offset into the entire history before reflow and restoring it aftewards.
2019-03-20 19:19:11 +00:00
Nicholas Marriott
0e0f2f765b Update CHANGES. 2019-03-20 14:01:46 +00:00
Thomas Adam
bff957a475 Merge branch 'obsd-master' 2019-03-20 08:02:38 +00:00
nicm
ed962e7612 Include function name in logging. 2019-03-20 07:30:05 +00:00
nicm
458b87150b Do not leak ranges on error. 2019-03-20 07:28:31 +00:00
nicm
ae46a19b8e Ignore invalid styles rather than throwing away the whole format, this
matches what we used to do.
2019-03-20 07:24:03 +00:00
nicm
3b959c05ff Bit more logging to show drawing errors. 2019-03-20 07:13:02 +00:00
Thomas Adam
46f642b030 Merge branch 'obsd-master' 2019-03-19 22:02:36 +00:00
nicm
8b74e959ef Include window-status-style and window-status-current style in the format. 2019-03-19 21:09:51 +00:00
Thomas Adam
320237fdb8 Merge branch 'obsd-master' 2019-03-19 20:02:37 +00:00
nicm
161b57869e Add a cursor_character format. 2019-03-19 19:01:50 +00:00
Nicholas Marriott
92732a2540 Add to TODO. 2019-03-19 14:39:55 +00:00
Thomas Adam
b3eebdec48 Merge branch 'obsd-master' 2019-03-19 14:02:36 +00:00
nicm
b24c9e34a9 Rename the first KEY BINDINGS section to DEFAULT KEY BINDINGS. 2019-03-19 13:35:42 +00:00
Thomas Adam
073d439965 Merge branch 'obsd-master' 2019-03-19 00:02:39 +00:00
Thomas Adam
f956c17c09 Merge branch 'obsd-master' 2019-03-18 22:02:36 +00:00
nicm
0406ec0ec2 Free temporary screens when writing format. 2019-03-18 21:55:04 +00:00
nicm
f34ebfed76 The individual -fg, -bg and -attr options have been deprecated (in
favour of -style), undocumented and hidden from show-options since
2014. Remove them, except for status-fg and status-bg.
2019-03-18 21:46:01 +00:00
Thomas Adam
962f255ee8 Merge branch 'obsd-master' 2019-03-18 21:24:49 +00:00
nicm
c62404673e Add some bits to the STATUS LINE section about the new option. 2019-03-18 21:01:04 +00:00
nicm
979313832c Extend the #[] style syntax and use that together with previous format
changes to allow the status line to be entirely configured with a single
option.

Now that it is possible to configure their content, enable the existing
code that lets the status line be multiple lines in height. The status
option can now take a value of 2, 3, 4 or 5 (as well as the previous on
or off) to configure more than one line. The new status-format array
option configures the format of each line, the default just references
the existing status-* options, although some of the more obscure status
options may be eliminated in time.

Additions to the #[] syntax are: "align" to specify alignment (left,
centre, right), "list" for the window list and "range" to configure
ranges of text for the mouse bindings.

The "align" keyword can also be used to specify alignment of entries in
tree mode and the pane status lines.
2019-03-18 20:53:33 +00:00
Thomas Adam
1d6fe43c7b Merge branch 'obsd-master' 2019-03-18 18:02:38 +00:00
Thomas Adam
4cbf596dc5 Merge branch 'obsd-master' 2019-03-18 15:30:55 +00:00
nicm
d738d51688 Mode init needs to be fired with the mode on the list or it will not be
resized correctly.
2019-03-18 15:25:36 +00:00
Thomas Adam
acb2413852 Merge branch 'obsd-master' 2019-03-18 15:07:51 +00:00
nicm
2628af573d Add format variables for the default formats for the various modes
(tree_mode_format and so on) and add a -a flag to display-message to
list variables with values.
2019-03-18 14:10:25 +00:00
Nicholas Marriott
aa2b3472c5 Update TODO. 2019-03-18 12:00:10 +00:00
nicm
ce6be7afd4 Make array options a sparse tree instead of an array of char * and
remove the size limit.
2019-03-18 11:58:40 +00:00
nicm
d2d43987d0 With force, kill previous job before starting new. Fixes problem
reported by Scott Mcdermott in GitHub issue 1627.
2019-03-18 09:46:42 +00:00
nicm
bd3332b211 Break description of styles into its own section. 2019-03-17 19:33:12 +00:00
Nicholas Marriott
3a298454ce Add to TODO. 2019-03-17 08:05:58 +00:00
nicm
b588b1729a Use a pointer for the active screen in the status line instead of
copying them around all the time.
2019-03-16 19:12:13 +00:00
nicm
818fda0363 Give status_save_old the client so it can do the reinit too. 2019-03-16 17:53:55 +00:00
nicm
b4f5b99e4b Tidy and rename some bits of status line code. 2019-03-16 17:14:07 +00:00
nicm
e8b33af780 Add a way to set individual defaults for an array option. 2019-03-15 21:54:47 +00:00
nicm
1d306e926a Add a : to make error messages clearer. 2019-03-15 15:20:00 +00:00
nicm
33595a255f Copy recursion counter into new formats when looping. 2019-03-15 15:02:25 +00:00
nicm
85044a634b Move status line free into its own function. 2019-03-15 14:46:58 +00:00
nicm
2d71bef0ca Remove unused member of struct client. 2019-03-15 10:48:05 +00:00
nicm
f6d34f066c Only print format logging when the flag is set, even if also sending to log_debug. 2019-03-15 10:22:57 +00:00
nicm
672c49d512 The pane and window loops need to pass the window and pane tags when
they build their format.
2019-03-15 10:07:24 +00:00
nicm
27578815da Add a -v flag to display-message to show verbose messages as the format
is parsed, this gives the user a way to debug problems with formats
rather than just being confronted with (for example) a blank status
line.
2019-03-15 10:04:13 +00:00
nicm
25e2e22791 Add a limit on how far format_expand can recurse. 2019-03-14 23:34:41 +00:00
nicm
10d60faba5 Store the time in the format tree rather than passing it around. 2019-03-14 23:14:27 +00:00
Thomas Adam
2c755e3c55 Merge branch 'obsd-master' 2019-03-14 22:02:39 +00:00
nicm
bace79a571 Remove some unnecessary temporary variables and be much less strict
about spacing in style_parse.
2019-03-14 21:46:08 +00:00
nicm
4206bcc10e Add format flags for start and end window. 2019-03-14 21:41:30 +00:00
nicm
38064e7593 Add T format modifier like E but also do strftime(3). 2019-03-14 21:31:43 +00:00
nicm
1416ceb575 Accept 0 time as a shorthand for now to format_expand_time. 2019-03-14 21:27:26 +00:00
Thomas Adam
d58bccfc63 Merge branch 'obsd-master' 2019-03-14 20:02:38 +00:00
nicm
9bd4b96766 Fix ED1 (clear end of screen), reported by Marc Reisner. 2019-03-14 17:58:52 +00:00
Thomas Adam
0b32fa81b6 Merge branch 'obsd-master' 2019-03-14 12:02:41 +00:00
nicm
0425e3178d A little tidying in style_parse. 2019-03-14 10:19:52 +00:00
nicm
13f9a061ac Add a wrapper (struct style) around styles rather than using the
grid_cell directly. There will be some non-cell members soon.
2019-03-14 09:53:52 +00:00
Thomas Adam
f33d2ab29e Merge branch 'obsd-master' 2019-03-14 08:02:37 +00:00
nicm
1e9f8a3523 Missing space in capture-pane usage, from Ben Boeckel.
Also man page fixed from jmc.
2019-03-14 06:36:21 +00:00
nicm
2fbd491ff0 Add actual HPA (\033[`), the existing one is CHA. From Marc Reisner. 2019-03-14 06:33:43 +00:00
Thomas Adam
81b393a493 Merge branch 'obsd-master' 2019-03-14 00:02:37 +00:00
nicm
5755bfc619 Need to set attributes before clearing. 2019-03-13 22:01:22 +00:00
nicm
10f0094be9 The pane's style should be initialized to default before parsing the
argument.
2019-03-13 21:39:21 +00:00
Thomas Adam
786f5e505e Merge branch 'obsd-master' 2019-03-13 20:02:36 +00:00
nicm
6dffbc4849 Tweak format_replace logging. 2019-03-13 18:09:12 +00:00
Thomas Adam
e6fd429d58 Merge branch 'obsd-master' 2019-03-13 16:02:41 +00:00
nicm
95ab1aaaec Add formats to list sessions, windows or panes. 2019-03-13 15:37:28 +00:00
Nicholas Marriott
f628afc850 Update TODO. 2019-03-13 14:51:19 +00:00
nicm
49f04a997a Apply length limits and substitution even to literal formats. 2019-03-13 14:27:17 +00:00
Nicholas Marriott
1aeac384f3 Add to TODO. 2019-03-13 14:20:58 +00:00
nicm
9032ac2a05 Add E: format to expand a format twice (useful to expand the value of an
option).
2019-03-13 14:19:54 +00:00
nicm
71e00c718c Make format parsing build the modifiers into a list, standardize how
arguments are given and allow multiple modifiers on a format (separated
by ;).
2019-03-13 14:10:34 +00:00
Nicholas Marriott
7a6b21de65 Add to TODO. 2019-03-13 09:30:42 +00:00
Nicholas Marriott
4f5cb88c2b Add to TODO. 2019-03-13 09:30:42 +00:00
Thomas Adam
0e6eda02a6 Merge branch 'obsd-master' 2019-03-13 08:02:35 +00:00
nicm
feaa5660a3 Do not use origin for VPA. 2019-03-13 07:34:36 +00:00
Thomas Adam
b03f58b977 Merge branch 'obsd-master' 2019-03-13 00:02:38 +00:00
nicm
b2bc34af12 Set a flag on cells are genuinely empty (cleared and never written to)
and use tty_clear_line (which will choose the best escape sequence) to
clear any batches of cells with that flag when redrawing a line from the
stored screen.
2019-03-12 23:21:45 +00:00
Thomas Adam
400529eea0 Merge branch 'obsd-master' 2019-03-12 22:02:42 +00:00
nicm
938156d73b DECRC and DECSC apparently need to preserve origin mode as well, based
on a fix from Marc Reisner.
2019-03-12 20:02:47 +00:00
Thomas Adam
ba4a884d75 Merge branch 'obsd-master' 2019-03-12 20:02:38 +00:00
nicm
2796ae81d0 Fix HPA in origin mode. 2019-03-12 18:30:08 +00:00
nicm
f3f534a3a0 Tidy up a lot of &ictx->ctx by using a local variable. 2019-03-12 18:26:57 +00:00
Nicholas Marriott
6c3ee42568 Add a couple of things. 2019-03-12 17:59:46 +00:00
Nicholas Marriott
2f0ffe6adb Add to TODO. 2019-03-12 17:52:22 +00:00
Nicholas Marriott
4002dbf0c1 Fix session size regress. 2019-03-12 17:36:58 +00:00
Thomas Adam
162d3cb1f4 Merge branch 'obsd-master' 2019-03-12 16:02:37 +00:00
Thomas Adam
7d2004a8dd Merge branch 'obsd-master' 2019-03-12 14:02:40 +00:00
Nicholas Marriott
860acecc0d Fix up regress test for control client size. 2019-03-12 13:57:06 +00:00
nicm
028f9d1d87 Fix resizing of control clients, should be ignored until SIZECHANGED flag set. 2019-03-12 13:56:30 +00:00
nicm
303d20a758 Fix wrapping after origin mode change. 2019-03-12 13:14:14 +00:00
nicm
3f0efc050a When asked for a window index, return it even if the window exists. 2019-03-12 13:14:04 +00:00
nicm
7804fa1b82 Revert to not clearing history on RIS, apparently some bootloaders send
this and it doesn't really do any harm.
2019-03-12 12:58:40 +00:00
nicm
7b819357ff Tweak target debug logging. 2019-03-12 12:49:46 +00:00
Nicholas Marriott
595b52490e Add to TODO. 2019-03-12 12:12:35 +00:00
Thomas Adam
3ec05e9405 Merge branch 'obsd-master' 2019-03-12 12:02:42 +00:00
Nicholas Marriott
f8a30e1588 Update CHANGES. 2019-03-12 11:20:21 +00:00
nicm
3f6bfbaf2b Allow multiple modes to be open in a pane. A stack of open modes is kept
and the previous restored when the top is exited. If a mode that is
already on the stack is entered, the existing instance is moved to the
top as the active mode rather than being opened new.
2019-03-12 11:16:49 +00:00
Thomas Adam
95d340cc4f Merge branch 'obsd-master' 2019-03-12 10:02:39 +00:00
nicm
ff4c80d53d Add support for origin mode (DECOM, SM/RM ?6), from Marc Reisner. 2019-03-12 07:39:27 +00:00
Thomas Adam
bc72cf2f52 Merge branch 'obsd-master' 2019-03-08 12:02:39 +00:00
nicm
de730f68a4 Make the mode used to view command output (a variant of copy mode) use
its own mode definition struct with a different init function rather
than calling special setup functions.
2019-03-08 10:34:20 +00:00
nicm
9cc04a0f9a Do not use window mode entry after free. 2019-03-08 10:29:25 +00:00
Thomas Adam
349aeb806a Merge branch 'obsd-master' 2019-03-07 22:02:42 +00:00
nicm
f98c66ece8 Add a separate mode struct for the active window mode if any. 2019-03-07 20:24:21 +00:00
Thomas Adam
a1009e7bd3 Merge branch 'obsd-master' 2019-03-07 20:02:41 +00:00
nicm
3c24bc5617 Tidy changing the mode into window_copy_init_for_output. 2019-03-07 19:34:22 +00:00
nicm
7f093fcddc Make adding mode formats a function pointer as well. 2019-03-07 19:01:21 +00:00
Nicholas Marriott
5a564a0c1a Add to TODO. 2019-03-07 15:34:24 +00:00
Thomas Adam
9ebd630675 Merge branch 'obsd-master' 2019-03-04 12:01:28 +00:00
nicm
5cdd578906 Fix sense of aggressive-resize flag. 2019-03-04 09:29:52 +00:00
nicm
a870c255c4 Don't set client offset if client is not a terminal 2019-03-04 09:29:40 +00:00
Thomas Adam
d5c837904b Merge branch 'obsd-master' 2019-02-16 20:02:36 +00:00
nicm
fa33603dc1 Do not look at next key byte if the length is 0, originally from Shingo
NISHIOKA in GitHub issue 1601.
2019-02-16 19:04:34 +00:00
Thomas Adam
fa8294436c Merge branch 'obsd-master' 2019-02-16 14:02:37 +00:00
nicm
82f0c859a2 Use starting client cwd in config file, GitHub issue 1606. 2019-02-16 11:42:08 +00:00
Thomas Adam
9768091ee4 Merge branch 'obsd-master' 2019-02-09 20:02:36 +00:00
nicm
f9c396db41 Completion of command-alias members. 2019-02-09 18:18:36 +00:00
Nicholas Marriott
bdb7e48cba Redirect which stderr. 2019-02-06 14:45:35 +00:00
Thomas Adam
c42e89a598 Merge branch 'obsd-master' 2019-02-06 08:02:37 +00:00
nicm
afd3127d89 Add -b to display-panes like run-shell, GitHub issue 1559. 2019-02-06 07:36:06 +00:00
Thomas Adam
4ab3b18b36 Merge branch 'obsd-master' 2019-01-20 18:02:36 +00:00
nicm
2ea22fce5e Should use DECFRA if not default, not if default. From Karl Beldan. 2019-01-20 15:57:27 +00:00
Thomas Adam
cd8a7fb07b Merge branch 'obsd-master' 2019-01-15 14:02:37 +00:00
nicm
cd39920abd Should save the bg colour when setting it to default, not the fg. 2019-01-15 12:08:53 +00:00
Thomas Adam
469a9e9439 Merge branch 'obsd-master' 2019-01-15 12:02:36 +00:00
nicm
34c0807be6 Do not highlight characters which will not be copied, reported by
Jaroslaw Rzeszotko.
2019-01-15 09:56:31 +00:00
Thomas Adam
c9d482ab48 Merge branch 'obsd-master' 2018-12-18 14:02:40 +00:00
nicm
bde0224deb Pass window into mode functions. 2018-12-18 13:20:44 +00:00
Thomas Adam
b6cdac05c7 Merge branch 'obsd-master' 2018-12-18 00:02:37 +00:00
nicm
4e3d661284 Fix parsing of empty colon-separated fields, reported by Siarhei Siniak. 2018-12-17 21:52:59 +00:00
Thomas Adam
1c5093c1c4 Merge branch 'obsd-master' 2018-11-30 10:02:37 +00:00
nicm
67254ed8df Clear PANE_EXITED flag when starting new child process in case the pane
has been respawned.
2018-11-30 08:44:40 +00:00
Nicholas Marriott
6cf2f74fe9 osdep_get_cwd for NetBSD, from Leonardo Taccari. 2018-11-29 10:37:27 +00:00
Thomas Adam
1ed994a6c8 Merge branch 'obsd-master' 2018-11-28 12:02:36 +00:00
nicm
40d246b29c Handle UTF-8 in word-separators option, GitHub issue 1551. 2018-11-28 11:20:13 +00:00
Thomas Adam
2977317243 Merge branch 'obsd-master' 2018-11-22 12:02:38 +00:00
nicm
3a7b9d5735 Do not use PWD unless it actually matches the real working directory. 2018-11-22 10:36:40 +00:00
Nicholas Marriott
2eca63b98e Add to TODO. 2018-11-21 09:50:53 +00:00
Nicholas Marriott
c4b04b1624 Fixes for GNU/kFreeBSD from James Clarke. 2018-11-21 08:50:22 +00:00
Thomas Adam
efd01f3bfd Merge branch 'obsd-master' 2018-11-19 14:02:41 +00:00
nicm
749f67b7d8 evbuffer_new and bufferevent_new can both fail (when malloc fails) and
return NULL. GitHub issue 1547.
2018-11-19 13:35:40 +00:00
Thomas Adam
a7da2357a5 Merge branch 'obsd-master' 2018-11-15 12:02:37 +00:00
kn
f103927a52 Add [template] to display-panes and choose-{buffer,client,tree} usage
OK nicm
2018-11-15 10:38:53 +00:00
Thomas Adam
0fd73f238d Merge branch 'obsd-master' 2018-11-13 12:02:38 +00:00
nicm
50cdfc06fb Initialize context property in alignment test handler function. 2018-11-13 11:36:37 +00:00
Thomas Adam
3c6cdf0115 Merge branch 'obsd-master' 2018-11-12 16:02:37 +00:00
nicm
86e648d906 Allow style #[] in mode formats. 2018-11-12 14:18:10 +00:00
Thomas Adam
849d06c0df Merge branch 'obsd-master' 2018-11-08 20:02:37 +00:00
nicm
09aee53763 It isn't possible to specify buffer name to copy mode commands now, so
remove the function argument.
2018-11-08 18:49:19 +00:00
Thomas Adam
4efba0bf9f Merge branch 'obsd-master' 2018-11-07 10:02:39 +00:00
nicm
0c7f64458f If a non-repeating key is used when repeating, it should be treated as
an entirely new key press, not checked in root table and ignored if not
found. GitHub issue 1513.
2018-11-07 08:06:28 +00:00
Nicholas Marriott
ff77010f70 Add to TODO. 2018-11-07 08:00:15 +00:00
nicm
7339845c01 There is no reason wait-for has to be restricted to outside tmux. 2018-11-07 07:58:16 +00:00
Thomas Adam
99072e1d81 Merge branch 'obsd-master' 2018-11-06 16:02:37 +00:00
nicm
f9881b3b5d Correctly unzoom and redraw panes in switch-client. 2018-11-06 15:13:13 +00:00
Thomas Adam
b1ad075d11 Merge branch 'obsd-master' 2018-10-31 12:02:38 +00:00
nicm
ef904cfef2 Reset all flags in screen_write_reset, reported by Benjamin Poirier. 2018-10-31 10:05:47 +00:00
Thomas Adam
ddffda4da5 Merge branch 'obsd-master' 2018-10-28 18:02:36 +00:00
nicm
d5b92ac37e Do not printf NULL. 2018-10-28 16:10:02 +00:00
Thomas Adam
0a54a07909 Merge branch 'obsd-master' 2018-10-28 16:02:37 +00:00
nicm
65dd7345e0 Do not check for a key again without an escape if only \033 is present. 2018-10-28 15:34:27 +00:00
Nicholas Marriott
0cefdff1b6 Add to CHANGES. 2018-10-26 11:36:36 +01:00
Thomas Adam
e771f10dc6 Merge branch 'obsd-master' 2018-10-25 17:02:42 +01:00
nicm
fc41bf46ac Add a "terminal" colour which can be used instead of "default" in style
options for the terminal default colour, bypassing any inheritance from
other options. Prompted by a discussion with abieber@.
2018-10-25 15:13:38 +00:00
Nicholas Marriott
2808f8261c Tweak wording. 2018-10-19 08:38:12 +01:00
Nicholas Marriott
c234032fcf Do not use master here. 2018-10-19 08:37:31 +01:00
Nicholas Marriott
bc6211cca5 Instead of "master" for the version number, use "next-X.X". It is more
useful to include the next version number.
2018-10-19 08:35:23 +01:00
Thomas Adam
164590e34c Merge branch 'obsd-master' 2018-10-18 15:02:38 +01:00
nicm
9feb35b7c4 Document new refresh-client flags. 2018-10-18 13:03:45 +00:00
Thomas Adam
f44d02c7f5 Merge branch 'obsd-master' 2018-10-18 11:09:54 +01:00
nicm
646995384d Support for windows larger than visible on the attached client. This has
been a limitation for a long time.

There are two new options, window-size and default-size, and a new
command, resize-window. The force-width and force-height options and the
session_width and session_height formats have been removed.

The new window-size option tells tmux how to work out the size of
windows: largest means it picks the size of the largest session,
smallest the smallest session (similar to the old behaviour) and manual
means that it does not automatically resize windows. The default is
currently largest but this may change. aggressive-resize modifies the
choice of session for largest and smallest as it did before.

If a window is in a session attached to a client that is too small, only
part of the window is shown. tmux attempts to keep the cursor visible,
so the part of the window displayed is changed as the cursor moves (with
a small delay, to try and avoid excess redrawing when applications
redraw status lines or similar that are not currently visible). The
offset of the visible portion of the window is shown in status-right.

Drawing windows which are larger than the client is not as efficient as
those which fit, particularly when the cursor moves, so it is
recommended to avoid using this on slow machines or networks (set
window-size to smallest or manual).

The resize-window command can be used to resize a window manually. If it
is used, the window-size option is automatically set to manual for the
window (undo this with "setw -u window-size"). resize-window works in a
similar way to resize-pane (-U -D -L -R -x -y flags) but also has -a and
-A flags. -a sets the window to the size of the smallest client (what it
would be if window-size was smallest) and -A the largest.

For the same behaviour as force-width or force-height, use resize-window
-x or -y, and "setw -u window-size" to revert to automatic sizing..

If the global window-size option is set to manual, the default-size
option is used for new windows. If -x or -y is used with new-session,
that sets the default-size option for the new session.

The maximum size of a window is 10000x10000. But expect applications to
complain and much higher memory use if making a window excessively
big. The minimum size is the size required for the current layout
including borders.

The refresh-client command can be used to pan around a window, -U -D -L
-R moves up, down, left or right and -c returns to automatic cursor
tracking. The position is reset when the current window is changed.
2018-10-18 08:38:01 +00:00
Nicholas Marriott
2dfdb55ace Handle pan correctly when the terminal is bigger than the window. 2018-10-18 09:24:15 +01:00
nicm
a51668ca06 Support OSC 52 ? to read the top buffer inside tmux (when set-clipboard
is changed to on), also add refresh-client -l to ask tmux to use the
same mechanism to get the clipboard from the terminal outside
tmux. GitHub issue 1477.
2018-10-18 08:04:14 +00:00
nicm
bc0e527f32 Support for extended underline styles on terminals which offer them,
enabled by adding the Smulx capability with terminal-overrides (add
something like ',vte*:Smulx=\E[4\:%p1%dm'). GitHub issue 1492.
2018-10-18 07:57:57 +00:00
Nicholas Marriott
f54f171d5c Merge branch '2.8-rc' 2018-10-17 19:33:43 +01:00
Nicholas Marriott
01918cb017 tmux 2.8. 2018-10-17 19:29:35 +01:00
Nicholas Marriott
a2c52d9f26 Add to TODO. 2018-10-16 14:16:48 +01:00
Nicholas Marriott
407075d8c7 Add to TODO. 2018-10-16 14:12:33 +01:00
Nicholas Marriott
cdd8c93f54 Add to TODO file. 2018-10-15 09:09:40 +01:00
Nicholas Marriott
c88e945bc5 Support OSC 52 ? to read the top buffer inside tmux, also add
refresh-client -l to get the clipboard outside tmux. GitHub issue
1477.
2018-10-11 16:20:14 +01:00
Nicholas Marriott
018f1b8a80 Use :: for escaping : in terminal-overrides not \:. 2018-10-08 19:42:55 +01:00
Nicholas Marriott
4b9e76aaaa Support for extended underline styles, enabled by adding the Smulx
capability with terminal-overrides (add something like
'vte*:Smulx=\E[4\:%p1%dm'). GitHub issue 1492.
2018-10-08 13:21:37 +01:00
Nicholas Marriott
46847e9b2e Update TODO. 2018-10-08 13:06:37 +01:00
Nicholas Marriott
1952b3f746 Update CHANGES. 2018-10-07 15:06:40 +01:00
Nicholas Marriott
546060f340 Update TODO. 2018-10-07 15:01:41 +01:00
Thomas Adam
c44bb2df17 Merge branch 'obsd-master' 2018-10-03 17:02:38 +01:00
nicm
f7c85f3ed8 Do not move the cursor when the mouse wheel is used, GitHub issue 1493. 2018-10-03 15:27:55 +00:00
Nicholas Marriott
5a7cf897f2 Correctly check offset for drawing multiple cells, GitHub issue 1481. 2018-10-01 19:47:58 +01:00
Nicholas Marriott
8053b65f1e Fix select-pane -m, GitHub issuie 1490. 2018-09-28 09:38:22 +01:00
Thomas Adam
a00cdcdfcb Merge branch 'obsd-master' 2018-09-27 11:02:37 +01:00
nicm
228e1a3951 Use same working directory rules for jobs as new windows rather than
always starting in home, GitHub issue 1488.
2018-09-27 07:43:18 +00:00
Nicholas Marriott
ebaf54251a Add formats for when window is larger than client, and show offset in
status-right by default when larger.
2018-09-26 18:41:18 +01:00
Nicholas Marriott
b74b047730 More of revert. 2018-09-26 16:49:03 +01:00
Nicholas Marriott
04c6db2d0f Revert "Add a B flag to mark windows bigger than the client."
This reverts commit b4e74f4310.
2018-09-26 16:42:29 +01:00
Nicholas Marriott
6abb62df1e Change the B into a +. 2018-09-25 21:57:29 +01:00
Thomas Adam
7cf00d6b72 Merge branch 'obsd-master' 2018-09-25 17:02:41 +01:00
nicm
7d59f82cf9 Allow panes to be 1 line or column by redrawing instead of using the
scroll region, from Soeren Tempel in GitHub issue 1487.
2018-09-25 14:27:20 +00:00
Nicholas Marriott
cbf1504fca Do not clamp to needed size since it may be too big. 2018-09-25 15:15:44 +01:00
Nicholas Marriott
83b2d5c513 window_printable_flags needs an additional argument. 2018-09-25 09:55:49 +01:00
Nicholas Marriott
b4e74f4310 Add a B flag to mark windows bigger than the client. 2018-09-25 09:54:47 +01:00
Nicholas Marriott
26d73a7736 Ignore clients that are suspended or exiting. 2018-09-25 09:48:48 +01:00
Nicholas Marriott
57069287a1 Add to TODO. 2018-09-25 08:27:53 +01:00
Thomas Adam
4799f43298 Merge branch 'obsd-master' 2018-09-24 17:02:38 +01:00
nicm
7bc6c105b7 Only include pane status in minimum size if it is turned on, GitHub
issue 1480.
2018-09-24 15:29:56 +00:00
Nicholas Marriott
ad71e7f9d2 Calculate size when trimming RHS correctly. 2018-09-24 12:17:29 +01:00
Nicholas Marriott
71d2ab184b Fix up merge. 2018-09-12 07:15:27 +01:00
Thomas Adam
c067af8e7d Merge branch 'obsd-master' 2018-09-11 20:11:11 +01:00
Nicholas Marriott
3fa538181b Restore window_pane_visible for drawing panes and borders, fixes issue
1458 reported by Felix Rosencrantz, problem located by Avi Halachmi.
2018-09-11 18:34:53 +01:00
nicm
be2201200f The cursor position is limited to the margins for CUF and CUB, so turn
margins off for printing cells (like most everything else already
does). Problem reported by Thomas Sattler.
2018-09-11 17:31:01 +00:00
Nicholas Marriott
84df87011c x,y -> px,py. 2018-09-11 09:39:28 +01:00
Thomas Adam
5e36d52651 Merge branch 'obsd-master' 2018-09-11 09:21:16 +01:00
nicm
bd9133b31d Do not check for mouse events on pane borders when zoomed, based on a
fix from Avi Halachmi.
2018-09-11 06:37:54 +00:00
Thomas Adam
9b32758a0c Merge branch 'obsd-master' 2018-09-10 09:02:39 +01:00
Nicholas Marriott
5aa435a9f0 window_get_active_at needs to check visible also. 2018-09-10 07:51:11 +01:00
nicm
1b92afa799 Do not clear selection when searching. 2018-09-10 06:48:01 +00:00
Nicholas Marriott
a618271e12 Bring back window_pane_visible to stop input going to panes which are
hidden by zoom.
2018-09-10 07:19:17 +01:00
Nicholas Marriott
8598fd1bc5 Add to TODO. 2018-09-09 07:52:28 +01:00
Nicholas Marriott
59df942e09 Fixes to resize-window from Ben Boeckel. 2018-09-05 08:43:58 +01:00
Nicholas Marriott
621bb15b83 Cast parameters to tparm, from Christos Zoulas via Leonardo Taccari. 2018-09-05 08:42:17 +01:00
Thomas Adam
8e24b0bb3e Makefile.am: Add space between -f and argument
Required for some (older) aek instance -- namely NetBSD.
2018-09-04 13:13:32 +01:00
Thomas Adam
0c07b10b30 Merge branch 'obsd-master' 2018-09-03 11:02:39 +01:00
nicm
8f9491ddfe Allow a large line number to go to the end with goto-line, from Mark
Kelly in GitHub issue 1460.
2018-09-03 08:51:43 +00:00
nicm
9bab73f489 Fix selection test, from Takeshi Banse. 2018-09-03 08:47:27 +00:00
Nicholas Marriott
4e867202e8 Add to TODO. 2018-08-31 14:10:51 +01:00
Thomas Adam
e27b588b6c Merge branch 'obsd-master' 2018-08-29 21:02:37 +01:00
Nicholas Marriott
479cac4896 Fix target line for fast path in tty_draw_pane. 2018-08-29 20:52:27 +01:00
nicm
95e3e363ff Reset line flag when clearing selection, GitHub issue 1454. 2018-08-29 18:54:23 +00:00
Nicholas Marriott
7637518b07 Fix refresh-client flags. 2018-08-29 18:59:43 +01:00
Nicholas Marriott
9263a65b5f Update TODO. 2018-08-29 18:52:04 +01:00
Thomas Adam
b29028a914 Merge branch 'obsd-master' 2018-08-29 13:02:38 +01:00
Thomas Adam
1ea17a72f0 Merge branch 'obsd-master' 2018-08-29 11:02:36 +01:00
nicm
f57aa143c1 Keep any text killed in the command prompt with C-w and yank it with
C-y, only use the top buffer if no text has previously been killed. This
and previous change promped by discussion with kn@.
2018-08-29 09:50:32 +00:00
nicm
e53094bc5f Add C-Left and C-Right as aliases for M-b and M-f. 2018-08-29 08:56:51 +00:00
Thomas Adam
18b611bc8d Merge branch 'obsd-master' 2018-08-27 13:02:38 +01:00
nicm
79d2351ce8 Memory leaks, from Gang Fan in GitHub issue 1453. 2018-08-27 11:03:34 +00:00
Nicholas Marriott
79a9472dbc tty_clamp_* need to use wp->xoff and wp->yoff for the check (which
don't include status line, line ox and oy), but ctx->xoff and yp->off
to calculate the position (which do have the statu line).
2018-08-26 14:10:39 +01:00
Thomas Adam
d64daf874f Merge branch 'obsd-master' 2018-08-26 11:02:38 +01:00
nicm
1b4402c823 Add q: format prefix to escape sh(1) special characters. Suggested by
someone ages ago and then more recently in GitHub issue 1449.
2018-08-26 09:28:42 +00:00
Nicholas Marriott
7fbd2f5498 Do not draw cells which have no cell (zoomed and they are not active). 2018-08-25 13:55:50 +01:00
Thomas Adam
45841400f2 Merge branch 'obsd-master' 2018-08-23 21:02:36 +01:00
nicm
f38b5a1b58 all_jobs can be static. 2018-08-23 18:39:12 +00:00
Thomas Adam
da5d563375 Merge branch 'obsd-master' 2018-08-23 19:02:40 +01:00
nicm
bceccc6b63 Move job struct into job.c. 2018-08-23 15:45:05 +00:00
Nicholas Marriott
183193bdbc Update CHANGES. 2018-08-23 08:52:22 +01:00
Thomas Adam
5b93f0fcd3 Merge branch 'obsd-master' 2018-08-22 23:02:43 +01:00
Nicholas Marriott
ee3e0eb183 Update TODO. 2018-08-22 21:29:30 +01:00
nicm
55db3623bf Add StatusLeft and StatusRight mouse key modifiers for the left and
right parts of the status line.
2018-08-22 20:06:14 +00:00
Nicholas Marriott
db8849e7ca Update TODO. 2018-08-21 09:29:12 +01:00
Nicholas Marriott
bfc9fb4b3b Add flags to refresh-client (-U -D -L -R and -c) to pan a window that
is larger than the client manually. Bound to S-Up, S-Down, S-Left,
S-Right and Delete manually.

Also add aliases for keys DC = Delete, IC = Insert, and make
refresh-client -C accept XxY as well as X,Y to match default-size.
2018-08-21 09:27:19 +01:00
Nicholas Marriott
314ee137a9 The stored mouse position should not include the status line offset if any. 2018-08-21 09:10:23 +01:00
Thomas Adam
f36d2ecb07 Merge branch 'obsd-master' 2018-08-20 23:02:38 +01:00
nicm
98a478ceb3 Move offset of window list into status struct. 2018-08-20 20:41:58 +00:00
Nicholas Marriott
9f39470b38 Only screen-redraw.c needs to adjust for message or prompt when the
status line is off, get rid of tty_status_lines and just pass the
client into status_line_size so it can check the CLIENT_STATUSOFF flag
as well.
2018-08-20 20:05:34 +01:00
Nicholas Marriott
458b4b7701 Need to adjust for lines if at top. 2018-08-20 19:45:32 +01:00
Nicholas Marriott
31508228bc Use the y offset from the context which has already been adjusted for
the status line, also make tty_clamp_line adjust the y position.
2018-08-20 19:34:04 +01:00
Nicholas Marriott
1e8c9fb490 Update CHANGES. 2018-08-20 17:52:27 +01:00
Thomas Adam
098967a085 Merge branch 'obsd-master' 2018-08-20 17:02:39 +01:00
nicm
665f046950 Add -Z to find-window as well. 2018-08-20 15:00:42 +00:00
Nicholas Marriott
641191ab20 Support for windows larger than the client.
This adds two new options, window-size and default-size, and a new
command, resize-window.

The force-width and force-height options, and the session_width and
session_height formats have been removed.

The new window-size option tells tmux how to work out the size of
windows: largest means it picks the size of the largest session,
smallest the smallest session (similar to the old behaviour) and
manual means that it does not automatically resize
windows. aggressive-resize modifies the choice of session for largest
and smallest as it did before.

If a window is in a session attached to a client that is too small,
only part of the window is shown. tmux attempts to keep the cursor
visible, so the part of the window displayed is changed as the cursor
moves (with a small delay, to try and avoid excess redrawing when
applications redraw status lines or similar that are not currently
visible).

Drawing windows which are larger than the client is not as efficient
as those which fit, particularly when the cursor moves, so it is
recommended to avoid using this on slow machines or networks (set
window-size to smallest or manual).

The resize-window command can be used to resize a window manually. If
it is used, the window-size option is automatically set to manual for
the window (undo this with "setw -u window-size"). resize-window works
in a similar way to resize-pane (-U -D -L -R -x -y flags) but also has
-a and -A flags. -a sets the window to the size of the smallest client
(what it would be if window-size was smallest) and -A the largest.

For the same behaviour as force-width or force-height, use
resize-width -x or -y.

If the global window-size option is set to manual, the default-size
option is used for new windows. If -x or -y is used with new-session,
that sets the default-size option for the new session.

The maximum size of a window is 10000x10000. But expect applications
to complain and higher memory use if you make a window that big. The
minimum size is the size required for the current layout including
borders.

This change allows some code improvements, most notably that since
windows can now never be cropped, that code can be removed from the
layout code, and since panes can now never be outside the size of the
window, window_pane_visible can be removed.
2018-08-20 15:22:14 +01:00
nicm
9f2db6a0af Fix problems with page scrolling in copy mode, GitHub issue 1440 from
Amos Bird.
2018-08-20 13:51:09 +00:00
Thomas Adam
bf03197e18 Merge branch 'obsd-master' 2018-08-19 21:40:26 +01:00
nicm
cac4eadca0 Add a flag to force redrawing of the status line even if the content
hasn't changed, needed for resizing.
2018-08-19 20:13:07 +00:00
Thomas Adam
3310972d75 Merge branch 'obsd-master' 2018-08-19 21:02:37 +01:00
nicm
d95fad3d5f Expand \u and \U escape sequences in command strings, from Christopher
Hunt in GitHub issue 1443.
2018-08-19 19:03:46 +00:00
Thomas Adam
9ecf657703 Merge branch 'obsd-master' 2018-08-19 19:02:40 +01:00
nicm
88327c7698 Add a client redraw-window flag instead of the redraw-all flag and for
all just use the three flags together (window, borders, status).
2018-08-19 16:45:03 +00:00
Thomas Adam
e811132b05 Merge branch 'obsd-master' 2018-08-18 23:02:40 +01:00
nicm
bd2896b65e SESSION_UNATTACHED flag is no longer necessary now we have an attached
count instead.
2018-08-18 20:08:52 +00:00
Thomas Adam
522d751eee Merge branch 'obsd-master' 2018-08-18 19:02:39 +01:00
nicm
3bc08b0dc0 Some tidying and helper functions. 2018-08-18 16:14:03 +00:00
Nicholas Marriott
af679326b2 Now master again. 2018-08-17 11:46:08 +01:00
Nicholas Marriott
aa6e6fa0f2 2.8. 2018-08-17 11:45:40 +01:00
Nicholas Marriott
9bdbe171b7 2.8-rc. 2018-08-17 11:31:16 +01:00
Thomas Adam
98a3c98c28 Merge branch 'obsd-master' 2018-08-17 11:20:20 +01:00
Nicholas Marriott
de2ddddd60 Add a full stop. 2018-08-17 10:30:04 +01:00
nicm
a9ffb56b65 Add the KEYC_XTERM flag to all function keys that imply a modifier so
that they are correctly translated into xterm(1)-style keys. GitHub
issue 1437.
2018-08-16 14:04:03 +00:00
nicm
14b97fc889 Add size to arguments struct too. 2018-08-14 11:38:05 +00:00
nicm
d0a600ccaa Some tidying, use a struct for arguments (there will be more later) and
add a helper function.
2018-08-14 11:31:34 +00:00
Thomas Adam
a368548645 Merge branch 'obsd-master' 2018-08-10 11:41:07 +01:00
Nicholas Marriott
13fe06a459 Update CHANGES. 2018-08-10 10:21:40 +01:00
nicm
87e87030fe Whoops, didn't mean to commit this. 2018-08-09 09:54:22 +00:00
nicm
a5ef1f2ed6 Bump the UTF-8 character array up to 18 to allow for more combining
characters (some languages use up to five). This size doesn't make as
much difference now that UTF-8 goes into an extended cell. GitHub issue
1430.
2018-08-09 09:53:44 +00:00
nicm
f5d7a80272 calloc the mode data instead of malloc and initialize everything. 2018-08-05 08:59:30 +00:00
Thomas Adam
33f9b316a3 Merge branch 'obsd-master' 2018-08-02 21:02:25 +01:00
nicm
d6ff630498 Log command arguments. 2018-08-02 18:35:21 +00:00
Thomas Adam
eceaa9a493 Merge branch 'obsd-master' 2018-08-02 15:02:25 +01:00
Thomas Adam
2e19a5ecb9 Merge branch 'obsd-master' 2018-08-02 13:02:26 +01:00
nicm
fb1f0fee5a session_groups can be static also. 2018-08-02 11:56:12 +00:00
nicm
6048b0f483 Make key trees and some other bits static. 2018-08-02 11:44:07 +00:00
nicm
f12b857415 Minor tidying. 2018-08-02 11:18:34 +00:00
Thomas Adam
79bdca4638 Merge branch 'obsd-master' 2018-08-02 11:02:25 +01:00
nicm
21f8ac2766 Make display-panes block the client until a pane is chosen or it times out. 2018-08-02 07:55:16 +00:00
Thomas Adam
89b56c3451 Merge branch 'obsd-master' 2018-08-01 17:02:25 +01:00
nicm
fe7486d43b Initialize new lineflag member. 2018-08-01 15:22:40 +00:00
Thomas Adam
400b807d75 Merge branch 'obsd-master' 2018-07-31 17:02:31 +01:00
nicm
5f07da6227 Do not leak path or use it after free. 2018-07-31 13:06:44 +00:00
Thomas Adam
7eb3ef66e5 Merge branch 'obsd-master' 2018-07-31 13:02:25 +01:00
nicm
82776c456e Move struct screen_sel into screen.c and tidy up members that are only
used by copy mode.
2018-07-31 11:49:26 +00:00
nicm
80bdd89856 Clear history on RIS like most other terminals do. 2018-07-31 10:32:19 +00:00
Thomas Adam
ed6327c87b Merge branch 'obsd-master' 2018-07-30 13:02:25 +01:00
nicm
b21a710de7 Remove a leftover unused struct. 2018-07-30 11:24:55 +00:00
Thomas Adam
aa32457772 Merge branch 'obsd-master' 2018-07-23 21:02:25 +01:00
kn
5c78b48cdf Point to glob in section 7 for the actual list of special characters instead
the C API in section 3.

OK millert jmc nicm, "the right idea" deraadt
2018-07-23 19:02:49 +00:00
Thomas Adam
5fc2d4a4fc Merge branch 'obsd-master' 2018-07-17 21:02:24 +01:00
nicm
969af935f3 When a key isn't in the first table, we need to try the same key again
not the any key. Also rename some labels. Fixes GitHub issue 1406
reeported by Mark Kelly.
2018-07-17 18:02:40 +00:00
Thomas Adam
4f04b2094c Merge branch 'obsd-master' 2018-07-16 11:02:25 +01:00
nicm
0d88f8a78b Add an "Any" key to run a command if a key is pressed that is not bound
in the current key table. GitHub issue 1404.
2018-07-16 08:48:22 +00:00
Thomas Adam
6de991d855 Merge branch 'obsd-master' 2018-07-15 11:02:25 +01:00
nicm
ff67ef945d Fix new-window -k, GitHub issue 1403. 2018-07-15 06:57:13 +00:00
Thomas Adam
711b8164bb Merge branch 'obsd-master' 2018-07-11 11:02:26 +01:00
Nicholas Marriott
35985c0add Updates to CHANGES. 2018-07-11 09:51:18 +01:00
nicm
cfc81692e6 Expand formats in load-buffer and save-buffer. 2018-07-11 08:29:21 +00:00
Thomas Adam
a4a7c3c68d Merge branch 'obsd-master' 2018-07-11 09:02:25 +01:00
nicm
e7d53020b4 Helper function to shorten history. 2018-07-11 06:51:39 +00:00
nicm
03519021b9 Add function comments. 2018-07-11 06:43:45 +00:00
Thomas Adam
6f2698004e Merge branch 'obsd-master' 2018-07-06 09:02:24 +01:00
nicm
28a5bc8fae Add a rectangle_toggle format, from Hirokazu Hata. 2018-07-06 07:11:23 +00:00
Thomas Adam
20154f391e Merge branch 'obsd-master' 2018-07-04 15:02:25 +01:00
jmc
98c4291df2 whitespace needed between macro args and punctuation; 2018-07-04 13:27:32 +00:00
Nicholas Marriott
5c0ce192ed +README.ja. 2018-07-04 13:45:40 +01:00
nicm
cc743dc296 Add set-hook -R to run a hook immediately (useful to set multiple hooks
to the same thing).
2018-07-04 12:30:52 +00:00
nicm
d254293a6d Add pane focus hooks. 2018-07-04 12:25:26 +00:00
Thomas Adam
850c26dd46 Merge branch 'obsd-master' 2018-07-04 13:02:25 +01:00
Nicholas Marriott
db07f33886 Japanese README from Kohei Takada. 2018-07-04 10:47:14 +01:00
nicm
2fae6a5761 Add accessors for grid linedata member, for some future work. From Dan
Aloni.
2018-07-04 09:44:07 +00:00
Thomas Adam
2ee0962c96 Merge branch 'obsd-master' 2018-07-02 15:02:25 +01:00
nicm
42935bde71 Fire notify for select-layout, from George Nachman. 2018-07-02 12:39:14 +00:00
Nicholas Marriott
ffebf00585 Solaris 11.4 and later prefers mdoc, from Alan Coopersmith. 2018-07-02 13:36:44 +01:00
Thomas Adam
ead6d652ff Merge branch 'obsd-master' 2018-06-27 19:02:25 +01:00
nicm
a14aa788d4 Allow any punctuation (except :) as separator in s/x/y/, not only
/. From JINNOUCHI Yasushi in GitHub issue 1386.
2018-06-27 17:36:10 +00:00
Thomas Adam
d8721b35a0 Merge branch 'obsd-master' 2018-06-26 15:02:25 +01:00
nicm
97738921cd Style nit. 2018-06-26 13:21:28 +00:00
Thomas Adam
486ce9b098 Merge branch 'obsd-master' 2018-06-26 13:02:25 +01:00
nicm
8fb6666f17 Do not take address of a member of a NULL pointer. GitHub issue 1382
from Kamil Rytarowski.
2018-06-26 11:14:05 +00:00
Thomas Adam
cb77c2aa78 Merge branch 'obsd-master' 2018-06-25 19:02:24 +01:00
nicm
0c94c3fbee If there are only two panes, always use the other pane as the last
pane. Based on a change from Duy Nguyen in GitHub issue 1377.
2018-06-25 17:23:16 +00:00
Thomas Adam
94712a8b0d Merge branch 'obsd-master' 2018-06-24 23:02:25 +01:00
nicm
dec6ec9e29 Minor cosmetic improvement from KOIE Hidetaka. 2018-06-24 21:24:09 +00:00
Thomas Adam
9da78d72de Merge branch 'obsd-master' 2018-06-11 13:02:25 +01:00
nicm
d0c992306d Fix some compiler warnings; from Thomas Adam. 2018-06-11 11:14:10 +00:00
Thomas Adam
54c2d48d7d Merge branch 'obsd-master' 2018-06-09 19:02:29 +01:00
nicm
e6cbeb4f38 Make it possible to resize multiple panes by dragging corners, from Dan
Aloni in GitHub issue 1376.
2018-06-09 17:05:52 +00:00
Thomas Adam
4581240ced Merge branch 'obsd-master' 2018-06-08 23:02:25 +01:00
nicm
f6bad7efd7 Instead of working out which pane to resize with the mouse by walking
the panes list, look through the layout cells for the nearest border and
resize that cell. From Dan Aloni in GitHub issue 1374.
2018-06-08 20:54:22 +00:00
Thomas Adam
713e0ddef3 Merge branch 'obsd-master' 2018-06-08 13:02:25 +01:00
nicm
ff45b2d343 Tweak previous - check for a NULL client and simplify manual text. 2018-06-08 09:43:58 +00:00
Thomas Adam
91280f1fca Linux: include sys/file.h for flock() 2018-06-07 09:17:05 +01:00
Thomas Adam
7de25d86e1 Merge branch 'obsd-master' 2018-06-03 13:02:31 +01:00
nicm
ba31d3a88c Increment the lines counter when skipping a line to avoid an infinite
loop, and fix a check to avoid a potential out-of-bounds access. Problem
reported by Yuxiang Qin and tracked down by Karl Beldan; GitHub issue
1352.

Also a man page fix request by jmc@.
2018-06-03 10:17:30 +00:00
Thomas Adam
54cd292f09 Merge branch 'obsd-master' 2018-05-29 11:02:26 +01:00
nicm
d1f5142dab If foo doesn't exist and can't be expanded in #{?foo,a,b} then assume it
is false.
2018-05-29 09:10:30 +00:00
Thomas Adam
058d2b94dc Merge branch 'obsd-master' 2018-05-28 15:02:31 +01:00
nicm
c177a627d2 When looking for panes, ignore dead ones (with -1 file
descriptor). GitHub issue 1354.
2018-05-28 11:50:47 +00:00
Nicholas Marriott
8f8e0975f1 Add format string test, from "sadie-parayno" in GitHub issue 1358. 2018-05-28 12:48:15 +01:00
nicm
b602c1fb9a Document escaping inside conditionals, from "sadie-parayno" in GitHub
issue 1359.
2018-05-28 11:45:26 +00:00
Thomas Adam
7448b38327 Merge branch 'obsd-master' 2018-05-24 13:02:29 +01:00
Thomas Adam
85d5a377c5 Merge branch 'obsd-master' 2018-05-24 11:02:25 +01:00
nicm
b9a6162d2f Make server_client_get_cwd used (almost) everywhere we need to work out
the cwd, and do not fall back to "." as it is pretty useless. GitHub
issue 1331.
2018-05-24 09:42:49 +00:00
nicm
8f5903d7c3 Improve logging of the environment etc for new panes. 2018-05-24 09:34:54 +00:00
Thomas Adam
f0ac0d6793 Merge branch 'obsd-master' 2018-05-22 11:02:33 +01:00
nicm
2a04665626 Allow escaping , and } with # in #{}; GitHub issue 1332. 2018-05-22 08:49:12 +00:00
Nicholas Marriott
07c0970f54 Sync tmux description with manual. 2018-05-22 08:02:43 +01:00
Thomas Adam
546123f950 Merge branch 'obsd-master' 2018-05-20 15:02:25 +01:00
nicm
f2f9605c63 -T should not actually select the pane. 2018-05-20 11:48:34 +00:00
Thomas Adam
e4e060f2be Merge branch 'obsd-master' 2018-05-15 17:02:31 +01:00
nicm
e3b034fac7 Fix switch-client -l, from Jean-Marc Eurin in GitHub issue 1343. 2018-05-15 14:58:09 +00:00
Thomas Adam
82c0eed36d Merge branch 'obsd-master' 2018-05-09 19:02:35 +01:00
nicm
80994a8de1 Mention allow-rename with \033k. 2018-05-09 16:20:50 +00:00
Thomas Adam
9e1093b7d7 Merge branch 'obsd-master' 2018-05-09 11:02:26 +01:00
nicm
f2029f9d9e Another check for NULL window if looking for index. 2018-05-09 07:50:03 +00:00
Thomas Adam
b2a2c3a1e9 Merge branch 'obsd-master' 2018-05-07 17:02:31 +01:00
nicm
f915a4bf0c Handle terminfo colors > 256 correctly, GitHub issue 1337. 2018-05-07 13:39:09 +00:00
Thomas Adam
91b220525b Merge branch 'obsd-master' 2018-05-04 11:02:31 +01:00
nicm
988c6bc433 Improve logging of sessions. 2018-05-04 08:21:42 +00:00
Thomas Adam
1d858aa89e Merge branch 'obsd-master' 2018-05-03 19:02:26 +01:00
nicm
e24a077752 Use window target if specified and exists even when looking for an
index, fixes neww -a with -t as well.
2018-05-03 16:56:59 +00:00
Thomas Adam
645fe9013f Merge branch 'obsd-master' 2018-04-26 17:02:31 +01:00
guenther
896c1da7da Use <fcntl.h> instead of <sys/file.h> for open() and friends.
Delete a bunch of unnecessary #includes and sort to match style(9)
while doing the above cleanup.

ok deraadt@ krw@
2018-04-26 12:42:51 +00:00
Thomas Adam
d24bd7394d Merge branch 'obsd-master' 2018-04-23 17:02:32 +01:00
Nicholas Marriott
aebb17dc75 Sync imsg from OpenBSD. 2018-04-23 15:40:15 +01:00
nicm
d9d2f84a4b Add KRB5CCNAME to update-environment. 2018-04-23 14:03:06 +00:00
nicm
068d1b97b2 #aabbcc will use RGB if supported so don't say it is closest match. 2018-04-23 13:51:21 +00:00
nicm
4bf6f2706e Check whether cursor is at start or end when copying rectangular
selections, from tb@.
2018-04-23 13:46:34 +00:00
nicm
9f39652d87 Remove unnecessary brackets. 2018-04-23 13:43:08 +00:00
Thomas Adam
c48440fd40 Merge branch 'obsd-master' 2018-04-23 11:02:27 +01:00
nicm
1afe71cc0a rxvt-unicode has some funny behaviour when scrolling with the cursor not
at column 1, so move it back there first if possible. GitHub issue 1318.
2018-04-23 07:41:30 +00:00
Thomas Adam
0e1b339c10 Merge branch 'obsd-master' 2018-04-18 17:02:28 +01:00
nicm
3dceddd70e Change how display-message uses the client. Originally it was only
intended as the target client where the message should be displayed but
at some point (perhaps when -p was added), it was used for format
expansion too. This means it can get a bit weird where you have client
formats expanding for a client with a different current session than the
target session.

However, it is nice that display-message can be used to show information
about a specific client. So change so that the -c client will be used if
the session matches the target session (-t or default), otherwise the
best client will be chosen.
2018-04-18 14:35:37 +00:00
nicm
2595718dd3 Include source function name in grid_check_y logging. 2018-04-18 14:31:42 +00:00
Thomas Adam
6ebd737590 Merge branch 'obsd-master' 2018-04-18 15:02:25 +01:00
nicm
e64d078a4c Fix || example. 2018-04-18 12:50:11 +00:00
Nicholas Marriott
ae0b7c7d72 Some changes. 2018-04-13 17:59:11 +01:00
Nicholas Marriott
a770ef3e2a Merge branch '2.7-rc' 2018-04-13 17:50:40 +01:00
Nicholas Marriott
b95d1de8fd 2.7. 2018-04-13 17:47:36 +01:00
Thomas Adam
7e5262ae9a Merge branch 'obsd-master' 2018-04-11 13:02:28 +01:00
nicm
14ecb5032e Allow no client for rename-session, from Ryan Freeman. 2018-04-11 09:54:45 +00:00
Thomas Adam
1bd66b65a3 Merge branch 'obsd-master' 2018-04-10 13:02:28 +01:00
nicm
051a29ca03 A couple of fixes to the : form of SGR. Apparently there is an extra
argument that nobody knew about, so skip that if it exists. Also there
are a bunch of useless optional arguments at the end, so ignore those.
2018-04-10 11:20:15 +00:00
nicm
c6975b3bb4 Add x and X to choose-tree (with a confirmation prompt) to kill an
item. Suggested by Matt Zagrabelny.
2018-04-10 10:48:44 +00:00
Nicholas Marriott
68bf7c532b Merge branch '2.7-rc' 2018-04-06 12:53:43 +01:00
Thomas Adam
9b73d76ddd Merge branch 'obsd-master' 2018-04-06 11:02:24 +01:00
nicm
5d616f4c72 Fix link, from Eliran Gonen. 2018-04-06 09:09:38 +00:00
nicm
8a81993ae1 Do not crash on empty window, reported by Jamie Macdonald in GitHub
issue 1299. Patch from Thomas Adam.
2018-03-29 13:19:19 +01:00
Thomas Adam
b5c0b2cae2 Merge branch 'obsd-master' 2018-03-29 10:28:18 +01:00
nicm
803b8815bd Do not crash on empty window, reported by Jamie Macdonald in GitHub
issue 1299. Patch from Thomas Adam.
2018-03-29 08:03:51 +00:00
nicm
785ce66ab9 Fix a regression: do not warn about no client in rename-window. 2018-03-26 07:39:12 +01:00
Thomas Adam
640d97afd0 Merge branch 'obsd-master' 2018-03-23 20:02:31 +00:00
nicm
194e9f611b Fix a regression: do not warn about no client in rename-window. 2018-03-23 19:17:03 +00:00
nicm
ea295ac397 Fix size calculation when spreading out panes. 2018-03-23 10:07:54 +00:00
Thomas Adam
5512de6a61 Merge branch 'obsd-master' 2018-03-23 10:02:30 +00:00
nicm
26792b9035 Fix size calculation when spreading out panes. 2018-03-23 07:44:44 +00:00
Nicholas Marriott
919f55ac4a Merge branch '2.7-rc' 2018-03-22 11:26:32 +00:00
Nicholas Marriott
2cd0ba5057 CHANGES for 2.7. 2018-03-22 11:25:58 +00:00
Nicholas Marriott
80283f99fb Revert "2.7-rc."
This reverts commit ced74bd72c.
2018-03-22 11:18:26 +00:00
Nicholas Marriott
ced74bd72c 2.7-rc. 2018-03-22 11:18:05 +00:00
Nicholas Marriott
50e3e3e72f Remove EVENT_* variables from environment after initializing libevent so they
are not carried into child processes; from Henry Qin.
2018-03-21 08:15:15 +00:00
Thomas Adam
c8a706117f Merge branch 'obsd-master' 2018-03-17 18:02:26 +00:00
nicm
0b3911631b Fix negative window index range check (> not <). Reported by Juan Pablo
in GitHub issue 1283.
2018-03-17 16:48:17 +00:00
Thomas Adam
0ca78ee51f Merge branch 'obsd-master' 2018-03-16 16:02:28 +00:00
nicm
f87d80737e Insert full size panes at the right position, from KOIE Hidetaka in
GitHub issue 1284.
2018-03-16 15:15:39 +00:00
Thomas Adam
9fd9952752 Merge branch 'obsd-master' 2018-03-08 10:02:26 +00:00
nicm
19f3a5c612 Add a missing client-detached hook when the server shuts down, and do
not exit until jobs started from run-shell/if-shell have finished (add a
job flags member and a flag to indicate other jobs). GitHub issue 1245.
2018-03-08 08:09:10 +00:00
Thomas Adam
3c451a64b5 Merge branch 'obsd-master' 2018-03-05 14:02:29 +00:00
nicm
85c48aafff For some reason tmux treats SGR 10 as SGR 0. It has done since the first
version and I'm not sure why since no other terminal appears to. Change
to just ignore SGR 10 instead.
2018-03-05 12:32:28 +00:00
Nicholas Marriott
61ea49c6dd Fix cmp use. 2018-03-02 15:08:34 +00:00
Thomas Adam
3b8f92359d Merge branch 'obsd-master' 2018-03-01 14:02:27 +00:00
nicm
182357f24b Expand formats in window and session names. 2018-03-01 12:53:08 +00:00
Thomas Adam
0ca9664ecf Merge branch 'obsd-master' 2018-02-28 10:02:29 +00:00
nicm
508e2f0b3a Add -Z flag to choose-tree, choose-client, choose-buffer to
automatically zoom the pane when the mode is entered and unzoom when it
exits, assuming the pane is not already zoomed. Add -Z to the default
key bindings.
2018-02-28 08:55:44 +00:00
Thomas Adam
f5a37d0071 Merge branch 'obsd-master' 2018-02-26 10:02:30 +00:00
nicm
4d72b8fff7 C-g for modes too, from Mike Hamrick. 2018-02-26 08:09:56 +00:00
Thomas Adam
9464b94f64 Merge branch 'obsd-master' 2018-02-22 14:02:30 +00:00
Thomas Adam
c2aa40449c Merge branch 'obsd-master' 2018-02-22 12:02:31 +00:00
nicm
3f3f13fbd7 Remove an unused variable. 2018-02-22 11:42:41 +00:00
nicm
e97daead43 Check prefix when retrying so it is checked while repeat flag is
set. GitHub issue 1239.
2018-02-22 10:58:12 +00:00
nicm
623f4b12d3 Add exit-empty option to exit server if no sessions (defaults to on). 2018-02-22 10:54:51 +00:00
Thomas Adam
5a44e18490 Merge branch 'obsd-master' 2018-02-20 12:02:23 +00:00
nicm
ab6f0bb348 Do not leak memory when working out job name in formats. 2018-02-20 10:43:46 +00:00
Thomas Adam
4e8b1b9ac2 Merge branch 'obsd-master' 2018-02-19 22:02:29 +00:00
Nicholas Marriott
d81aec2439 Update CHANGES. 2018-02-19 21:24:17 +00:00
nicm
6ae04dd5a0 Support ISO colon-separated SGR. 2018-02-19 21:20:10 +00:00
Thomas Adam
968296bb07 Merge branch 'obsd-master' 2018-02-16 12:02:29 +00:00
nicm
320abba341 Reflowing the grid in-place involved way too much memmove() for a big
performance cost with a large history. Instead change back to using a
second grid and copying modified lines over which is much faster (this
doesn't revert to the old code however which didn't support UTF-8
properly). GitHub issue 1249.
2018-02-16 09:51:41 +00:00
Thomas Adam
88711e885e Merge branch 'obsd-master' 2018-02-05 10:02:31 +00:00
nicm
7f4513ec34 Add struct status_line to hold status line members of struct client, not
used yet but will be soon. From Thomas Adam.
2018-02-05 08:21:54 +00:00
Thomas Adam
2d5101621b Merge branch 'obsd-master' 2018-02-05 08:02:27 +00:00
nicm
0817132f97 Show if filter is active/no matches in modes. 2018-02-05 06:51:41 +00:00
Thomas Adam
24abfb72eb Merge branch 'obsd-master' 2018-02-04 12:02:24 +00:00
nicm
fe7a871a23 Upstream ncurses has introduced terminfo capabilities to specify RGB
colour ("true" or "direct" colour). These consist of new entries (such
as "xterm-direct") which have a different setaf/setab implementation,
colors and pairs set to 0x1000000 and 0x10000, and a new RGB flag.

The setaf/setab definitions seem to be geared towards what ncurses (or
emacs maybe) needs, in that the new versions do only ANSI and RGB
colours (they can't be used for the 256 colour palette); they rely on
the silly ISO colon-separated version of SGR; and they use a weird
multiplication scheme so they still only need one argument. The higher
values of colors and pairs require a recent ncurses to parse.

tmux can use the RGB flag to detect RGB colour support (keeping the old
Tc extension for backwards compatibility for now). However, as we still
want to send 256 colour information unchanged when possible, the new
setaf/setab are awkward. So when RGB is present, reserve setaf/setab
only for ANSI colours and use the escape sequences directly for 256 and
RGB colours. (To my knowledge no recent terminal uses unusual escape
sequences for these in any case.)
2018-02-04 10:10:39 +00:00
Nicholas Marriott
4e4c500879 Add more to TODO. 2018-01-29 12:46:52 +00:00
Nicholas Marriott
0407d847a4 Add to TODO. 2018-01-29 12:44:31 +00:00
Thomas Adam
19afd842bf Merge branch 'obsd-master' 2018-01-18 16:02:25 +00:00
nicm
17d4c39f24 Discard all but the last line when reading from a #() command - the
callback is just going to be fired again straight away to go through all
the lines, it is better just to use the last one straight away.
2018-01-18 14:28:11 +00:00
Thomas Adam
d9e740f86d Merge branch 'obsd-master' 2018-01-18 08:02:30 +00:00
nicm
c9037fde1c Remove unused hooks_run function, from Thomas Adam. 2018-01-18 07:10:53 +00:00
Thomas Adam
84ddc72744 Merge branch 'obsd-master' 2018-01-17 11:26:10 +00:00
nicm
75842bfe66 Fix drawing of ACS characters (they need to go character-at-a-time),
accidentally broken in last commit.
2018-01-16 17:03:18 +00:00
nicm
5849b73b81 Add -I to pipe-pane to connect pane stdin as well as stdout, suggested
by Kristof Kovacs in GitHub issue 1186.
2018-01-16 09:00:38 +00:00
Nicholas Marriott
58e9d12f23 msys is apparently a cygwin variant that doesn't say it is cygwin... 2018-01-16 08:29:15 +00:00
nicm
53b25635da Another redundant check, GitHub issue 1219. 2018-01-15 15:30:03 +00:00
nicm
481703d669 Some unused code, GitHub issue 1219. 2018-01-15 15:27:03 +00:00
nicm
b0c1cefeda Do not collect top-bit-set characters in case they need to be replaced. 2018-01-12 16:43:47 +00:00
nicm
2c5a6f9af5 Simplify character replacement on non-UTF-8 terminals and make a common
function.
2018-01-12 16:41:00 +00:00
nicm
c03565611e Simplify UTF-8 states down into one state. 2018-01-12 16:32:12 +00:00
nicm
f32fd2df69 Improve error message if creating socket parent directory fails, from
Thomas Adam for GitHub issue 1215.
2018-01-12 10:22:02 +00:00
nicm
829fe38ab1 Improve logging for layout cells. 2018-01-12 10:16:03 +00:00
Thomas Adam
06684c93de Merge branch 'obsd-master' 2018-01-01 12:01:13 +00:00
nicm
d17c90583a Prefer PWD for current directory if present in client, from Wei Zhao in
GitHub issue 1183.
2018-01-01 11:19:08 +00:00
nicm
fe26f977e6 Add C-g at command prompt for emacs people, GitHub issue 1213. 2018-01-01 11:03:54 +00:00
Thomas Adam
6e99a2f4bb Merge branch 'obsd-master' 2017-12-31 22:01:15 +00:00
nicm
c9896d9554 Initialize the size of new panes created by the even-* layout correctly;
reported by Andreas Kahari and Anton Lindqvist.
2017-12-31 20:00:44 +00:00
Thomas Adam
ad417f6eb7 Merge branch 'obsd-master' 2017-12-28 14:01:14 +00:00
nicm
299c552e33 Redrawing status is needed after changing window flags or title does not
update if status line is off, GitHub issue 1191.
2017-12-28 12:10:50 +00:00
Thomas Adam
cd46568ebe Merge branch 'obsd-master' 2017-12-27 14:43:20 +00:00
nicm
937f8ed095 Draw command prompt correctly with status line off. 2017-12-27 13:55:42 +00:00
Nicholas Marriott
6ce8fe0537 Still need to globfree on failure. 2017-12-27 13:54:37 +00:00
nicm
c363c236aa Fix memory leak in screen_redraw_make_pane_status. 2017-12-22 23:16:41 +00:00
Thomas Adam
e19df0e869 Merge branch 'obsd-master' 2017-12-22 12:01:22 +00:00
nicm
7ba5ad4cfb Do not try to set default value on user options (they don't have one),
from Charles Howard in GitHub issue 1161.
2017-12-22 10:18:51 +00:00
nicm
5c82432200 Remove duplicate WheelUp/WheelDown entries in list, GitHub issue 1184. 2017-12-22 10:16:36 +00:00
Thomas Adam
74ecc866cf Merge branch 'obsd-master' 2017-12-19 16:01:20 +00:00
nicm
b20a00f93e Report better error from server when socket create fails, GitHub issue
1201.
2017-12-19 15:00:39 +00:00
Thomas Adam
641a885af8 Merge branch 'obsd-master' 2017-12-19 00:01:18 +00:00
nicm
62144b9f57 Do not try to put more in command message than will fit when sending
(the server will treat as a fatal error). GitHub issue 1200.
2017-12-18 22:13:36 +00:00
Thomas Adam
43a1294ed9 Merge branch 'obsd-master' 2017-12-18 14:01:18 +00:00
nicm
58f6456af7 Remove unused variable from Thomas Adam. 2017-12-18 12:39:34 +00:00
Thomas Adam
2c6af068d7 Merge branch 'obsd-master' 2017-11-17 12:01:17 +00:00
nicm
695dc5a153 Allow formats in selectp -T, from Thomas Adam. 2017-11-17 09:52:18 +00:00
Thomas Adam
5fddddbe21 Merge branch 'obsd-master' 2017-11-16 12:01:18 +00:00
nicm
e5ae9dd53d Add -and-cancel variants for scrolling commands to exit copy mode when
the bottom is reached, from Stephen Hicks.
2017-11-16 11:16:15 +00:00
Thomas Adam
102df8dc80 Merge branch 'obsd-master' 2017-11-15 22:01:22 +00:00
Nicholas Marriott
e58d16b2df Add to CHANGES. 2017-11-15 20:14:49 +00:00
Thomas Adam
e755ca37b3 Merge branch 'obsd-master' 2017-11-15 20:01:22 +00:00
nicm
3b649d2fcd Add a common function for spreading out cells and use it for the two
even layouts and to add a -E flag to select-layout to spread out cells
evenly without changing parent cells.
2017-11-15 19:59:27 +00:00
nicm
533a5719c5 Completely rewrite the reflow code to correctly handle double width
characters (previously they were not accounted for).
2017-11-15 19:21:24 +00:00
nicm
aeda2e5808 If there is a double width character at the very end of the line with
not enough room to draw it, just leave it out.
2017-11-15 19:18:57 +00:00
Thomas Adam
392da897ff Merge branch 'obsd-master' 2017-11-13 14:01:18 +00:00
nicm
d81fa579c3 When searching in copy mode, do not scroll if the result is already on
screen. GitHub issue 1150.
2017-11-13 11:49:11 +00:00
Thomas Adam
515da63d2b Merge branch 'obsd-master' 2017-11-10 00:01:19 +00:00
nicm
384736e955 If we successfully change the directory, set PWD too to give the shell a
hint in case of symlinks.
2017-11-09 23:02:13 +00:00
Thomas Adam
6f3b6c8d92 Merge branch 'obsd-master' 2017-11-03 18:01:21 +00:00
nicm
a2681ffcee Clear key properly if on space with nothing in it. 2017-11-03 17:11:20 +00:00
nicm
50a5f84cb4 Support mouse on preview in tree mode. 2017-11-03 17:02:33 +00:00
Thomas Adam
24c387206c Merge branch 'obsd-master' 2017-11-03 16:01:17 +00:00
nicm
ba93a647f1 Change mouse in modes so that one click moves the cursor and a double
click chooses the line.
2017-11-03 14:23:44 +00:00
Thomas Adam
e1606172dd Merge branch 'obsd-master' 2017-11-03 00:01:20 +00:00
Thomas Adam
c9ec33d0d0 Merge branch 'obsd-master' 2017-11-02 22:01:20 +00:00
nicm
43264dfbf4 Make the mode draw function use the parent screen directly rather than
its own to avoid copying twice.
2017-11-02 22:00:42 +00:00
nicm
8d37f699ad Add a "fast" version of screen_write_copy for tree mode that doesn't do
all the checks and selection and marking stuff needed for copy mode.
2017-11-02 21:29:17 +00:00
Thomas Adam
8c29f7413b Merge branch 'obsd-master' 2017-11-02 20:01:26 +00:00
nicm
17655e5ba6 Format for group list of "other sessions" is a bit weird, just list all
the sessions in the group.
2017-11-02 18:52:05 +00:00
nicm
95850e1aca Tweak previous slightly so that current session is chosen if it is in
the group rather than first.
2017-11-02 18:43:51 +00:00
nicm
c1f62f1fde Only show the first member of session groups in tree mode (-G flag
disables).
2017-11-02 18:27:35 +00:00
nicm
3887d95bca There is no point in reflowing panes which have not changed width. 2017-11-02 18:26:38 +00:00
Thomas Adam
cf782c4f54 Merge branch 'obsd-master' 2017-10-26 10:01:18 +01:00
nicm
e91e8a2a6c Fix crash exiting command prompt (from Alex Maese in GitHub issue 1139)
and a man page tweak from jmc.
2017-10-26 08:17:12 +00:00
Thomas Adam
d36ac3db15 Merge branch 'obsd-master' 2017-10-25 18:01:17 +01:00
nicm
be4c01697c Note that notifications are also hooks. 2017-10-25 15:20:10 +00:00
Thomas Adam
0072bc65e6 Merge branch 'obsd-master' 2017-10-25 16:01:22 +01:00
Nicholas Marriott
37f83adca8 Update CHANGES. 2017-10-25 15:26:54 +01:00
nicm
578a63bbc9 Default allow-rename to off because it is ridiculous that applications
are even able to do this and confusing when they do.
2017-10-25 14:14:52 +00:00
Thomas Adam
6b83ca0077 Merge branch 'obsd-master' 2017-10-25 14:01:26 +01:00
nicm
78ae4ee82c h/l keys for expand and collapse. 2017-10-25 12:13:20 +00:00
Nicholas Marriott
d6edd06749 Merge branch 'master' of github.com:tmux/tmux 2017-10-25 12:29:23 +01:00
Nicholas Marriott
6e8d29e9a2 Update TODO. 2017-10-25 12:29:10 +01:00
nicm
8dd776106d Add P key to paste tagged in buffer mode, and trim some code that should
no longer be necessary.
2017-10-25 11:26:11 +00:00
Thomas Adam
e85213a944 Merge branch 'obsd-master' 2017-10-22 15:47:07 +01:00
nicm
26f1857154 Use window_pane_index() when drawing pane numbers (so pane-base-index is
applied), from Thomas Adam. GitHub issue 1125.
2017-10-22 13:16:54 +00:00
Nicholas Marriott
f7a037ba26 Apparently vim(1) now has syntax highlighting built in, GitHub issue 1124. 2017-10-22 14:14:14 +01:00
Thomas Adam
61114c6c72 Merge branch 'obsd-master' 2017-10-20 16:01:17 +01:00
nicm
d3e8709ab5 Clear status line with spaces again so reverse works, spotted by sthen. 2017-10-20 13:10:54 +00:00
Nicholas Marriott
37531673a3 Need compat for queue.h. 2017-10-20 13:26:54 +01:00
Thomas Adam
31901e3c07 Merge branch 'obsd-master'
Conflicts:
	server-fn.c
2017-10-20 12:36:29 +01:00
Nicholas Marriott
a34de2e378 Save and restore LIBS when checking for b64_ntop, reported by Ralf Friedl. 2017-10-17 10:35:35 +01:00
nicm
2f6935a630 Infrastructure for drawing status lines of more than one line in height,
still only one is allowed but this lets tmux draw bigger ones.
2017-10-16 19:30:53 +00:00
nicm
a5fd5782f8 Show exit status and time in the remain-on-exit pane text, mostly from
Timo Boettcher in GitHub issue 1103.
2017-10-12 11:32:27 +00:00
Nicholas Marriott
fb02df66cc Merge branch 'master' of github.com:tmux/tmux 2017-10-12 11:56:32 +01:00
Nicholas Marriott
d10def5b0b Check missed during merge. 2017-10-12 11:56:06 +01:00
Thomas Adam
2357bfb254 Merge branch 'obsd-master' 2017-10-11 16:01:17 +01:00
Thomas Adam
87babfa473 Merge branch 'obsd-master' 2017-10-11 14:01:17 +01:00
nicm
eb9839fd32 Box around label in preview. 2017-10-11 12:57:49 +00:00
nicm
6e5121be7e Clear to end of line properly with UTF-8 present. 2017-10-11 11:26:58 +00:00
Thomas Adam
4efd41f3af Merge branch 'obsd-master' 2017-10-11 10:01:19 +01:00
nicm
99351c9cae Add C-n and C-p keys for tree mode, and choose the right initial line
when no panes.
2017-10-11 08:08:16 +00:00
Nicholas Marriott
60074a6bc6 Merge branch 'master' of github.com:tmux/tmux 2017-10-11 08:03:55 +01:00
Nicholas Marriott
a3967de9a5 Include headers if found regardless of forkpty. 2017-10-11 08:03:31 +01:00
Thomas Adam
044019d9d6 Merge branch 'obsd-master' 2017-10-09 14:01:16 +01:00
nicm
db44151a37 kind should be S-Down not S-Up. 2017-10-09 11:35:35 +00:00
Thomas Adam
ceab7154d4 Merge branch 'obsd-master' 2017-10-08 18:40:41 +01:00
nicm
0b4c408168 Fix description of history_size, from Campbell Barton. 2017-10-08 16:45:01 +00:00
Thomas Adam
f069c0ba09 Merge branch 'obsd-master' 2017-10-06 20:01:17 +01:00
nicm
9c4caf49a2 Support %else in config files to match %if, from Brad Town in GitHub
issue 1071.
2017-10-06 18:02:30 +00:00
Thomas Adam
2be01ab4ec Merge branch 'obsd-master' 2017-10-06 13:33:32 +01:00
nicm
b462063cd5 Add -- to some key bindings so leading -s work. 2017-10-05 13:43:34 +00:00
Nicholas Marriott
8aaf86a6ea Merge branch '2.6-rc' 2017-10-05 14:39:33 +01:00
Nicholas Marriott
bd71cbbe27 2.6. 2017-10-05 14:31:23 +01:00
nicm
88517ceebb Add support for the xterm(1) title stack, from Brad Town, GitHub issue
1075.
2017-10-05 13:29:18 +00:00
nicm
6a292f09ba When writing batches of characters to the screen, we need to clear
padding or later UTF-8 characters could be displayed incorrectly. GitHub
issue 1090.
2017-10-05 08:12:24 +00:00
nicm
71ec616e4d Initialize alerts timer event where it is used, avoids crash with new windows. 2017-09-22 17:58:30 +01:00
Thomas Adam
ff526e43de Merge branch 'obsd-master' 2017-09-22 12:01:13 +01:00
nicm
d563aa7c7b Initialize alerts timer event where it is used, avoids crash with new windows. 2017-09-22 09:04:46 +00:00
Thomas Adam
ae5a62a514 Merge branch 'obsd-master' 2017-09-13 10:01:10 +01:00
nicm
c86d83f835 Remove unused (always 1) arguments from some functions, from Daniel
Mueller in GitHub issue 1073.
2017-09-13 07:31:07 +00:00
Thomas Adam
9a1b9f15a1 Merge branch 'obsd-master' 2017-09-11 22:01:10 +01:00
nicm
af2c7ce646 Check event is initialized before delete; fixes crash reported by
Michael Nickerson in GitHub issue 1068.
2017-09-11 20:11:45 +00:00
Nicholas Marriott
b541a97821 2.6-rc3. 2017-09-11 10:12:25 +01:00
Nicholas Marriott
a8b84b7cfa 2.6-rc3. 2017-09-11 10:08:28 +01:00
Nicholas Marriott
495e2ed17f Merge branch 'master' into 2.6-rc 2017-09-11 10:08:15 +01:00
Thomas Adam
d8c397d1b7 Merge branch 'obsd-master' 2017-09-11 10:01:11 +01:00
nicm
d8d6c2746e Mention that filter is a format. 2017-09-11 06:53:06 +00:00
nicm
6fdaaa0637 Do not free more lines than are available in the history. 2017-09-11 06:40:46 +00:00
Nicholas Marriott
034b19b734 2.6-rc2. 2017-09-10 16:08:22 +01:00
Nicholas Marriott
cb8eba1530 Merge branch 'master' into 2.6-rc 2017-09-10 16:07:44 +01:00
Thomas Adam
7aa8b8a25c Merge branch 'obsd-master' 2017-09-10 16:01:14 +01:00
Nicholas Marriott
abcbfcb0e8 Merge branch 'master' into 2.6-rc 2017-09-10 15:38:02 +01:00
nicm
70bc07a358 Previously, extended cell data was never reduced in size even when the
cell was overwritten. With a large history this can be a substantial
amount of memory. To reduce this, compact each extended cell list to
only cells in use as it is scrolled off the visible screen into the
history. From Dan Aloni in GitHub issue 1062.
2017-09-10 14:36:12 +00:00
Thomas Adam
7f83b53027 Merge branch 'obsd-master'
Conflicts:
	server-client.c
2017-09-10 11:39:45 +01:00
nicm
8405fcdd9b Apply timeout to CAN and RS which also wait for ST. 2017-09-10 08:01:23 +00:00
nicm
f56f09ea38 Fix a few errors in how the selected line is chosen after resize,
reported by Felix Rosencrantz in GitHub issue 1059.
2017-09-08 16:28:41 +00:00
Nicholas Marriott
c62cfe64c8 Add to CHANGES. 2017-09-08 14:22:34 +01:00
nicm
78cf3c14ca When removing a key table clear it out of clients, fixes issue with
unbind -a reported by Thomas Sattler.
2017-09-08 08:45:27 +00:00
nicm
89e057dc4a Do not fail if unset an option that is already unset, reported by Thomas
Sattler.
2017-09-07 13:18:44 +00:00
nicm
466066c3a1 Do not attempt to use TIOCSWINSZ on a -1 file descriptor (possible if
the pane has already died).
2017-09-06 07:12:41 +00:00
Thomas Adam
ff3d05d92f Merge branch 'obsd-master' 2017-09-04 12:01:11 +01:00
nicm
eadd79acec Move to current mouse position not last when clcking in copy mode; fixes
GitHub issue 1055. Also a man page fix from jmc.
2017-09-04 09:18:51 +00:00
Thomas Adam
d019821281 Merge branch 'obsd-master' 2017-09-02 20:01:18 +01:00
nicm
f4848b437f Add selectp -T to set pane title. 2017-09-02 17:51:54 +00:00
Nicholas Marriott
e941e532fa Mention GitHub for code. 2017-08-30 21:49:31 +01:00
Nicholas Marriott
a1986c5973 Add to CHANGES. 2017-08-30 21:24:16 +01:00
Nicholas Marriott
6e2b3f435a Add to CHANGES. 2017-08-30 21:23:26 +01:00
Nicholas Marriott
07d3c4d882 Merge branch 'master' into 2.6-rc 2017-08-30 20:04:37 +01:00
Thomas Adam
f81e87f1e2 Merge branch 'obsd-master' 2017-08-30 20:01:11 +01:00
nicm
6abfd9b8ff Instead of overloading the line clear function to mean free if
background is default (8), introduce an explicit free function and use
it where a free alone is needed. Likewise, use memmove directly rather
than grid_move_lines where it makes sense. Based on a memory leak fix by
Dan Aloni in GitHub issue 1051.
2017-08-30 18:13:47 +00:00
Nicholas Marriott
07c679b52d Merge branch 'master' into 2.6-rc 2017-08-30 12:04:09 +01:00
Nicholas Marriott
b4c633cc40 Merge branch 'master' of github.com:tmux/tmux 2017-08-30 12:03:59 +01:00
Thomas Adam
54c5070767 Merge branch 'obsd-master' 2017-08-30 12:01:10 +01:00
nicm
17cf1b21c6 Pass flags into cmd_find_from_* to fix prefer-unattached, reported by
Thomas Sattler.
2017-08-30 10:33:57 +00:00
Nicholas Marriott
8f364053ca Add to TODO. 2017-08-30 11:21:20 +01:00
Nicholas Marriott
2e4e521629 2.6-rc version. 2017-08-30 09:34:27 +01:00
Nicholas Marriott
fa20f19494 Fix position of -v, pointed out by Thomas Sattler. 2017-08-30 09:33:53 +01:00
Nicholas Marriott
c1d8b0f74e Back to master. 2017-08-29 22:19:46 +01:00
Nicholas Marriott
3815e4f05e This is not true now... 2017-08-29 22:19:27 +01:00
Nicholas Marriott
72488b526b Merge branch 'master' into 2.6-rc 2017-08-29 22:06:22 +01:00
Nicholas Marriott
5fec6c598e Merge branch 'master' of github.com:tmux/tmux 2017-08-29 22:06:06 +01:00
Thomas Adam
dee6bb5a31 Merge branch 'obsd-master' 2017-08-29 22:01:11 +01:00
Nicholas Marriott
566b9623b3 Merge branch 'master' into 2.6-rc 2017-08-29 21:42:15 +01:00
Nicholas Marriott
3f3fb43850 More style. 2017-08-29 21:42:05 +01:00
Nicholas Marriott
2248b886fe 2.6-rc version. 2017-08-29 21:37:51 +01:00
Nicholas Marriott
82b30f2322 Style of headings. 2017-08-29 21:34:56 +01:00
Nicholas Marriott
6b841a036a Fix example from Adam Spiers. 2017-08-29 21:32:09 +01:00
nicm
a7d1ee5433 Redraw rectangle selections properly when cursor at end, GitHub issue 992. 2017-08-29 20:26:25 +00:00
Thomas Adam
0f7160eb2f Merge branch 'obsd-master' 2017-08-29 12:01:25 +01:00
Nicholas Marriott
91d6bff8b8 Merge branch 'master' of github.com:tmux/tmux 2017-08-29 11:13:54 +01:00
Nicholas Marriott
5cdccf78a1 Update CHANGES. 2017-08-29 11:13:35 +01:00
nicm
5fc0be5045 Support REP escape sequence (\033[b). 2017-08-29 09:28:45 +00:00
nicm
9852bd743c Check for complete keys before escape prefix, allows keys to be defined
with a leading escape. GitHub issue 1048.
2017-08-29 09:18:48 +00:00
Thomas Adam
7d3bf6453e Merge branch 'obsd-master' 2017-08-28 14:01:17 +01:00
nicm
fe4467ad2b Do not forbid targets to specify non-visible panes - the checks for
visibility are better where the target is used. GitHub issue 1049.
2017-08-28 12:36:38 +00:00
Thomas Adam
b2322b3893 Merge branch 'obsd-master' 2017-08-27 11:48:44 +01:00
nicm
fccfc4e4be Do not allow the current line of screen when the preview is toggled,
from Thomas Adam.
2017-08-27 09:08:36 +00:00
Thomas Adam
e65cc09276 Merge branch 'obsd-master' 2017-08-27 10:01:15 +01:00
nicm
25cf126de8 Use kind and kri for S-Up/Down as well as kUP and kDN. 2017-08-27 08:33:55 +00:00
Thomas Adam
1492c9d7d9 Merge branch 'obsd-master' 2017-08-24 12:01:10 +01:00
nicm
3c63ad4a9c When tty is error or closed, remove client. Reported by Thomas Sattler. 2017-08-24 08:48:37 +00:00
Thomas Adam
3b40f8e42c Merge branch 'obsd-master' 2017-08-23 12:01:13 +01:00
nicm
08b125194e Key (v) and flag (-N) to toggle preview in choose modes. 2017-08-23 09:39:11 +00:00
nicm
1d60dd5872 Fix searching when match is at end of line, from Brad Town. 2017-08-23 09:18:22 +00:00
nicm
f0ce29c341 Allow multiple bells even if there is an existing bell (but not activity
or silence), from Brad Town.
2017-08-23 09:16:39 +00:00
nicm
e1b3dc89d2 Run alert hooks based on the options rather than unconditionally, from
Brad Town.
2017-08-23 09:14:21 +00:00
Nicholas Marriott
0f708dd6e2 Add to TODO. 2017-08-22 13:02:20 +01:00
Thomas Adam
730312e60f Merge branch 'obsd-master' 2017-08-22 00:01:10 +01:00
nicm
bbe9da063e Same as previous for \r alone. 2017-08-21 21:02:58 +00:00
nicm
7ec2a2b9ce Do not emit \r\n to move to column 0 if there are margins, because it
will instead move to the margin left.
2017-08-21 21:01:21 +00:00
Thomas Adam
ccdc369025 Merge branch 'obsd-master' 2017-08-20 00:01:22 +01:00
nicm
768740ae98 Fix example for user-keys. 2017-08-19 20:40:16 +00:00
Thomas Adam
07a13697e1 Merge branch 'obsd-master' 2017-08-17 12:01:17 +01:00
nicm
8daa1d5f54 Add monitor-bell window option to match the activity and silence
options, from Brad Town.
2017-08-17 08:37:38 +00:00
Nicholas Marriott
de86bf1856 Add to CHANGES. 2017-08-16 16:23:58 +01:00
Thomas Adam
2103a09430 Merge branch 'obsd-master' 2017-08-16 14:01:15 +01:00
nicm
c6a8ad23a1 Add -d flag to display-panes to specify timeout, and make 0 mean no
timeout. From Laurens Post.
2017-08-16 12:12:54 +00:00
nicm
c1ec28a34b Rename BELL_* values to ALERT_* now they are used by more than bells,
based on a diff from Brad Town.
2017-08-16 11:46:08 +00:00
Thomas Adam
0824850bbc Merge branch 'obsd-master' 2017-08-09 16:01:10 +01:00
Thomas Adam
27c3852103 Merge branch 'obsd-master'
Conflicts:
	tmux.1
2017-08-09 15:07:18 +01:00
nicm
ac2ba0961b Fix filtering so it works after the change to only show windows if they
have multiple panes.
2017-08-09 13:44:36 +00:00
Nicholas Marriott
237b7a50f4 Update CHANGES and TODO. 2017-08-09 12:48:54 +01:00
nicm
5dd5543fe4 Add -F to choose-tree, choose-client, choose-buffer to specify the
format of each line, as well as adding a couple of formats needed for
the default display.
2017-08-09 11:43:45 +00:00
Thomas Adam
4bb5bb9450 Merge branch 'obsd-master' 2017-08-08 12:01:15 +01:00
nicm
31b06571aa Hooks for after-select-pane and after-select-window. 2017-08-08 09:21:20 +00:00
Thomas Adam
e7b1e05bbd Merge branch 'obsd-master' 2017-08-02 14:01:10 +01:00
nicm
6f9b9655d7 Add selection_present format so commands in copy mode can use it, GitHub
issue 1028.
2017-08-02 11:10:48 +00:00
Nicholas Marriott
45ee118b26 Merge branch 'master' of github.com:tmux/tmux 2017-07-28 15:14:35 +01:00
Nicholas Marriott
0d6fc7eb1e I already mentioned these... revert previous. 2017-07-28 15:14:01 +01:00
Thomas Adam
ed8ddf2449 Merge branch 'obsd-master' 2017-07-28 14:01:13 +01:00
nicm
b4c9f6edba Show pane title in window list for windows with only one pane. 2017-07-28 10:59:58 +00:00
Nicholas Marriott
a704f57971 This is a big meaningless. 2017-07-27 23:25:39 +01:00
Nicholas Marriott
6b60a5c6d6 Update CHANGES. 2017-07-27 23:22:54 +01:00
Thomas Adam
147740ed40 Merge branch 'obsd-master' 2017-07-27 14:01:13 +01:00
nicm
3df7c91f1a Add pane_at_left/right/top/bottom formats, from Amos Bird. 2017-07-27 10:42:05 +00:00
Thomas Adam
58744de3eb Merge branch 'obsd-master' 2017-07-26 18:01:16 +01:00
nicm
b1bd0c7fc1 Always reset the alerts timer so it works even if activity and silence
are enabled on the same window.
2017-07-26 16:16:25 +00:00
nicm
76887b1d27 Make bell, activity and silence alerting more consistent:
- remove the bell-on-alert option;

- add activity-action and silence-action options with the same possible
  values as the existing bell-action;

- add "both" value for the visual-bell, visual-activity and
  visual-silence options to trigger both a bell and a message.

This means all three work the same way. Based on changes from Yvain Thonnart.
2017-07-26 16:14:08 +00:00
Nicholas Marriott
06a2644ab2 Update CHANGES. 2017-07-26 11:25:33 +01:00
Nicholas Marriott
ef9afddd1a Merge branch 'master' of github.com:tmux/tmux 2017-07-26 08:41:45 +01:00
Nicholas Marriott
3065b21375 Mention autoconf and automake. 2017-07-26 08:38:37 +01:00
Thomas Adam
358df10191 Merge branch 'obsd-master' 2017-07-22 02:01:13 +01:00
nicm
3bb426d92c Use the actual width written rather than the possible width to clear. 2017-07-21 22:55:45 +00:00
Thomas Adam
26db50d6df Merge branch 'obsd-master' 2017-07-21 16:01:13 +01:00
nicm
8c6ad55320 Trim trailing spaces from full line when it is clearly OK to do so. 2017-07-21 14:25:29 +00:00
nicm
e0d49ad758 Allow ispunct() as well as isalnum() when parsing initial window names. 2017-07-21 12:58:02 +00:00
Thomas Adam
e725b96a59 Merge branch 'obsd-master' 2017-07-21 12:01:16 +01:00
nicm
11e2af6df7 Add -c for respawn-pane and respawn-window, from J Raynor. 2017-07-21 09:17:19 +00:00
Thomas Adam
acbbc93501 Merge branch 'obsd-master' 2017-07-14 22:01:10 +01:00
nicm
932f6cfbfc Because ignore SIGCHLD early, letting signal_del restore it doesn't work
correctly, so set it explicitly back to default (and the others for good
measure).
2017-07-14 18:49:07 +00:00
Thomas Adam
1265e212e4 Merge branch 'obsd-master' 2017-07-14 10:01:11 +01:00
Nicholas Marriott
e4cd8751a2 Update CHANGES. 2017-07-14 09:14:23 +01:00
nicm
2678fe53f5 Fix redraw defer code in the presence of multiple clients - the timer
may be needed for all of them, so don't delete it on the first; and
don't skip setting the redraw flag if the timer is already running.

Reported by Pol Van Aubel in GitHub issue 1003.
2017-07-14 08:04:23 +00:00
Thomas Adam
e3698e6e1f Merge branch 'obsd-master' 2017-07-12 16:01:11 +01:00
nicm
8b84fc177c Line up keys in tree mode, and don't expand windows with one pane. From
Thomas Adam.
2017-07-12 14:31:06 +00:00
Thomas Adam
5122f3477f Merge branch 'obsd-master' 2017-07-12 14:01:13 +01:00
Thomas Adam
1076a2e26c Merge branch 'obsd-master'
Conflicts:
	cmd-pipe-pane.c
	proc.c
	tmux.c
	window.c
2017-07-12 13:43:08 +01:00
nicm
fba6140a4a Do not need to set up USR2 twice. 2017-07-12 12:35:31 +00:00
nicm
51112221ee Block signals between forking and clearing signal handlers (or calling
event_reinit) - if the child gets a signal and fires the libevent signal
handler during this period it could write a signal into the parent's
signal pipe. GitHub issue 1001 from Aaron van Geffen.
2017-07-12 10:04:51 +00:00
nicm
0453ad0146 Move signal code into proc.c. 2017-07-12 09:24:17 +00:00
nicm
ed3cfaafb2 Make shell_command a global like other stuff rather than making it an
exception and using callback argument.
2017-07-12 09:21:25 +00:00
nicm
d0d42dc4cb proc_send_s now seems unnecessary. 2017-07-12 09:07:52 +00:00
Thomas Adam
fbbf5a108b Merge branch 'obsd-master' 2017-07-10 00:01:15 +01:00
nicm
58b796608f Some extra logging to show why tmux might exit. 2017-07-09 22:33:09 +00:00
Thomas Adam
05062e7d2d Merge branch 'obsd-master' 2017-07-07 18:01:15 +01:00
nicm
bfaa885f10 Fix size of rightmost preview section. 2017-07-07 16:27:26 +00:00
nicm
9913cce3ba Add a pane_pipe format to show if pipe-pane is active, GitHub issue 990. 2017-07-07 14:39:45 +00:00
Thomas Adam
1029f2b277 Merge branch 'obsd-master' 2017-07-07 10:01:09 +01:00
nicm
1f7ca973c5 When working out the current client (for example for switch-client with
no target), prefer clients attached to the current session if there is
one. GitHub issue 995 from Jan Larres.
2017-07-07 07:13:14 +00:00
Thomas Adam
6b1ceca86a Merge branch 'obsd-master' 2017-07-05 00:01:10 +01:00
nicm
53d4ed22e8 < and > keys to scroll preview list left and right in tree mode. 2017-07-04 22:21:31 +00:00
Thomas Adam
feb044bd2d Merge branch 'obsd-master' 2017-07-04 14:01:15 +01:00
nicm
bedf8bd437 Handle 0 size of preview box in caller. 2017-07-04 12:26:14 +00:00
Thomas Adam
6cb4a3bb19 Merge branch 'obsd-master' 2017-07-04 02:01:13 +01:00
nicm
4039802fce Change session and window preview so that the current window or pane is
always shown.
2017-07-03 22:48:02 +00:00
Thomas Adam
5e98770936 Merge branch 'obsd-master' 2017-07-03 16:01:14 +01:00
nicm
6ee0afb579 Change previous to not wait for both process exit and pty close -
instead if there is a pipe-pane active, do not exit until all data is
read (including any libevent hasn't seen yet). Fixes problem reported by
Theo Buehler and still seems to solve the original issue.
2017-07-03 12:38:50 +00:00
Thomas Adam
4e01036cb6 Merge branch 'obsd-master' 2017-07-03 10:01:14 +01:00
nicm
28687f2d55 Do not close panes until process has exited and any outstanding data
has been written to the pipe-pane event if there is one. GitHub issue 991.
2017-07-03 08:16:03 +00:00
nicm
42285ac989 Try C.UTF-8 which is also a commonly useful locale on some platforms,
from Romain Francoise.
2017-07-03 08:08:30 +00:00
Thomas Adam
6fba9a39b7 Merge branch 'obsd-master' 2017-07-01 00:01:21 +01:00
nicm
fa677fc0e1 Don't write over right border. 2017-06-30 22:37:35 +00:00
nicm
b565644c81 Fix previous when we end up able to show no panes. 2017-06-30 22:36:11 +00:00
nicm
7247553c77 Try to show a better preview of sessions and windows in tree mode. 2017-06-30 22:24:08 +00:00
Thomas Adam
f059fe3ef2 Merge branch 'obsd-master' 2017-06-30 00:01:14 +01:00
nicm
8b0fd63ddb Use 100 as the example for command-alias because the defaults are from 0
to (currently) 5.
2017-06-29 22:02:19 +00:00
Thomas Adam
336beeb09a Merge branch 'obsd-master' 2017-06-28 14:01:13 +01:00
nicm
a00b0d13ed Apply the xterm key flag when needed for send-keys, fixes problem
reported by Franky Spamschleuder.
2017-06-28 11:36:39 +00:00
Thomas Adam
1ca920bbeb Merge branch 'obsd-master' 2017-06-28 10:01:16 +01:00
nicm
1e376be13d Fix visual-silence (check accidentally the wrong way round), from Brad
Town. Plus some tmux.1 fixes from jmc@.
2017-06-28 06:45:31 +00:00
Thomas Adam
6995497e5b Merge branch 'obsd-master' 2017-06-23 18:01:11 +01:00
nicm
95ed7d48c8 Add user-keys option to allow user-defined keys to be set, from Dan
Aloni.
2017-06-23 15:36:52 +00:00
Thomas Adam
a61200776d Merge branch 'obsd-master' 2017-06-16 18:01:13 +01:00
nicm
a67df17763 Tweak some logging. 2017-06-16 15:12:38 +00:00
Thomas Adam
233bae6992 Merge branch 'obsd-master' 2017-06-16 14:01:14 +01:00
nicm
d685604d04 Log terminal capabilities for each new terminal. 2017-06-16 11:50:06 +00:00
Thomas Adam
91dec25fc9 Merge branch 'obsd-master' 2017-06-14 10:01:10 +01:00
nicm
af93453190 Don't overwrite error message when it is available in
cmd_string_parse. Reported by Jimi Damon in GitHub issue 975.
2017-06-14 07:42:41 +00:00
Nicholas Marriott
6e57401610 New test. 2017-06-14 08:37:58 +01:00
nicm
dec00d3579 Add missing error message when no target, GitHub issue 971. 2017-06-14 07:37:17 +00:00
Thomas Adam
154c95d0c9 Merge branch 'obsd-master' 2017-06-13 13:48:37 +01:00
nicm
ac7080b31b Remove xterm flag from key before checking prefix, reported by Peter
Fern in GitHub issue 974.
2017-06-13 07:12:33 +00:00
Thomas Adam
a073d11c3e Merge branch 'obsd-master' 2017-06-12 14:01:14 +01:00
nicm
e028ab3476 Need to flush out the linefeed after wrapper. GitHub issue 970. 2017-06-12 10:57:35 +00:00
Thomas Adam
5362f956f0 Merge branch 'obsd-master' 2017-06-12 10:01:15 +01:00
nicm
8037159f93 Add explicit keys for the bracketed paste sequences, both to avoid mix
ups with other keys and to make logs clearer.
2017-06-12 07:04:24 +00:00
Thomas Adam
4dbab75855 Merge branch 'obsd-master' 2017-06-09 18:01:14 +01:00
nicm
adcd5aff6f Extend filters (f key) to buffer and client mode and add -f flag to
specify to command.
2017-06-09 16:01:39 +00:00
nicm
bab4da5133 Add -O option to choose-* to set initial sort order. 2017-06-09 15:29:15 +00:00
nicm
3ec28ceb9b Default sort for buffer mode should be time not name. 2017-06-09 15:17:20 +00:00
Thomas Adam
ed45052d6d Merge branch 'obsd-master' 2017-06-09 16:01:13 +01:00
Nicholas Marriott
411640c032 Merge branch 'master' of github.com:tmux/tmux 2017-06-09 15:57:13 +01:00
Nicholas Marriott
eea93638c6 Set AM_CFLAGS for ncurses libraries, reported by Peter Schow. 2017-06-09 15:56:50 +01:00
nicm
a2ca51c27a Use brackets around prompts which looks better and matches the other modes. 2017-06-09 14:00:46 +00:00
Thomas Adam
e640907d24 Merge branch 'obsd-master' 2017-06-09 12:01:17 +01:00
nicm
74b2deae1c Add a hook when the clipboard is set. 2017-06-09 09:21:24 +00:00
Nicholas Marriott
143ccd27b4 Add memmem to compat. 2017-06-09 08:53:58 +01:00
Nicholas Marriott
a4d2fa1b6d Update TODO. 2017-06-08 17:21:30 +01:00
Nicholas Marriott
065c360730 Typo. 2017-06-08 14:08:04 +01:00
Nicholas Marriott
738d9aece7 Note what to have for building Git. 2017-06-08 13:40:24 +01:00
Nicholas Marriott
8c38409aef Merge branch 'master' of github.com:tmux/tmux 2017-06-08 13:29:59 +01:00
Nicholas Marriott
61ed6425bd Move FAQ online and do not ship TODO. 2017-06-08 13:29:36 +01:00
Thomas Adam
6e8c93afdd Merge branch 'obsd-master' 2017-06-08 10:01:10 +01:00
nicm
8c4ae1c938 Add size to client descriptions in list, suggested by Greg Hurrell. 2017-06-08 07:48:04 +00:00
Thomas Adam
4aa02c3743 Merge branch 'obsd-master' 2017-06-07 18:01:13 +01:00
nicm
356fab7bcb Return 1 if name matches not 0, also fix some spaces. 2017-06-07 15:27:46 +00:00
Nicholas Marriott
9543f076fd Use osdep_get_name. 2017-06-07 16:21:01 +01:00
Thomas Adam
86d6666fe7 Merge branch 'obsd-master' 2017-06-07 16:01:10 +01:00
nicm
405cc337f3 Add simple searching (C-s and n) to the various choose modes: by name
for client and tree, and by name and content for buffer.
2017-06-07 14:37:30 +00:00
Nicholas Marriott
772dacc89b Tweak title. 2017-06-07 11:27:04 +01:00
Nicholas Marriott
696d2889f4 Mention U8, from Carles Cufi. 2017-06-07 11:19:04 +01:00
Nicholas Marriott
9316b9b57a Typo. 2017-06-07 11:15:36 +01:00
Nicholas Marriott
fb288ef9a7 Remove a bunch of out-of-date stuff from the FAQ or stuff that is documentation
for other programs.
2017-06-07 11:13:05 +01:00
Thomas Adam
7077980055 Merge branch 'obsd-master' 2017-06-06 18:01:13 +01:00
nicm
50b27c8c0d Continue and pass keys through if they are repeated keys, so that the
first key after a repeated key doesn't get lost.
2017-06-06 15:49:35 +00:00
nicm
bbc35b0b19 Do not pass a state into commands when fired on individual items in tree
mode, rely on the %% target substitution in the command for the chosen
pane and leave the default target as the current pane (where the mode
is). Otherwise, joinp and similar end up with -t and -s the
same. Reported by Jacob Niehus in GitHub issue 960.
2017-06-06 15:07:35 +00:00
nicm
d7280917da Delete input event when evbuffer_read() fails to avoid just spinning
around a dead file descriptor. Seems to fix a problem reported by Greg
Hurrell in GitHub issue 941.
2017-06-06 14:53:28 +00:00
Nicholas Marriott
78352fdd32 Add a small dance to daemon() to reattach tmux to the user's namespace (which
allows access to the clipboard) on OS X 10.10 and above.

Chis Johnsen has done much work on and documentation of this issue, the code is
copied (with some tweaks) from his reattach-to-user-namespace at:

    https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard

Tested by Enrico Ghirardi.

Will see how this goes, if it breaks stuff it might go away again.
2017-06-06 07:59:53 +01:00
Nicholas Marriott
63f8a2cb89 Merge branch 'master' of github.com:tmux/tmux 2017-06-05 12:02:10 +01:00
Nicholas Marriott
e1686c26dd Update CHANGES. 2017-06-05 12:01:58 +01:00
Thomas Adam
a999f6f876 Linux build fixes
Linux doesn't have vis.h
2017-06-05 12:00:52 +01:00
Thomas Adam
e62e17d046 Merge branch 'obsd-master'
Conflicts:
	tmux.1
	window.c
2017-06-05 11:59:38 +01:00
nicm
2f04108f3a Do not leak command, from David CARLIER. 2017-06-04 15:36:33 +00:00
Nicholas Marriott
1c83c0ebcd tparm() fix for Solaris. 2017-06-04 11:27:35 +01:00
Nicholas Marriott
8ec6c323b6 signal.h for utempter, from David CARLIER. 2017-06-04 11:23:48 +01:00
nicm
c5b7faaefc Add a timeout to prevent the sequences which wait for a specific
terminator (OSC, APC and DCS) waiting forever, which helps to avoid
garbage (cat /dev/random) locking up panes completely. This (and the
last commit) prompted by a discussion with theo.
2017-06-04 09:22:34 +00:00
nicm
467ece53e6 Remove unused variable. 2017-06-04 09:02:57 +00:00
nicm
8149bc3fa6 Be more strict about escape sequences that rename windows or set titles:
ignore any that not valid UTF-8 outright, and for good measure pass the
result through our UTF-8-aware vis(3).
2017-06-04 09:02:36 +00:00
nicm
adf5628087 Support SIGUSR2 to stop and start logging for an existing server. Also
we currently only have two log levels so just use -v and -vv rather than
-v and -vvvv, and clarify the man page entry for -v.
2017-06-04 08:25:57 +00:00
Nicholas Marriott
67cd496b39 Update CHANGES. 2017-06-04 09:09:31 +01:00
nicm
184039044a Typo/style; plus man page escaping from jmc. 2017-06-04 08:02:20 +00:00
Thomas Adam
757eb060cd Merge branch 'obsd-master' 2017-06-03 20:01:10 +01:00
nicm
3442066054 Make set-clipboard a three-state option so tmux itself can ignore the
sequencess.
2017-06-03 17:43:01 +00:00
Thomas Adam
80235d6fdd Merge branch 'obsd-master' 2017-06-03 10:01:10 +01:00
nicm
493a1846d0 Foreground colours with the bright attribute set need to use the bright
entries in the palette. GitHub issue 954.
2017-06-03 07:15:23 +00:00
Thomas Adam
73b9328c1f Merge branch 'obsd-master'
Conflicts:
	window-buffer.c
2017-06-01 18:29:36 +01:00
nicm
248aa54bfd Style and spacing nits. 2017-05-31 17:56:48 +00:00
nicm
70cc8f2c7e Shut up a warning. 2017-05-31 16:44:33 +00:00
Nicholas Marriott
92d86586b7 Update TODO. 2017-05-31 17:38:34 +01:00
Nicholas Marriott
a8e0363914 Add setrgbf setrgbb. 2017-05-31 17:22:43 +01:00
Nicholas Marriott
35008200bd Differences to OpenBSD. 2017-05-31 16:34:39 +01:00
Nicholas Marriott
113356c848 Build fixes. 2017-05-31 16:29:07 +01:00
nicm
b3d0ed4057 time.h here too. 2017-05-31 15:27:57 +00:00
nicm
61c0189bb1 Need time.h. 2017-05-31 15:26:41 +00:00
Thomas Adam
f17ecaa495 Merge branch 'obsd-master'
Conflicts:
	Makefile.am
	cfg.c
	server-client.c
2017-05-31 15:56:13 +01:00
Nicholas Marriott
9c4d0d454a Some changes that will appear when we sync up. 2017-05-31 13:56:07 +01:00
nicm
d60663ea86 Some applications like vi(1) and tmux until 10 minutes or so ago, do not
redraw on SIGWINCH if the size returns to the original size between the
original SIGWINCH and when they get around to calling TIOCGWINSZ. So use
the existing resize timer to introduce a small delay between the two
resizes.
2017-05-31 11:00:00 +00:00
nicm
ea6428a5d2 It is not OK to ignore SIGWINCH if SIOCGWINSZ reports the size has
unchanged, because it may have changed and changed back in the time
between us getting the signal and calling ioctl(). Always redraw when we
see SIGWINCH.
2017-05-31 10:29:15 +00:00
nicm
80c6b487dc Because we defer actually resizing applications (calling TIOCSWINSZ)
until the end of the server loop, tmux may have gone through several
internal resizes in between. This can be a problem if the final size is
the same as the initial size (what the application things it currently
is), because the application may choose not to redraw, assuming the
screen state is unchanged, when in fact tmux has thrown away parts of
the screen, assuming the application will redraw them.

To avoid this, do an extra resize if the new size is the same size as
the initial size. This should force the application to redraw when tmux
needs it to, while retaining the benefits of deferring (so we now resize
at most two times instead of at most one - and only two very rarely).

Fixes a problem with break-pane and zoomed panes reported by Michal
Mazurek.
2017-05-31 10:15:51 +00:00
nicm
7eb496c00c Look for setrgbf and setrgbb terminfo extensions for RGB colour. This is
the most reasonable of the various (some bizarre) suggestions for
capabilities.
2017-05-31 08:43:44 +00:00
nicm
aad4e4ddb1 Rewrite of choose mode, both to simplify and tidy the code and to add
some modern features.

Now the common code is in mode-tree.c, which provides an API used by the
three modes now separated into window-{buffer,client,tree}.c. Buffer
mode shows buffers, client mode clients and tree mode a tree of
sessions, windows and panes.

Each mode has a common set of key bindings plus a few that are specific
to the mode. Other changes are:

- each mode has a preview pane: for buffers this is the buffer content
  (very useful), for others it is a preview of the pane;

- items may be sorted in different ways ('O' key);

- multiple items may be tagged and an operation applied to all of them
  (for example, to delete multiple buffers at once);

- in tree mode a command may be run on the selected item (session,
  window, pane) or on tagged items (key ':');

- displayed items may be filtered in tree mode by using a format (this
  is used to implement find-window) (key 'f');

- the custom format (-F) for the display is no longer available;

- shortcut keys change from 0-9, a-z, A-Z which was always a bit weird
  with keys used for other uses to 0-9, M-a to M-z.

Now that the code is simpler, other improvements will come later.

Primary key bindings for each mode are documented under the commands in
the man page (choose-buffer, choose-client, choose-tree).

Parts written by Thomas Adam.
2017-05-30 21:44:59 +00:00
Thomas Adam
cea83c0e1f Merge branch 'obsd-master' 2017-05-30 10:01:12 +01:00
nicm
bd39fcbeea Preserve search string when entering prompt again. 2017-05-30 08:13:48 +00:00
Thomas Adam
0d073907b5 Merge branch 'obsd-master' 2017-05-30 00:01:14 +01:00
Thomas Adam
5ee6dc2120 Merge branch 'obsd-master' 2017-05-29 22:01:15 +01:00
nicm
64552ae304 Add a flag to stop the prompt input being expanded. 2017-05-29 20:42:53 +00:00
nicm
b95e5827c1 Store a copy of the old status line, will be needed soon for new choose mode. 2017-05-29 20:41:29 +00:00
nicm
8a214b2f8e Function to count clients. 2017-05-29 20:37:30 +00:00
Thomas Adam
5bc5fe5e7e Merge branch 'obsd-master' 2017-05-29 20:01:12 +01:00
nicm
a2ace9da24 Add ||, && format operators and C: to search pane content. 2017-05-29 18:06:34 +00:00
Thomas Adam
d3959a2118 Merge branch 'obsd-master' 2017-05-29 18:01:14 +01:00
nicm
1257501499 Add m: for fnmatch(3) format matching. 2017-05-29 15:43:48 +00:00
Thomas Adam
bfd7209053 Merge branch 'obsd-master' 2017-05-29 10:01:15 +01:00
nicm
1883d299bf Do not factor in screen_hsize() for the visible copy mode screen when
adjusting the selection, it should never have any useful history (and
when it does, after resize, we shouldn't use it). From Michal Mazurek.
2017-05-29 07:58:33 +00:00
nicm
15253448af Tweak text to mention initial size, from John Hood. 2017-05-29 07:46:32 +00:00
Nicholas Marriott
b017dc7e32 Update release text. 2017-05-29 08:40:33 +01:00
Nicholas Marriott
b5a6458cde Merge branch '2.5-rc' 2017-05-29 08:23:03 +01:00
Nicholas Marriott
caa90735cf 2.5. 2017-05-29 08:12:25 +01:00
Nicholas Marriott
de45957c42 Add to CHANGES. 2017-05-29 08:11:47 +01:00
Thomas Adam
f4a42738af Merge branch 'obsd-master' 2017-05-29 02:01:15 +01:00
nicm
d5158620bb Support OSC 10 and 11 to set foreground and background colours, from
"bertnp" in GitHub issue 942.
2017-05-28 23:23:40 +00:00
Nicholas Marriott
bf5a196c78 Changes in master. 2017-05-28 22:10:17 +01:00
Thomas Adam
5d7dfefa36 Merge branch 'obsd-master' 2017-05-28 22:01:11 +01:00
nicm
dbc8cae18c Change so that sessions created detached (-d or no client) are always
80x24 and the status line is not applied until they attach. Also make -x
and -y work for control clients whether the session is detached or not.
2017-05-28 19:46:55 +00:00
Nicholas Marriott
1e1e0f1fbb Add test for -x and -y too. 2017-05-28 20:15:45 +01:00
nicm
385bf084a5 Also recalculate session sizes when refreh-client -C is used. GitHub
issue 947.
2017-05-28 19:00:52 +00:00
Nicholas Marriott
eb1f362687 Do not need /dev/null. 2017-05-28 19:53:08 +01:00
Nicholas Marriott
5386e6583d Add some tests. 2017-05-28 19:52:51 +01:00
Thomas Adam
d1497527c6 Merge branch 'obsd-master' 2017-05-17 18:01:14 +01:00
nicm
91d202da7e Tidy command prompt callbacks and pass in the client. 2017-05-17 15:20:23 +00:00
Nicholas Marriott
3888bf9d12 Need to check libutil for fparseln. 2017-05-17 12:48:42 +01:00
Thomas Adam
3df4e78492 Merge branch 'obsd-master' 2017-05-16 16:01:28 +01:00
Nicholas Marriott
b74b6dc77f Missed during merge. 2017-05-16 14:15:35 +01:00
nicm
31625c2d17 Line length and spaces to tabs. 2017-05-16 12:57:26 +00:00
Thomas Adam
dcdaf5c8b9 Merge branch 'obsd-master' 2017-05-15 20:01:14 +01:00
Thomas Adam
36181775cd Merge branch 'obsd-master' 2017-05-15 18:01:14 +01:00
nicm
1ba7f1d03f Check the terminfo(5) U8 capability and disable using UTF-8 for ACS if
it is present and zero. This is useful for users with terminals or fonts
that do not correctly support UTF-8 line drawing characters. GitHub
issue 927, reported by Hiroaki Yamazoe and Akinori Hattori.
2017-05-15 16:44:04 +00:00
nicm
b160de5cb4 Notify layout changed when choosing predefined layouts, from Joshua Brot. 2017-05-15 14:57:29 +00:00
Thomas Adam
7edaedf3a1 Merge branch 'obsd-master' 2017-05-15 10:01:16 +01:00
nicm
cb5fcb3d22 The Konsole SU bug means it can't clear the entire scroll region (it
ignores if >= size, not if > as I first thought). So we can't
effectively fix it in code - remove the workarounds which just cause
bugs on other terminals.
2017-05-15 07:54:44 +00:00
Thomas Adam
58f8421eac Merge branch 'obsd-master' 2017-05-13 10:01:16 +01:00
nicm
7a4c66b7f5 Scroll the right number of lines off the region when clearing. 2017-05-13 07:41:59 +00:00
nicm
d58c3793d6 Some other unused variables. 2017-05-13 07:30:50 +00:00
Nicholas Marriott
ea190d862a Merge branch '2.5-rc' 2017-05-13 08:20:01 +01:00
Nicholas Marriott
0f26739c9f 2.5-rc2. 2017-05-13 08:17:01 +01:00
Nicholas Marriott
ae2c5ad768 Reset updated flag when restarting job so new output is detected, reported by
Gregory Pakosz in GitHub issue 922.
2017-05-13 08:16:11 +01:00
Thomas Adam
9f9f8c8e76 Merge branch 'obsd-master' 2017-05-13 02:01:13 +01:00
nicm
50f1f1dce9 Compare >= for columns not >. 2017-05-12 23:10:19 +00:00
nicm
0264ef094a Can scroll away full lines to clear them too. 2017-05-12 23:06:43 +00:00
nicm
f688653710 Remove an unused variable. 2017-05-12 22:43:15 +00:00
Thomas Adam
886d896098 Merge branch 'obsd-master' 2017-05-12 18:01:14 +01:00
Nicholas Marriott
8331000764 Merge branch '2.5-rc' 2017-05-12 16:18:31 +01:00
nicm
0cd74723e1 When expanding a line in order to clear it, we need to use the default
background colour - there may be portions that we do not want to clear
with the new background colour.
2017-05-12 15:18:13 +00:00
Nicholas Marriott
2bff5e7867 ECH needs to use background colour. 2017-05-12 16:16:16 +01:00
nicm
90f2a417af Need to clear tty context before using it. 2017-05-12 16:04:13 +01:00
nicm
7c07f5f640 Cannot rely on cursor position after DL and IL (some terminals move to
column 0, some do not).
2017-05-12 16:03:49 +01:00
Thomas Adam
20e30593a5 Merge branch 'obsd-master' 2017-05-12 16:01:14 +01:00
nicm
e2a18e2b37 Need to store bg for ECH. 2017-05-12 14:56:56 +00:00
nicm
da724fe1c0 Cannot rely on cursor position after DL and IL (some terminals move to
column 0, some do not).
2017-05-12 14:13:54 +00:00
nicm
ffd8beb6f6 Need to clear tty context before using it. 2017-05-12 13:29:05 +00:00
nicm
5d3cf2ff15 Only redraw single client, and tweak some logging. 2017-05-12 13:27:57 +00:00
Thomas Adam
7f813dcb6a Merge branch 'obsd-master' 2017-05-12 14:01:17 +01:00
nicm
18bab30792 Scrolling needs to use background colour. 2017-05-12 13:00:56 +00:00
nicm
60f7b05c0c Regions can't be smaller than 2 so don't try to clear them by scrolling if so. 2017-05-12 11:19:24 +00:00
nicm
7f626c8959 Can use INDN to clear regions with default background colour if margins
are supported.
2017-05-12 11:13:43 +00:00
nicm
886d50dcab ECH needs to use background colour. 2017-05-12 10:50:11 +00:00
nicm
7d3e2c83d4 Store copy mode search string in pane so search-again command works even
if you exit and reenter copy mode (it doesn't remember the position,
just the search string), suggested by espie@.
2017-05-12 10:45:38 +00:00
Nicholas Marriott
1cdc4568bd Merge branch '2.5-rc' 2017-05-11 23:28:56 +01:00
nicm
69df38f8d8 Clear to start of screen needs to use background colour. 2017-05-11 23:28:44 +01:00
nicm
5e30b81825 Need to redraw out to cellsize (total cells used in a line) rather than
cellused (only non-space cells) because there may be cells with a
nondefault background.
2017-05-11 23:28:22 +01:00
Thomas Adam
99582befc4 Merge branch 'obsd-master' 2017-05-11 14:01:10 +01:00
nicm
c0d3f204b0 Clear to start of screen needs to use background colour. 2017-05-11 11:39:30 +00:00
nicm
989cdca95f Need to redraw out to cellsize (total cells used in a line) rather than
cellused (only non-space cells) because there may be cells with a
nondefault background.
2017-05-11 11:38:49 +00:00
Thomas Adam
def8f852e3 Merge branch 'obsd-master' 2017-05-11 10:01:10 +01:00
nicm
349cdd6110 Make environ_log prefix take a format. 2017-05-11 07:34:54 +00:00
nicm
c54a5b3690 Change how we resolve which pane is dragging when there are multiple
options - choose the largest pane, which is more likely to be the one the
user wants to resize. Prompted by a report from Thomas Sattler.
2017-05-11 07:24:42 +00:00
Thomas Adam
6d961d672d Merge branch 'obsd-master' 2017-05-10 22:01:13 +01:00
Thomas Adam
247ec2ad88 Merge branch 'obsd-master' 2017-05-10 20:01:17 +01:00
nicm
8ab2753521 Move to the right cursor position before using spaces to clear. 2017-05-10 18:40:13 +00:00
nicm
2dc9bfd93a Prevent control clients from affecting the session size until they have
specified a size with refresh-client -C. Prompted by a different change
with the same purpose from George Nachman.
2017-05-10 16:48:36 +00:00
nicm
9dc6946ebf We can use ECH to clear sections of lines, so use it for internal panes
(that don't touch an edge). Move all the tty clear code into two common
functions rather than having the same bunch of checks everywhere.
2017-05-10 16:47:03 +00:00
Thomas Adam
0868512bbc Merge branch 'obsd-master' 2017-05-10 16:01:10 +01:00
nicm
b519551153 Expand formats in option names and add -F flag to do so in option values as well. 2017-05-10 13:05:41 +00:00
Thomas Adam
f8b3f1622d Merge branch 'obsd-master' 2017-05-10 14:01:11 +01:00
nicm
0e3c5ebe1a Insert copy mode bindings at the right place in the command queue. 2017-05-10 10:46:59 +00:00
Nicholas Marriott
daef51e038 Typo. 2017-05-09 23:18:48 +01:00
Nicholas Marriott
e82c42661b Back to master. 2017-05-09 23:11:01 +01:00
Nicholas Marriott
3a47dec424 Fix test. 2017-05-09 23:01:10 +01:00
Nicholas Marriott
7b17618890 2.5-rc and changes. 2017-05-09 22:53:36 +01:00
Nicholas Marriott
71bc255e6f Merge branch 'master' of github.com:tmux/tmux 2017-05-09 22:34:15 +01:00
Nicholas Marriott
8f990c573c Update TODO. 2017-05-09 22:33:39 +01:00
Thomas Adam
3f1d6102f3 Merge branch 'obsd-master' 2017-05-09 20:01:10 +01:00
nicm
3712b41aba If the target pane for send-keys in in a mode with a key table (that is,
copy mode), then look the key up in the table and fire any command
instead of delivering the key to the pane directly where it will be
ignored. This makes C-b C-b (send-prefix) work in copy mode again.
2017-05-09 17:56:55 +00:00
Thomas Adam
4bcb64f8c1 Merge branch 'obsd-master' 2017-05-09 15:44:33 +01:00
Thomas Adam
a651b08a2f Merge branch 'obsd-master'
Conflicts:
	format.c
2017-05-09 15:44:13 +01:00
nicm
3b35daacf7 If the current screen was complex enough, it was possible to make redraw
itself hit the "terminal can't keep up" check. To avoid this, record how
much data we send during redraw (we know we will be starting with 0) and
skip the check until it has been flushed. GitHub issue 912.
2017-05-09 13:04:36 +00:00
nicm
18f36906a9 Set current pane in rotate-window. 2017-05-09 11:00:48 +00:00
nicm
5fee4638e0 Add a format for the name of the pane's mode, lets it be used as a
conditional for key bindings.
2017-05-07 22:27:57 +00:00
nicm
d52f579fd5 Up to now, tmux sees \033\033[OA as M-Up and since we turned on
xterm-keys by default, generates \033[1;3A instead of
\033\033[OA. Unfortunately this confuses vi, which doesn't understand
xterm keys and now sees Escape+Up pressed within escape-time as Escape
followed by A.

The issue doesn't happen in xterm itself because it gets the keys from X
and can distinguish between a genuine M-Up and Escape+Up.

Because xterm can, tmux can too: xterm will give us \033[1;3A (that is,
kUP3) for a real M-Up and \033\033OA for Escape+Up - in fact, we can be
sure any \033 preceding an xterm key is a real Escape key press because
Meta would be part of the xterm key instead of a separate \033.

So change tmux to recognise both sequences as M-Up for its own purposes,
but generate the xterm version of M-Up only if it originally received
the xterm version from the terminal.

This means we will return to sending \033\033OA instead of the xterm key
for terminals that do not support xterm keys themselves, but there is no
practical way around this because they do not allow us to distinguish
between Escape+Up and M-Up. xterm style escape sequences are now the de
facto standard for these keys in any case.

Problem reported by jsing@ and subsequently by Cecile Tonglet in GitHub
issue 907.
2017-05-07 21:25:59 +00:00
nicm
2fef10b9ac Add some formats to look at the session window stack, suggested by Scott
ROCHFORD.
2017-05-05 11:59:47 +00:00
Thomas Adam
f3221941f2 Merge branch 'obsd-master' 2017-05-04 10:01:12 +01:00
nicm
d98d316903 Some new notifications, mainly for active pane and current window and
session:

    pane-mode-changed
    window-pane-changed
    client-session-changed
    session-window-changed

From Joshua Brot.
2017-05-04 07:16:43 +00:00
Thomas Adam
97ecb4f9d8 Merge branch 'obsd-master' 2017-05-03 08:01:14 +01:00
nicm
ca6a121e63 Add a format for the last search string in copy mode and fix the prompt
so it can work when in -I, suggested by Suraj N Kurapati.
2017-05-03 05:53:34 +00:00
Thomas Adam
e354b0e40f Merge branch 'obsd-master' 2017-05-01 14:01:14 +01:00
nicm
0ccfb61bb0 In order that people can use formats like #D in #() in the status line
and not have to wait for an update when they change pane, we allow
commands to run more than once a second if the expanded form
changes. Unfortunately this can mean them being run far too often
(pretty much continually) when multiple clients exist, because some
formats (including #D) will always differ between clients.

To avoid this, give each client its own tree of jobs which means that
the same command will be different instances for each client - similar
to how we have the tag to separate commands for different panes.

GitHub issue 889; test case reported by Paul Johnson.
2017-05-01 12:20:55 +00:00
Nicholas Marriott
4b39120d22 .NOTPARALLEL. 2017-04-30 13:55:32 +01:00
Nicholas Marriott
76950a6401 Add regress/Makefile. 2017-04-30 13:47:25 +01:00
Nicholas Marriott
909d962d3a Make example match reality; Greg Hurrell. 2017-04-30 08:27:23 +01:00
Nicholas Marriott
dde53cfde1 Add to TODO. 2017-04-30 08:23:14 +01:00
Thomas Adam
0adb60b3a6 Merge branch 'obsd-master' 2017-04-30 00:01:17 +01:00
nicm
a2dd7daf4e Fix UTF-8 combining characters in column 0, based on a diff from Keith
Winstein.
2017-04-29 21:27:46 +00:00
Thomas Adam
3a8e56b282 Merge branch 'obsd-master' 2017-04-28 22:01:18 +01:00
Nicholas Marriott
36202a63e9 Merge branch 'master' of github.com:tmux/tmux 2017-04-28 20:22:31 +01:00
Nicholas Marriott
abad809e7a Test that kill-session closes the panes (processes end up dead). 2017-04-28 20:22:01 +01:00
nicm
0f2f783584 Log what is happening with window and session reference counts much more
obviously.
2017-04-28 19:13:55 +00:00
nicm
bcd6b41674 Remove a reference from the right window when removing from a winlink's
list.
2017-04-28 19:12:15 +00:00
nicm
92053cb492 Do not put the window on the alerts queue and add a reference unless the
alert is enabled and we are actually going to add the alerts event.
2017-04-28 19:10:48 +00:00
Thomas Adam
14cb489a3b Merge branch 'obsd-master' 2017-04-28 20:01:14 +01:00
nicm
54e2205e54 Konsole incorrectly ignores SU (CSI S) if the parameter is bigger than
the scroll region, so clamp it. Reported by Moritz Bunkus.
2017-04-28 17:58:44 +00:00
Thomas Adam
99b0f48b2e Merge branch 'obsd-master' 2017-04-28 16:01:12 +01:00
nicm
c12711affd Default for xterm-keys was wrong, stop documenting it. 2017-04-28 13:39:59 +00:00
Nicholas Marriott
e4b4125310 source-file too. 2017-04-27 13:14:14 +01:00
Nicholas Marriott
6b2d850e54 Tests for some new session and new window bits. 2017-04-27 13:09:08 +01:00
Thomas Adam
0daeefefdb Merge branch 'obsd-master' 2017-04-25 20:01:11 +01:00
nicm
d520dae6ac Make full width panes try to play more nicely with terminal copy and
paste by avoiding explicit line wraps if we think the terminal will wrap
anyway.
2017-04-25 18:30:29 +00:00
nicm
03d01eabb5 When we write out the grid including escape sequences, an SGR 0 needs to
cause the colours to be written again. Also treat colours separately
from attributes so that RGB colours will work.
2017-04-25 18:20:51 +00:00
Thomas Adam
65d6278f88 Merge branch 'obsd-master' 2017-04-25 18:01:11 +01:00
nicm
c48d09ec88 Do not update TERM into config file parsing has finished. 2017-04-25 15:35:10 +00:00
nicm
4a51a9d9d5 Block the initial client if there is one until the configuration file
has finished loading.
2017-04-25 14:46:23 +00:00
Nicholas Marriott
b938212563 Another test. 2017-04-25 15:40:10 +01:00
Nicholas Marriott
accaff8ac0 Remove stuff from TODO. 2017-04-25 14:31:05 +01:00
Nicholas Marriott
45965fb020 And another test. 2017-04-25 14:30:58 +01:00
Thomas Adam
6ac39d5cdb Merge branch 'obsd-master' 2017-04-25 14:01:16 +01:00
Nicholas Marriott
9794c03537 And another. 2017-04-25 13:50:44 +01:00
Nicholas Marriott
1b221a56ea Try to start writing test scripts. 2017-04-25 13:37:03 +01:00
nicm
eb6fd6ff80 if-shell doesn't need to queue its error message into a callback, and in
fact it can't do so because the item it was working with will have been
freed. Reported by Daniel Hahler.
2017-04-25 11:49:35 +00:00
Thomas Adam
9d041d8e6c Merge branch 'obsd-master' 2017-04-23 20:01:13 +01:00
nicm
5172014668 Only use ED for clear screen if at the bottom, same as earlier fix to
clear end of screen.
2017-04-23 18:13:24 +00:00
Thomas Adam
b853054e71 Merge branch 'obsd-master' 2017-04-22 16:01:19 +01:00
Thomas Adam
a6a294c8f8 Merge branch 'obsd-master' 2017-04-22 14:01:15 +01:00
nicm
1e0eb914d9 Memory leak from David CARLIER. 2017-04-22 12:55:06 +00:00
nicm
ae1a6c2fc5 Do not need getopt.h. 2017-04-22 12:08:41 +00:00
Thomas Adam
e802b683ea Merge branch 'obsd-master' 2017-04-22 12:01:19 +01:00
nicm
55cd4c7bc7 Can't collect UTF-8 characters of more than one byte at the moment. 2017-04-22 10:30:56 +00:00
nicm
a4eaac359a new -A should use the session name. 2017-04-22 10:26:44 +00:00
nicm
ee45a8a149 Get rid of the extra layer of flags and cmd_prepare() and just store the
CMD_FIND_* flags in the cmd_entry and call it for the command. Commands
with special requirements call it themselves and update the target for
hooks to use.
2017-04-22 10:22:39 +00:00
Thomas Adam
b08e451c91 Merge branch 'obsd-master' 2017-04-22 10:01:51 +01:00
nicm
2c0f826c36 Mouse bindings and hooks set up an initial current state when running a
command. This is used for the session, window and pane for all commands
in the command sequence if there is no -t or -s.

However, using it for all commands in the command sequence means that if
the active pane or current session is changed, subsequent commands still
use the previous state. So make commands which explicitly change the
current state (such as neww and selectp) update it themselves for later
commands. Commands which may invalidate the state (like killp) are
already OK because an invalid state will be ignored.

Also fill in the current state for all key bindings rather than just the
mouse, so that any omissions are easier to spot.
2017-04-22 08:56:24 +00:00
nicm
bcab77e266 We need to collect UTF-8 characters so that width != 1 characters are
correctly flushed.
2017-04-22 08:33:28 +00:00
Thomas Adam
d8398af770 Merge branch 'obsd-master' 2017-04-22 08:01:54 +01:00
nicm
30348edc7c Fix if-shell without a client (so in the config file). Reported by Theo
Buehler.
2017-04-22 06:27:15 +00:00
nicm
59ff9b8128 Typo in example. 2017-04-22 06:15:22 +00:00
nicm
2c9bdd9e32 Memory leaks, from David CARLIER. 2017-04-22 06:13:30 +00:00
Thomas Adam
21240c1a8f Merge branch 'obsd-master' 2017-04-22 00:01:11 +01:00
nicm
c8ecbf38ab Log error properly when no current state, and some other minor tweaks. 2017-04-21 22:23:24 +00:00
nicm
194a121ef6 Make sure cmd_find_from_* clear the state if they fail. 2017-04-21 22:00:06 +00:00
nicm
8867951144 Rename a variable. 2017-04-21 21:02:26 +00:00
Thomas Adam
fd13731049 Merge branch 'obsd-master' 2017-04-21 22:01:14 +01:00
nicm
c68ceca8cd Clear shared state if not filling it in. 2017-04-21 20:34:05 +00:00
nicm
efaf4c16cf Make the cmd_find_* functions more obvious when looking for a client,
rather than having it inside other functions. Should be no change to the
way targets are resolved just yet.
2017-04-21 20:26:34 +00:00
nicm
2ad09ab5af Key needs to be initialized to zero now it has flags in it. 2017-04-21 19:33:07 +00:00
Thomas Adam
1f209ed030 Merge branch 'obsd-master' 2017-04-21 20:01:18 +01:00
nicm
3c876235cc Style nits and an unused struct. 2017-04-21 18:18:17 +00:00
nicm
afa4e3ed9c Add cmd_find_from_winlink_pane and use it in a couple of places, and
make functions that can't fail void.
2017-04-21 17:22:20 +00:00
Thomas Adam
c376c5a817 Merge branch 'obsd-master' 2017-04-21 18:01:11 +01:00
nicm
92a77e7654 It is annoying that the copy mode key table (or any other key table)
will suppress root key table bindings. So change to always check the
root table if no binding is found in the current table (whether it be
the prefix table from pressing the prefix or the copy mode table from a
pane).

A root key binding can be blocked by binding the key to a command that
does nothing (like send-keys with no arguments).

Problem reported by Thomas Sattler.
2017-04-21 16:04:18 +00:00
Thomas Adam
4612419c14 Merge branch 'obsd-master' 2017-04-21 16:01:18 +01:00
nicm
c799425069 More unnecessary arguments now winlink points back to session. 2017-04-21 14:09:44 +00:00
nicm
428be9803c History needs to be loaded after config parsing is done - now that
commands are queued, that's in cfg_done not after start_cfg finishes.
2017-04-21 14:04:54 +00:00
nicm
bba588752f Store state shared between multiple commands in the queue in a shared
structure.
2017-04-21 14:01:19 +00:00
nicm
311dad8c28 Do not run the config file in the context of the first client, instead
use no client like we did before. This means commands like new-session
won't try to attach if they are in the config file.
2017-04-21 13:15:43 +00:00
Thomas Adam
93062ad099 Fix after merge 2017-04-21 09:29:22 +01:00
Thomas Adam
22e594fcea Merge branch 'obsd-master'
Conflicts:
	Makefile.am
	pty.c
2017-04-21 09:25:07 +01:00
Nicholas Marriott
02580ac134 Typo; Daniel Hahler. 2017-04-21 06:49:38 +01:00
Nicholas Marriott
b723f50e65 Do not need getopt.h for getopt, from Eric N Vander Weele. 2017-04-20 20:35:11 +01:00
Nicholas Marriott
4a2e75fc8c Merge branch 'master' of github.com:tmux/tmux 2017-04-20 19:09:36 +01:00
Nicholas Marriott
9420758127 getptmfd() and fdforkpty() compat. 2017-04-20 19:09:07 +01:00
nicm
87997efe8d Use fdforkpty() instead of our own unwrapped versions. 2017-04-20 17:49:26 +00:00
Thomas Adam
69e0f28333 Merge branch 'obsd-master' 2017-04-20 18:01:12 +01:00
nicm
51a0dbb172 Only set up a current target for mouse key bindings. Fixes:
bind q select-pane -U \; resize-pane -Z

(There is still some possible weirdness with the way we do current
targets, it should probably be done in a different way at some point.)
2017-04-20 15:16:20 +00:00
Nicholas Marriott
7934e7a6b5 Notes on target resolution. 2017-04-20 15:40:28 +01:00
Nicholas Marriott
aebbb15fe2 Turn on debug if $VERSION is master rather than commenting and uncommenting. 2017-04-20 12:06:39 +01:00
Thomas Adam
48371216df Merge branch 'obsd-master' 2017-04-20 12:01:14 +01:00
Nicholas Marriott
e30f9dc1fa Merge tag '2.4'
Version 2.4.
2017-04-20 11:59:07 +01:00
nicm
21993105e5 Now that struct winlink has a session pointer, can remove some arguments. 2017-04-20 09:43:45 +00:00
nicm
0f25ad3ca3 There is no real need for window_printable_flags to allocate, make it
return a buffer from the stack.
2017-04-20 09:39:07 +00:00
Nicholas Marriott
f9c7c50a93 Update TODO. 2017-04-20 10:20:42 +01:00
nicm
0b44ad99b5 If a #() command doesn't exit, use its most recent line of output (it
must be a full line). Don't let it redraw the status line more than once
a second.

Requested by someone about 10 years ago...
2017-04-20 09:20:22 +00:00
Nicholas Marriott
78d707dc83 Add to TODO. 2017-04-20 08:53:03 +01:00
Thomas Adam
3385159c94 Merge branch 'obsd-master' 2017-04-19 20:01:11 +01:00
nicm
f184c6f06c load_cfg returns < 0 on error, not != 0. Problem reported by Kaushal Modi. 2017-04-19 16:59:54 +00:00
Thomas Adam
5a551ac57f Merge branch 'obsd-master' 2017-04-19 16:01:14 +01:00
nicm
53fde21bb8 Add a suspend helper function, and do not allow detaching or suspending
while already doing so.
2017-04-19 14:00:28 +00:00
nicm
689f4bfac2 Style nits and a missing cast. 2017-04-19 12:44:29 +00:00
Thomas Adam
85af9c9c9d Merge branch 'obsd-master' 2017-04-19 10:01:12 +01:00
Nicholas Marriott
95c38087db Missed freezero. 2017-04-19 07:58:45 +01:00
nicm
fa6deb5866 When the data we have buffered to write to a terminal grows beyond a
reasonable amount (currently width * height * 8 bytes), discard all
output to the terminal and start trying to redraw periodically
instead. Continue with this until the amount of data we are trying to
write falls to a low level again.

This helps to prevent tmux sitting on a huge buffer of data when there
are processes with fast output running inside tmux but the outside
terminal is slow.

A new client_discarded format holds the amount of data that has been
discarded due to this mechanism.

The three variables (when to start this, when to stop, and how often to
redraw) are basically "works for me" at the moment, this is going in to
see how it goes and if it causes problems for anyone else.
2017-04-19 06:52:27 +00:00
Thomas Adam
a71c262d5f Merge branch 'obsd-master' 2017-04-19 00:01:15 +01:00
nicm
f731ae4a2d Revert use of DECSLRM on iTerm2, it doesn't help as much as we throught,
and there are some question marks about it's support.
2017-04-18 21:41:42 +00:00
nicm
8c8ce08d79 On terminals without DECSLRM, when a pane that is less than the full
with of the terminal scrolls, tmux needs to redraw the entire pane. This
results in a large amount of output data which can cause slow terminals
to struggle, particularly when many lines are scrolled together quickly.

This can be reduced by only redrawing when tmux doesn't hold any
buffered data for the terminal. If a redraw is required and data is
buffered, the redraw is deferred until all that data is consumed (it is
checked after every event loop, a timer is used to ensure this happens
at some point). While a redraw is pending, no additional data will be
written to the terminal.

The redraw still happens, now it is just pushed back if it is possible
it would just add more data on top of a terminal that is already
behind. This both gives the terminal a chance to catch up, and allows
tmux to process more scrolling (that would require additional redraws)
in the meantime.

Helps with a problem reported by Greg Hurrell.
2017-04-18 20:37:49 +00:00
Thomas Adam
de4f817bd6 Merge branch 'obsd-master' 2017-04-18 20:01:12 +01:00
nicm
623e35f594 Detect iTerm2 and use DECSLRM for it as well. 2017-04-18 18:21:37 +00:00
202 changed files with 26440 additions and 11928 deletions

71
.github/CONTRIBUTING.md vendored Normal file
View File

@@ -0,0 +1,71 @@
## What should I do before opening an issue?
Before opening an issue, please ensure that:
- `$TERM` inside tmux is screen, screen-256color, tmux or tmux-256color. Check
by running `echo $TERM` inside tmux.
- You can reproduce the problem with the latest tmux release, or a build from
Git master.
- Your question or issue is not covered in the manual (run man tmux).
- Nobody else has opened the same issue recently.
## What should I include in an issue?
Please include the output of:
~~~bash
uname -sp && tmux -V && echo $TERM
~~~
Also include:
- Your platform (Linux, OS X, or whatever).
- A brief description of the problem with steps to reproduce.
- A minimal tmux config, if you can't reproduce without a config.
- Your terminal, and `$TERM` inside and outside of tmux.
- Logs from tmux (see below).
- At most one or two screenshots, if helpful.
## How do I test without a .tmux.conf?
Run a separate tmux server with `-f/dev/null` to skip loading `.tmux.conf`:
~~~bash
tmux -Ltest kill-server
tmux -Ltest -f/dev/null new
~~~
## How do I get logs from tmux?
Add `-vv` to tmux to create three log files in the current directory. If you can
reproduce without a configuration file:
~~~bash
tmux -Ltest kill-server
tmux -vv -Ltest -f/dev/null new
~~~
Or if you need your configuration:
~~~base
tmux kill-server
tmux -vv new
~~~
The log files are:
- `tmux-server*.log`: server log file.
- `tmux-client*.log`: client log file.
- `tmux-out*.log`: output log file.
Please attach the log files to your issue.

19
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,19 @@
### Issue description
Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md
before opening an issue.
Describe the problem and the steps to reproduce. Add a minimal tmux config if
necessary. Screenshots can be helpful, but no more than one or two.
Do not report bugs (crashes, incorrect behaviour) without reproducing on a tmux
built from the latest code in Git.
### Required information
Please provide the following information:
* tmux version (`tmux -V`).
* Platform (`uname -sp`).
* $TERM inside and outside of tmux (`echo $TERM`).
* Logs from tmux (`tmux kill-server; tmux -vv new`).

88
.github/README.md vendored Normal file
View File

@@ -0,0 +1,88 @@
# Welcome to tmux!
tmux is a terminal multiplexer: it enables a number of terminals to be created,
accessed, and controlled from a single screen. tmux may be detached from a
screen and continue running in the background, then later reattached.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.
## Dependencies
tmux depends on [libevent](https://libevent.org) 2.x, available from [this
page](https://github.com/libevent/libevent/releases/latest).
It also depends on [ncurses](https://www.gnu.org/software/ncurses/), available
from [this page](https://invisible-mirror.net/archives/ncurses/).
## Installation
### From release tarball
To build and install tmux from a release tarball, use:
~~~bash
./configure && make
sudo make install
~~~
tmux can use the utempter library to update utmp(5), if it is installed - run
configure with `--enable-utempter` to enable this.
### From version control
To get and build the latest from version control:
~~~bash
git clone https://github.com/tmux/tmux.git
cd tmux
sh autogen.sh
./configure && make
~~~
(Note that this requires at least a working C compiler, `make`, `autoconf`,
`automake`, `pkg-config` as well as `libevent` and `ncurses` libraries and
headers.)
## Contributing
Bug reports, feature suggestions and especially code contributions are most
welcome. Please send by email to:
tmux-users@googlegroups.com
Or open a GitHub issue or pull request.
There is [a TODO list](https://github.com/tmux/tmux/wiki/Contributing) which
explains some ideas for tmux not yet developed. Please feel free to ask for
clarifications on the mailing list if you're thinking of working on these or
need further information.
Please read the CONTRIBUTING file before opening an issue.
## Documentation
For documentation on using tmux, see the tmux.1 manpage. View it from the
source tree with:
~~~bash
nroff -mdoc tmux.1|less
~~~
A small example configuration is in `example_tmux.conf`.
And a bash(1) completion file at:
https://github.com/imomaliev/tmux-bash-completion
For debugging, run tmux with `-v` or `-vv` to generate server and client log
files in the current directory.
## Support
The tmux mailing list for general discussion and bug reports is:
https://groups.google.com/forum/#!forum/tmux-users
Subscribe by sending an email to:
tmux-users+subscribe@googlegroups.com

1
.gitignore vendored
View File

@@ -18,3 +18,4 @@ Makefile.in
configure
tmux.1.*
*.dSYM
cmd-parse.c

View File

@@ -1,10 +1,16 @@
language: c
matrix:
include:
- compiler: gcc
- compiler: clang
env: CFLAGS="-g -O2"
os:
- linux
- osx
compiler:
- gcc
- clang
before_install:
- sudo apt-get update -qq
- sudo apt-get -y install debhelper autotools-dev dh-autoreconf file libncurses5-dev libevent-dev pkg-config libutempter-dev build-essential
script: (CFLAGS= ./autogen.sh) && ./configure --enable-debug && make
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -y install bison autotools-dev libncurses5-dev libevent-dev pkg-config libutempter-dev build-essential; fi
script:
- ./autogen.sh && ./configure && make

524
CHANGES
View File

@@ -1,4 +1,493 @@
CHANGES FROM 2.3 to 2.4 20 April 2017
CHANGES FROM 2.9 to 3.0
* INCOMPATIBLE: Add a new {} syntax to the configuration file. This is a string
similar to single quotes but also includes newlines and allows commands that
take other commands as string arguments to be expressed more clearly and
without additional escaping.
A literal { and } or a string containing { or } must now be escaped or
quoted, for example '{' and '}' instead of { or }, or 'X#{foo}' instead of
X#{foo}.
* New <, >, <= and >= comparison operators for formats.
* Improve escaping of special characters in list-keys output.
* INCOMPATIBLE: tmux's configuration parsing has changed to use yacc(1). There
is one incompatible change: a \ on its own must be escaped or quoted as
either \\ or '\' (the latter works on older tmux versions).
Entirely the same parser is now used for parsing the configuration file
and for string commands. This means that constructs previously only
available in .tmux.conf, such as %if, can now be used in string commands
(for example, those given to if-shell - not commands invoked from the
shell, they are still parsed by the shell itself).
* Add support for the overline attribute (SGR 53). The Smol capability is
needed in terminal-overrides.
* Add the ability to create simple menus. Introduces new command
display-menu. Default menus are bound to MouseDown3 on the status line;
MouseDown3 or M-MouseDown3 on panes; MouseDown3 in tree, client and
buffer modes; and C-b C-m and C-b M-m.
* Allow panes to be empty (no command). They can be created either by piping to
split-window -I, or by passing an empty command ('') to split-window. Output
can be sent to an existing empty window with display-message -I.
* Add keys to jump between matching brackets (emacs C-M-f and C-M-b, vi %).
* Add a -e flag to new-window, split-window, respawn-window, respawn-pane to
pass environment variables into the newly created process.
* Hooks are now stored in the options tree as array options, allowing them to
have multiple separate commands. set-hook and show-hooks remain but
set-option and show-options can now also be used (show-options will only show
hooks if given the -H flag). Hooks with multiple commands are run in index
order.
* Automatically scroll if dragging to create a selection with the mouse and the
cursor reaches the top or bottom line.
* Add -no-clear variants of copy-selection and copy-pipe which do not clear the
selection after copying. Make copy-pipe clear the selection by default to be
consistent with copy-selection.
* Add an argument to copy commands to set the prefix for the buffer name, this
(for example) allows buffers for different sessions to be named separately.
* Update session activity on focus event.
* Pass target from source-file into the config file parser so formats in %if
and %endif have access to more useful variables.
* Add the ability to infer an option type (server, session, window) from its
name to show-options (it was already present in set-option).
CHANGES FROM 2.9 to 2.9a
* Fix bugs in select-pane and the main-horizontal and main-vertical layouts.
CHANGES FROM 2.8 to 2.9
* Attempt to preserve horizontal cursor position as well as vertical with
reflow.
* Rewrite main-vertical and horizontal and change layouts to better handle the
case where all panes won't fit into the window size, reduce problems with
pane border status lines and fix other bugs mostly found by Thomas Sattler.
* Add format variables for the default formats in the various modes
(tree_mode_format and so on) and add a -a flag to display-message to list
variables with values.
* Add a -v flag to display-message to show verbose messages as the format is
parsed, this allows formats to be debugged
* Add support for HPA (\033[`).
* Add support for origin mode (\033[?6h).
* No longer clear history on RIS.
* Extend the #[] style syntax and use that together with previous format
changes to allow the status line to be entirely configured with a single
option.
Now that it is possible to configure their content, enable the existing code
that lets the status line be multiple lines in height. The status option can
now take a value of 2, 3, 4 or 5 (as well as the previous on or off) to
configure more than one line. The new status-format array option configures
the format of each line, the default just references the existing status-*
options, although some of the more obscure status options may be eliminated
in time.
Additions to the #[] syntax are: "align" to specify alignment (left, centre,
right), "list" for the window list and "range" to configure ranges of text
for the mouse bindings.
The "align" keyword can also be used to specify alignment of entries in tree
mode and the pane status lines.
* Add E: and T: format modifiers to expand a format twice (useful to expand the
value of an option).
* The individual -fg, -bg and -attr options have been removed; they
were superseded by -style options in tmux 1.9.
* Allow more than one mode to be opened in a pane. Modes are kept on a stack
and retrieved if the same mode is entered again. Exiting the active mode goes
back to the previous one.
* When showing command output in copy mode, call it view mode instead (affects
pane_mode format).
* Add -b to display-panes like run-shell.
* Handle UTF-8 in word-separators option.
* New "terminal" colour allowing options to use the terminal default colour
rather than inheriting the default from a parent option.
* Do not move the cursor in copy mode when the mouse wheel is used.
* Use the same working directory rules for jobs as new windows rather than
always starting in the user's home.
* Allow panes to be one line or column in size.
* Go to last line when goto-line number is out of range in copy mode.
* Yank previously cut text if any with C-y in the command prompt, only use the
buffer if no text has been cut.
* Add q: format modifier to quote shell special characters.
* Add StatusLeft and StatusRight mouse locations (keys such as
MouseDown1StatusLeft) for the status-left and status-right areas of the
status line.
* Add -Z to find-window.
* Support for windows larger than the client. This adds two new options,
window-size and default-size, and a new command, resize-window. The
force-width and force-height options and the session_width and session_height
formats have been removed.
The new window-size option tells tmux how to work out the size of windows:
largest means it picks the size of the largest session, smallest the smallest
session (similar to the old behaviour) and manual means that it does not
automatically resize windows. aggressive-resize modifies the choice of
session for largest and smallest as it did before.
If a window is in a session attached to a client that is too small, only part
of the window is shown. tmux attempts to keep the cursor visible, so the part
of the window displayed is changed as the cursor moves (with a small delay,
to try and avoid excess redrawing when applications redraw status lines or
similar that are not currently visible).
Drawing windows which are larger than the client is not as efficient as those
which fit, particularly when the cursor moves, so it is recommended to avoid
using this on slow machines or networks (set window-size to smallest or
manual).
The resize-window command can be used to resize a window manually. If it is
used, the window-size option is automatically set to manual for the window
(undo this with "setw -u window-size"). resize-window works in a similar way
to resize-pane (-U -D -L -R -x -y flags) but also has -a and -A flags. -a
sets the window to the size of the smallest client (what it would be if
window-size was smallest) and -A the largest.
For the same behaviour as force-width or force-height, use resize-window -x
or -y.
If the global window-size option is set to manual, the default-size option is
used for new windows. If -x or -y is used with new-session, that sets the
default-size option for the new session.
The maximum size of a window is 10000x10000. But expect applications to
complain and higher memory use if making a window that big. The minimum size
is the size required for the current layout including borders.
The refresh-client command can be used to pan around a window, -U -D -L -R
moves up, down, left or right and -c returns to automatic cursor
tracking. The position is reset when the current window is changed.
CHANGES FROM 2.7 to 2.8
* Make display-panes block the client until a pane is chosen or it
times out.
* Clear history on RIS like most other terminals do.
* Add an "Any" key to run a command if a key is pressed that is not
bound in the current key table.
* Expand formats in load-buffer and save-buffer.
* Add a rectangle_toggle format.
* Add set-hook -R to run a hook immediately.
* Add README.ja.
* Add pane focus hooks.
* Allow any punctuation as separator for s/x/y not only /.
* Improve resizing with the mouse (fix resizing the wrong pane in some
layouts, and allow resizing multiple panes at the same time).
* Allow , and } to be escaped in formats as #, and #}.
* Add KRB5CCNAME to update-environment.
* Change meaning of -c to display-message so the client is used if it
matches the session given to -t.
* Fixes to : form of SGR.
* Add x and X to choose-tree to kill sessions, windows or panes.
CHANGES FROM 2.6 TO 2.7
* Remove EVENT_* variables from environment on platforms where tmux uses them
so they do not pass on to panes.
* Fixes for hooks at server exit.
* Remove SGR 10 (was equivalent to SGR 0 but no other terminal seems to do
this).
* Expand formats in window and session names.
* Add -Z flag to choose-tree, choose-client, choose-buffer to automatically
zoom the pane when the mode is entered and unzoom when it exits, assuming the
pane is not already zoomed. This is now part of the default key bindings.
* Add C-g to exit modes with emacs keys.
* Add exit-empty option to exit server if no sessions (defaults to on).
* Show if a filter is present in choose modes.
* Add pipe-pane -I to to connect stdin of the child process.
* Performance improvements for reflow.
* Use RGB terminfo(5) capability to detect RGB colour terminals (the existing
Tc extension remains unchanged).
* Support for ISO colon-separated SGR sequences.
* Add select-layout -E to spread panes out evenly (bound to E key).
* Support wide characters properly when reflowing.
* Pass PWD to new panes as a hint to shells, as well as calling chdir().
* Performance improvements for the various choose modes.
* Only show first member of session groups in tree mode (-G flag to choose-tree
to show all).
* Support %else in config files to match %if; from Brad Town in GitHub issue
1071.
* Fix "kind" terminfo(5) capability to be S-Down not S-Up.
* Add a box around the preview label in tree mode.
* Show exit status and time in the remain-on-exit pane text; from Timo
Boettcher in GitHub issue 1103.
* Correctly use pane-base-index in tree mode.
* Change the allow-rename option default to off.
* Support for xterm(1) title stack escape sequences (GitHub issue 1075 from
Brad Town).
* Correctly remove padding cells to fix a UTF-8 display problem (GitHub issue
1090).
CHANGES FROM 2.5 TO 2.6, 05 October 2017
* Add select-pane -T to set pane title.
* Fix memory leak when lines with BCE are removed from history.
* Fix (again) the "prefer unattached" behaviour of attach-session.
* Reorder how keys are checked to allow keys to be specified that have a
leading escape. GitHub issue 1048.
* Support REP escape sequence (\033[b).
* Run alert hooks based on options rather than always, and allow further bells
even if there is an existing bell.
* Add -d flag to display-panes to override display-panes-time.
* Add selection_present format when in copy mode (allows key bindings that do
something different if there is a selection).
* Add pane_at_left, pane_at_right, pane_at_top and pane_at_bottom formats.
* Make bell, activity and silence alerting more consistent by: removing the
bell-on-alert option; adding activity-action and silence-action options with
the same possible values as the existing bell-action; adding a "both" value
for the visual-bell, visual-activity and visual-silence options to trigger
both a bell and a message.
* Add a pane_pipe format to show if pipe-pane is active.
* Block signals between forking and resetting signal handlers so that the
libevent signal handler doesn't get called in the child and incorrectly write
into the signal pipe that it still shares with the parent. GitHub issue 1001.
* Allow punctuation in pane_current_command.
* Add -c for respawn-pane and respawn-window.
* Wait for any remaining data to flush when a pane is closed while pipe-pane is
in use.
* Fix working out current client with no target. GitHub issue 995.
* Try to fallback to C.UTF-8 as well as en_US.UTF-8 when looking for a UTF-8
locale.
* Add user-keys option for user-defined key escape sequences (mapped to User0
to User999 keys).
* Add pane-set-clipboard hook.
* FAQ file has moved out of repository to online.
* Fix problem with high CPU usage when a client dies unexpectedly. GitHub issue
941.
* Do a dance on OS X 10.10 and above to return tmux to the user namespace,
allowing access to the clipboard.
* Do not allow escape sequences which expect a specific terminator (APC, DSC,
OSC) to wait for forever - use a small timeout. This reduces the chance of
the pane locking up completely when sent garbage (cat /dev/random or
similar).
* Support SIGUSR2 to toggle logging on a running server, also generate the
"out" log file with -vv not -vvvv.
* Make set-clipboard a three state option: on (tmux both sends to outside
terminal and accepts from applications inside); external (tmux sends outside
but does not accept inside); and off.
* Fix OSC 4 palette setting for bright foreground colours. GitHub issue 954.
* Use setrgbf and setrgbb terminfo(5) capabilities to set RGB colours, if they
are available. (Tc is still supported as well.)
* Fix redrawing panes when they are resized several times but end up with the
size unchanged (for example, splitw/resizep -Z/breakp).
* Major rewrite of choose mode. Now includes preview, sorting, searching and
tagging; commands that can be executed directly from the mode (for example,
to delete one or more buffers); and filtering in tree mode.
* choose-window and choose-session are now aliases of choose-tree (in the
command-alias option).
* Support OSC 10 and OSC 11 to set foreground and background colours.
* Check the U8 capability to determine whether to use UTF-8 line drawing
characters for ACS.
* Some missing notifications for layout changes.
* Control mode clients now do not affect session sizes until they issue
refresh-client -C. new-session -x and -y works with control clients even if
the session is not detached.
* All new sessions that are unattached (whether with -d or started with no
terminal) are now created with size 80 x 24. Whether the status line is on or
off does not affect the size of new sessions until they are attached.
* Expand formats in option names and add -F flag to expand them in option values.
* Remember the search string for a pane even if copy mode is exited and entered
again.
* Some further BCE fixes (scroll up, reverse index).
* Improvements to how terminals are cleared (entirely or partially).
CHANGES FROM 2.4 TO 2.5, 09 May 2017
* Reset updated flag when restarting #() command so that new output is properly
recognised. GitHub issue 922.
* Fix ECH with a background colour.
* Do not rely on the terminal not moving the cursor after DL or EL.
* Fix send-keys and send-prefix in copy-mode (so C-b C-b works). GitHub issue
905.
* Set the current pane for rotate-window so it works in command sequences.
* Add pane_mode format.
* Differentiate M-Up from Escape+Up when possible (that is, in terminals with
xterm(1) style function keys). GitHub issue 907.
* Add session_stack and window_stack_index formats.
* Some new control mode notifications and corresponding hooks:
pane-mode-changed, window-pane-changed, client-session-changed,
session-window-changed.
* Format pane_search_string for last search term while in copy mode (useful
with command-prompt -I).
* Fix a problem with high CPU usage and multiple clients with #(). GitHub issue
889.
* Fix UTF-8 combining characters in column 0.
* Fix reference counting so that panes are properly destroyed and their
processes killed.
* Clamp SU (CSI S) parameter to work around a bug in Konsole.
* Tweak line wrapping in full width panes to play more nicely with terminal
copy and paste.
* Fix when we emit SGR 0 in capture-pane -e.
* Do not change TERM until after config file parsing has finished, so that
commands run inside the config file can use it to make decisions (typically
about default-terminal).
* Make the initial client wait until config file parsing has finished to avoid
racing with commands.
* Fix core when if-shell fails.
* Only use ED to clear screen if the pane is at the bottom.
* Fix multibyte UTF-8 output.
* Code improvements around target (-t) resolution.
* Change how the default target (for commands without -t) is managed across
command sequences: now it is set up at the start and commands are required
to update it if needed. Fixes binding command sequences to mouse keys.
* Make if-shell from the config file work correctly.
* Change to always check the root key table if no binding is found in the
current table (prefix table or copy-mode table or whatever). This means that
root key bindings will take effect even in copy mode, if not overridden by a
copy mode key binding.
* Fix so that the history file works again.
* Run config file without a client rather than using the first client, restores
previous behaviour.
* If a #() command doesn't exit, continue to read from it and use its last full
line of output.
* Handle slow terminals and fast output better: when the amount of data
outstanding gets too large, discard output until it is drained and we are
able to do a full redraw. Prevents tmux sitting on a huge buffer that the
terminal will take forever to consume.
* Do not redraw a client unless we realistically think it can accept the data -
defer redraws until the client has nothing else waiting to write.
CHANGES FROM 2.3 TO 2.4, 20 April 2017
Incompatible Changes
====================
@@ -23,12 +512,12 @@ Incompatible Changes
bind -Tcopy-mode C-Up send -X scroll-up
bind -Tcopy-mode WheelUpPane send -N5 -X scroll-up
This changes allows the full command parser (including command sequences) and
These changes allows the full command parser (including command sequences) and
command set to be used - for example, the normal command prompt with editing
and history is now used for searching, jumping, and so on instead of a custom
one. The default C-r binding is now:
bind -Tcopy-mode C-r command-prompt -p'search up' "send -X search-backward '%%'"
bind -Tcopy-mode C-r command-prompt -i -p'search up' "send -X search-backward-incremental '%%'"
There are also some new commmands available with send -X, such as
copy-pipe-and-cancel.
@@ -78,7 +567,7 @@ Normal Changes
set -ag syntax should work without change).
* There have been substantial performance improvements.
CHANGES FROM 2.2 to 2.3 29 September 2016
CHANGES FROM 2.2 TO 2.3, 29 September 2016
Incompatible Changes
====================
@@ -99,7 +588,7 @@ Normal Changes
* 'display-panes' can now accept a command to run, rather than always
selecting the pane.
CHANGES FROM 2.1 to 2.2 10 April 2016
CHANGES FROM 2.1 TO 2.2, 10 April 2016
Incompatible Changes
====================
@@ -164,8 +653,7 @@ Normal Changes
* RGB (24bit) colour support. The 'Tc' flag must be set in the external TERM
entry (using terminal-overrides or a custom terminfo entry).
CHANGES FROM 2.0 to 2.1 18 October 2015
CHANGES FROM 2.0 TO 2.1, 18 October 2015
Incompatible Changes
====================
@@ -216,7 +704,7 @@ Normal Changes
* Copy mode is exited if the history is cleared whilst in copy-mode.
* 'copy-mode' learned '-e' to exit copy-mode when scrolling to end.
CHANGES FROM 1.9a to 2.0 6 March 2015
CHANGES FROM 1.9a TO 2.0, 06 March 2015
Incompatible Changes
====================
@@ -275,18 +763,18 @@ Normal Changes
* 'split-window' and 'join-window' understand -b to create the pane to the left
or above the target pane.
CHANGES FROM 1.9 to 1.9a 22 February 2014
CHANGES FROM 1.9 TO 1.9a, 22 February 2014
NOTE: This is a bug-fix release to address some important bugs which just
NOTE: This is a bug-fix release to address some important bugs which just
missed the 1.9 deadline, but were found afterwards.
Normal Changes
==============
* Fix crash due to uninitialized lastwp member of layout_cell
* Fix -fg/-bg/-style with 256 colour terminals.
* Fix -fg/-bg/-style with 256 colour terminals.
CHANGES FROM 1.8 to 1.9, 20 February 2014
CHANGES FROM 1.8 TO 1.9, 20 February 2014
NOTE: This release has bumped the tmux protocol version. It is therefore
advised that the prior tmux server is restarted when this version of tmux is
@@ -341,7 +829,7 @@ Normal Changes
* tmux now supports 256 colours running under fbterm.
* Many bug fixes!
CHANGES FROM 1.7 to 1.8, 26 March 2013
CHANGES FROM 1.7 TO 1.8, 26 March 2013
Incompatible Changes
====================
@@ -392,7 +880,7 @@ Normal Changes
* Lots and lots of bug fixes, fixing memory-leaks, etc.
* Various manpage improvements.
CHANGES FROM 1.6 to 1.7, 13 October 2012
CHANGES FROM 1.6 TO 1.7, 13 October 2012
* tmux configuration files now support line-continuation with a "\" at the
end of a line.
@@ -642,7 +1130,7 @@ CHANGES FROM 1.2 TO 1.3, 18 July 2010
* Run job commands explicitly in the global environment (which can be modified
with setenv -g), rather than with the environment tmux started with.
* Use the machine's hostname as the default title, instead of an empty string.
* Prevent double free if the window option remain-on-exit is set.
* Prevent double free if the window option remain-on-exit is set.
* Key string conversions rewritten.
* Mark zombie windows as dead in the choose-window list.
* Tiled layout added.
@@ -744,7 +1232,7 @@ CHANGES FROM 1.0 TO 1.1, 05 November 2009
* New lock-client (alias lockc), and lock-session (alias locks) commands to
lock a particular client, or all clients attached to a session.
* Support C-n/C-p/C-v/M-v with emacs keys in choice mode.
* Use : for goto line rather than g in vi mode.
* Use : for goto line rather than g in vi mode.
* Try to guess which client to use when no target client was specified. Finds
the current session, and if only one client is present, use it. Otherwise,
return the most recently used client.
@@ -783,7 +1271,7 @@ CHANGES FROM 1.0 TO 1.1, 05 November 2009
* xterm-keys rewrite.
* Additional code reduction, and bug fixes.
CHANGES FROM 0.9 TO 1.0, 20 Sept 2009
CHANGES FROM 0.9 TO 1.0, 20 September 2009
* Option to alter the format of the window title set by tmux.
* Backoff for a while after multiple incorrect password attempts.
@@ -875,7 +1363,7 @@ The list of older changes is below.
* main-horizontal layout and main-pane-height option to match vertical.
* New window option main-pane-width to set the width of the large left pane with
main-vertical (was left-vertical) layout.
main-vertical (was left-vertical) layout.
* Lots of layout cleanup. manual layout is now manual-vertical.
16 May 2009

View File

@@ -1,33 +0,0 @@
When reporting issues:
YOU MUST INCLUDE THE TMUX VERSION
DO NOT OPEN AN ISSUE THAT DOES NOT MENTION THE TMUX VERSION
Please also include:
- your platform (Linux, OS X, or whatever);
- a brief description of the problem with steps to reproduce;
- a minimal tmux config, if you can't reproduce without a config;
- your terminal, and $TERM inside and outside of tmux;
- logs from tmux (see below);
- at most one or two screenshots, if helpful.
This should include at least the output of:
$ uname -sp && tmux -V && echo $TERM
Please do not report bugs (crashes, incorrect behaviour) without reproducing on
a tmux built from Git master.
Note that TERM inside tmux must be a variant of screen or tmux (for example:
screen or screen-256color, tmux or tmux-256color). Please ensure this is the
case before opening an issue.
To run tmux without a config and get logs, run:
tmux -Ltest kill-server
tmux -vvvv -Ltest -f/dev/null new
Then reproduce the problem, exit tmux, and attach the tmux-server-*.log file
from the current directory to the issue.

View File

@@ -1,10 +1,7 @@
THIS IS FOR INFORMATION ONLY, CODE IS UNDER THE LICENCE AT THE TOP OF ITS FILE.
The README, CHANGES, FAQ and TODO files are licensed under the ISC
license. Files under examples/ remain copyright their authors unless otherwise
stated in the file but permission has been received to distribute them with
tmux. All other files have a license and copyright notice at their start,
typically:
The README, CHANGES, FAQ and TODO files are licensed under the ISC license. All
other files have a license and copyright notice at their start, typically:
Copyright (c) <author>

462
FAQ
View File

@@ -1,462 +0,0 @@
tmux frequently asked questions
******************************************************************************
* PLEASE NOTE: most display problems are due to incorrect TERM! Before *
* reporting problems make SURE that TERM settings are correct inside and *
* outside tmux. *
* *
* Inside tmux TERM must be "screen" or similar (such as "screen-256color"). *
* Don't bother reporting problems where it isn't! *
* *
* Outside, it must match your terminal: particularly, use "rxvt" for rxvt *
* and derivatives. *
******************************************************************************
* How is tmux different from GNU screen?
tmux and GNU screen have many similarities. Some of the main differences I am
aware of are (bearing in mind I haven't used screen for a few years now):
- tmux uses a client-server model. Each server has single Unix domain socket in
/tmp and within one server there are multiple sessions which may be attached
to multiple clients (terminals).
This has advantages, notably: windows may be linked simultaneously to
multiple sessions; windows may be moved freely between sessions; and a client
may be switched between sessions easily (C-b D). There is one major
disadvantage: if the server crashes, game over, all sessions die. In
practice, however, tmux is quite stable and gets more so as people report any
bugs they hit :-).
This model is different from screen, where typically each new screen instance
is independent. tmux supports the same behaviour by using multiple servers
with the -L option but it is not typically recommended.
- Different command interfaces. One of the goals of tmux is that the shell
should be easily usable as a scripting language - almost all tmux commands
can be used from the shell and behave identically whether used from the
shell, from a key binding or from the command prompt. Personally I also find
tmux's command interface much more consistent and clearer, but this is
subjective.
- tmux calls window names (what you see in the status line) "names", screen
calls them "titles".
- tmux has a multiple paste buffers. Not a major one but comes in handy quite a
lot.
- tmux supports automatically renaming windows to the running application
without gross hacks using escape sequences. Its even on by default.
- tmux has a choice of vi or emacs key layouts. Again, not major, but I use
emacs so if tmux did support only one key set it would be emacs and then all
the vi users would get humpy. Key bindings may be completely reconfigured in
any case.
- tmux has an option to limit the window size.
- tmux has search in windows (C-b f).
- The window split (pane) model is different. tmux has two objects, windows and
panes; screen has just windows. This difference has several implications:
* In screen you can have a window appear in several layouts, in tmux a pane
can only be in one window (fixing this is a big todo item but quite
invasive).
* tmux layouts are immutable and do not get changed unless you modify them.
* In tmux, all panes are closed when you kill a window.
* tmux panes do not have individual names, titles and so on.
I think tmux's model is much easier to manage and navigate within a window,
but breaking panes off from and joining them to windows is more clumsy.
tmux also has support for preset pane layouts.
- tmux's status line syntax is more readable and easier to use. I think it'd be
hard for anyone to argue with this. tmux doesn't support running a command
constantly and always using the last line of its output, commands must be run
again each time.
- tmux has modern, easily extended code. Again hard to argue screen is better
if you have looked at the code.
- tmux depends on libevent. I don't see this as a disadvantage: libevent is
small and portable, and on modern systems with current package management
systems dependencies are not an issue. libevent brings advantages in code
simplicity and performance.
- screen allows the window to be bigger than the terminal and can pan around
it. tmux limits the size to the largest attached client. This is a big todo
item for tmux but it is not trivial.
- screen has builtin serial and telnet support; this is bloat and is unlikely
to be added to tmux.
- Environment handling is different.
- tmux tends to be more demanding on the terminal so tends to show up terminal
and application bugs which screen does not.
- screen has wider platform support, for example IRIX, and for odd terminals.
* I found a bug! What do I do?
Check the latest version of tmux from Git to see if the problem is still
reproducible. Sometimes the length of time between releases means a lot of
fixes can be sitting in Git and the problem might already be fixed.
Please send bug reports by email to nicholas.marriott@gmail.com or
tmux-users@googlegroups.com. Please include as much of the following
information as possible:
- the version of tmux you are running;
- the operating system you are using and its version;
- the terminal emulator you are using and the TERM setting when tmux was
started;
- a description of the problem;
- if the problem is repeatable, the steps to repeat the problem;
- for screen corruption issues, a screenshot and the output of "infocmp $TERM"
from outside tmux are often very useful.
* Why doesn't tmux do $x?
Please send feature requests by email to tmux-users@googlegroups.com.
* Why do you use the screen terminal description inside tmux? It sucks.
It is already widely available. It is planned to change to something else such
as xterm-xfree86 at some point, if possible.
* I don't see any colour in my terminal! Help!
On some platforms, common terminal descriptions such as xterm do not include
colour. screen ignores this, tmux does not. If the terminal emulator in use
supports colour, use a value for TERM which correctly lists this, such as
xterm-color.
* tmux freezes my terminal when I attach to a session. I even have to kill -9
the shell it was started from to recover!
Some consoles really really don't like attempts to set the window title. Tell
tmux not to do this by turning off the "set-titles" option (you can do this
in .tmux.conf):
set -g set-titles off
If this doesn't fix it, send a bug report.
* Why is C-b the prefix key? How do I change it?
The default key is C-b because the prototype of tmux was originally developed
inside screen and C-b was chosen not to clash with the screen meta key. It
also has the advantage of not interfering with the use of C-a for start-of-line
in emacs and the shell (although it does interfere with previous-character).
Changing is simple: change the "prefix-key" option, and - if required - move
the binding of the "send-prefix" command from C-b (C-b C-b sends C-b by
default) to the new key. For example:
set -g prefix C-a
unbind C-b
bind C-a send-prefix
* How do I use UTF-8?
When running tmux in a UTF-8 capable terminal, UTF-8 must be turned on in tmux;
as of release 0.9, tmux attempts to autodetect a UTF-8-capable terminal by
checking the LC_ALL, LC_CTYPE and LANG environment variables. list-clients may
be used to check if this is detected correctly; if not, the -u command-line
flag may be specified when creating or attaching a client to a tmux session:
$ tmux -u new
Since the 1.0 release, tmux will turn on UTF-8 related options automatically
(ie status-utf8, and utf8) if the above conditions are met.
* How do I use a 256 colour terminal?
Provided the underlying terminal supports 256 colours, it is usually sufficient
to add the following to ~/.tmux.conf:
set -g default-terminal "screen-256color"
Note that some platforms do not support "screen-256color" ("infocmp
screen-256color" will return an error) - in this case see the next entry in
this FAQ.
tmux attempts to detect a 256 colour terminal both by looking at the colors
terminfo entry and by looking for the string "256col" in the TERM environment
variable.
If both these methods fail, the -2 flag may be passed to tmux when attaching
to a session to indicate the terminal supports 256 colours.
* vim or $otherprogram doesn't display 256 colours. What's up?
Some programs attempt to detect the number of colours a terminal is capable of
by checking the colors terminfo or Co termcap entry. However, this is not
reliable, and in any case is missing from the "screen" terminal description
used inside tmux.
There are two options (aside from using "screen-256color") to allow programs to
recognise they are running on a 256-colour terminal inside tmux:
- Manually force the application to use 256 colours always or if TERM is set to
screen. For vim, you can do this by overriding the t_Co option, see
http://vim.wikia.com/wiki/256_colors_in_vim.
- Creating a custom terminfo file that includes colors#256 in ~/.terminfo and
using it instead. These may be compiled with tic(1).
* How do I make Ctrl-PgUp and Ctrl-PgDn work in vim?
tmux supports passing through ctrl (and where supported by the client terminal,
alt and shift) modifiers to function keys using xterm(1)-style key sequences.
This may be enabled per window, or globally with the tmux command:
setw -g xterm-keys on
Because the TERM variable inside tmux must be set to "screen", vim will not
automatically detect these keys are available; however, the appropriate key
sequences can be overridden in .vimrc using the following:
if &term == "screen"
set t_kN=^[[6;*~
set t_kP=^[[5;*~
endif
And similarly for any other keys for which modifiers are desired.
Please note that the "xterm-keys" setting may affect other programs, in the
same way as running them in a standard xterm; for example most shells do not
expect to receive xterm(1)-style key sequences so this setting may prevent keys
such as ctrl-left and ctrl-right working correctly. tmux also passes through
the ctrl (bit 5 set, for example ^[[5~ to ^[[5^) modifier in non-xterm(1) mode;
it may be possible to configure vim to accept these, an example of how to do so
would be welcome.
vim users may also want to set the "ttyfast" option inside tmux.
* How do I make ctrl and shift arrow keys work in emacs?
The terminal-init-screen function in term/screen.el is called for new frames,
but it doesn't configure any function keys.
If the tmux xterm-keys option is on, it is enough to define the same keys as
xterm. Add the following to init.el or .emacs to do this:
(defadvice terminal-init-screen
;; The advice is named `tmux', and is run before `terminal-init-screen' runs.
(before tmux activate)
;; Docstring. This describes the advice and is made available inside emacs;
;; for example when doing C-h f terminal-init-screen RET
"Apply xterm keymap, allowing use of keys passed through tmux."
;; This is the elisp code that is run before `terminal-init-screen'.
(if (getenv "TMUX")
(let ((map (copy-keymap xterm-function-map)))
(set-keymap-parent map (keymap-parent input-decode-map))
(set-keymap-parent input-decode-map map))))
And ensure .tmux.conf contains "set -g xterm-keys on".
Alternatively, the screen.el file can be copied to the load path and
customized.
* Why doesn't elinks set the window title inside tmux?
There isn't a way to detect if a terminal supports setting the window title, so
elinks attempts to guess by looking at the environment. Rather than looking for
TERM=screen, it uses the STY variable to detect if it is running in screen;
tmux does not use this so the check fails. A workaround is to set STY before
running elinks.
The following shell function does this, and also clears the window title on
exit (elinks, for some strange reason, sets it to the value of TERM):
elinks() {
STY= `which elinks` $*
echo -ne \\033]0\;\\007;
}
* What is the proper way to escape characters with #(command)?
When using the #(command) construction to include the output from a command in
the status line, the command will be parsed twice. First, when it's read by the
configuration file or the command-prompt parser, and second when the status
line is being drawn and the command is passed to the shell. For example, to
echo the string "(test)" to the status line, either single or double quotes
could be used:
set -g status-right "#(echo \\\\(test\\\\))"
set -g status-right '#(echo \\\(test\\\))'
In both cases, the status-right option will be set to the string "#(echo
\\(test\\))" and the command executed will be "echo \(test\)".
* tmux uses too much CPU. What do I do?
Automatic window renaming may use a lot of CPU, particularly on slow computers:
if this is a problem, turn it off with "setw -g automatic-rename off". If this
doesn't fix it, please report the problem.
* I use PuTTY and my tmux window pane separators are all qqqqqqqqq's!
PuTTY is using a character set translation that doesn't support ACS line
drawing. With a Unicode font, try setting PuTTY to use a different translation
on the Window -> Translation configuration page. For example, change UTF-8 to
ISO-8859-1 or CP437. It may also be necessary to adjust the way PuTTY treats
line drawing characters in the lower part of the same configuration page.
* What is the best way to display the load average? Why no #L?
It isn't possible to get the load average portably in code and it is preferable
not to add portability goop. The following works on at least Linux, *BSD and OS
X:
uptime|awk '{split(substr($0, index($0, "load")), a, ":"); print a[2]}'
* How do I attach the same session to multiple clients but with a different
current window, like screen -x?
One or more of the windows can be linked into multiple sessions manually with
link-window, or a grouped session with all the windows can be created with
new-session -t.
* Ctrl and arrow keys doesn't work in putty! What do I do?
putty inverts the sense of the cursor key mode on ctrl, which is a bit hard for
tmux to detect properly. To get ctrl keys right, change the terminfo settings
so kUP5 (Ctrl-Up etc) are the adjusted versions, and disable smkx/rmkx so tmux
doesn't change the mode. For example with this line in .tmux.conf (assuming you
have TERM set to xterm):
set -g terminal-overrides "xterm*:kLFT5=\eOD:kRIT5=\eOC:kUP5=\eOA:kDN5=\eOB:smkx@:rmkx@"
Note that this will only work in tmux 1.2 and above.
* How can I blank the tmux window?
GNU screen has a feature whereby it will blank the screen after a period of
inactivity. To do the same thing in tmux, use the lock-command setting, for
example (with GNU bash):
set -g lock-command 'tput civis && read -s -n1'
This will remove the cursor and tell the shell to quit once a key has been
pressed. For zsh, use "read -s -k1".
In addition, it's possible to have both blanking and locking (for instance via
lock(1) or vlock(1)) by using the following:
bind x set lock-command '/usr/bin/vlock' \; lock-client \; set lock-command 'tput civis && read -s -n1'
* I don't see italics! Or less and vim show italics and reverse the wrong way round!
GNU screen does not support italics and the "screen" terminfo description uses
the italics escape sequence incorrectly.
As of tmux 2.1, if default-terminal is set to "screen" or matches "screen-*",
tmux will behave like screen and italics will be disabled.
To enable italics, create a new terminfo entry called "tmux" (some platforms
may already have this, you can check with "infocmp tmux"):
$ cat <<EOF|tic -x -
tmux|tmux terminal multiplexer,
ritm=\E[23m, rmso=\E[27m, sitm=\E[3m, smso=\E[7m, Ms@,
use=xterm+tmux, use=screen,
tmux-256color|tmux with 256 colors,
use=xterm+256setaf, use=tmux,
EOF
$
And tell tmux to use it in ~/.tmux.conf:
set -g default-terminal "tmux"
If using urxvt, make sure you have an italics capable font enabled. for
example, add to ~/.Xdefaults:
urxvt.italicFont: xft:Bitstream Vera Sans Mono:italic:autohint=true
* How can I make tmux use my terminal's scrollback buffer?
Normally, tmux enables the terminal's "alternate screen". Most terminals (such
as xterm) do not save scrollback for the alternate screen. You might prefer
tmux to use the normal screen, so it uses your terminal's scrollback
buffer. This way, you can access the scrollback buffer as usual, for example
using the mouse wheel - although there is no guarantee output inside tmux will
always (or ever) be added to the scrollback.
You can make tmux use the normal screen by telling it that your terminal does
not have an alternate screen. Put the following in ~/.tmux.conf:
set -ga terminal-overrides ',xterm*:smcup@:rmcup@'
Adjust if your $TERM does not start with xterm.
tmux will still emulate the alternate screen for applications run under tmux,
so you don't really lose anything with this setting. The only disadvantage is
that when you exit tmux, it will not restore whatever was there before you
started.
* How do I see the default configuration?
Show the default session options by starting a new tmux server with no
configuration file:
$ tmux -Lfoo -f/dev/null start\; show -g
Or the default window options:
$ tmux -Lfoo -f/dev/null start\; show -gw
* How do I copy a selection from tmux to the system's clipboard?
When running in xterm(1), tmux can automatically send copied text to the
clipboard. This is controlled by the set-clipboard option and also needs this
X resource to be set:
XTerm*disallowedWindowOps: 20,21,SetXprop
For rxvt-unicode (urxvt), there is an unofficial Perl extension here:
http://anti.teamidiot.de/static/nei/*/Code/urxvt/
Otherwise a key binding for copy mode using xclip (or xsel) works:
bind -temacs-copy C-y copy-pipe "xclip -i >/dev/null"
Or for inside and outside copy mode with the prefix key:
bind C-y run -b "tmux save-buffer - | xclip -i"
On OS X, look at the pbcopy(1) and pbpaste(1) commands.
* Why don't some commands work inside tmux on OS X?
Apple requires some undocumented, unsupported fiddling to allow commands that
interact with the GUI to work. Neither tmux itself nor most shells do this, so
an external program is required. This can be found here:
https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard
Affected commands may include say(1), pbcopy(1), pbpaste(1) and ssh(1).
* Why do I see dots around a session when I attach to it?
tmux limits the size of the window to the smallest attached session. If
it didn't do this then it would be impossible to see the entire window.
The dots mark the size of the window tmux can display.
To avoid this, detach all other clients when attaching:
$ tmux attach -d
Or from inside tmux by detaching individual clients with C-b D or all
using:
C-b : attach -d

View File

@@ -1 +0,0 @@
Please read https://raw.githubusercontent.com/tmux/tmux/master/CONTRIBUTING

View File

@@ -2,14 +2,12 @@
# Obvious program stuff.
bin_PROGRAMS = tmux
CLEANFILES = tmux.1.mdoc tmux.1.man
CLEANFILES = tmux.1.mdoc tmux.1.man cmd-parse.c
# Distribution tarball options.
EXTRA_DIST = \
CHANGES FAQ README TODO COPYING example_tmux.conf compat/*.[ch] \
CHANGES README README.ja COPYING example_tmux.conf compat/*.[ch] \
osdep-*.c mdoc2man.awk tmux.1
dist-hook:
grep "^#enable_debug=" configure
# Preprocessor flags.
AM_CPPFLAGS += @XOPEN_DEFINES@ -DTMUX_CONF="\"$(sysconfdir)/tmux.conf\""
@@ -68,13 +66,12 @@ dist_tmux_SOURCES = \
cmd-bind-key.c \
cmd-break-pane.c \
cmd-capture-pane.c \
cmd-choose-buffer.c \
cmd-choose-client.c \
cmd-choose-tree.c \
cmd-command-prompt.c \
cmd-confirm-before.c \
cmd-copy-mode.c \
cmd-detach-client.c \
cmd-display-menu.c \
cmd-display-message.c \
cmd-display-panes.c \
cmd-find-window.c \
@@ -97,6 +94,7 @@ dist_tmux_SOURCES = \
cmd-move-window.c \
cmd-new-session.c \
cmd-new-window.c \
cmd-parse.y \
cmd-paste-buffer.c \
cmd-pipe-pane.c \
cmd-queue.c \
@@ -104,6 +102,7 @@ dist_tmux_SOURCES = \
cmd-rename-session.c \
cmd-rename-window.c \
cmd-resize-pane.c \
cmd-resize-window.c \
cmd-respawn-pane.c \
cmd-respawn-window.c \
cmd-rotate-window.c \
@@ -115,14 +114,12 @@ dist_tmux_SOURCES = \
cmd-send-keys.c \
cmd-set-buffer.c \
cmd-set-environment.c \
cmd-set-hook.c \
cmd-set-option.c \
cmd-show-environment.c \
cmd-show-messages.c \
cmd-show-options.c \
cmd-source-file.c \
cmd-split-window.c \
cmd-string.c \
cmd-swap-pane.c \
cmd-swap-window.c \
cmd-switch-client.c \
@@ -135,9 +132,9 @@ dist_tmux_SOURCES = \
control.c \
environ.c \
format.c \
format-draw.c \
grid-view.c \
grid.c \
hooks.c \
input-keys.c \
input.c \
job.c \
@@ -147,13 +144,14 @@ dist_tmux_SOURCES = \
layout-set.c \
layout.c \
log.c \
menu.c \
mode-tree.c \
names.c \
notify.c \
options-table.c \
options.c \
paste.c \
proc.c \
pty.c \
resize.c \
screen-redraw.c \
screen-write.c \
@@ -162,7 +160,7 @@ dist_tmux_SOURCES = \
server-fn.c \
server.c \
session.c \
signal.c \
spawn.c \
status.c \
style.c \
tmux.c \
@@ -172,9 +170,11 @@ dist_tmux_SOURCES = \
tty-term.c \
tty.c \
utf8.c \
window-choose.c \
window-buffer.c \
window-client.c \
window-clock.c \
window-copy.c \
window-tree.c \
window.c \
xmalloc.c \
xmalloc.h \
@@ -198,7 +198,7 @@ install-exec-hook:
>$(srcdir)/tmux.1.mdoc; \
else \
sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1| \
$(AWK) -f$(srcdir)/mdoc2man.awk >$(srcdir)/tmux.1.man; \
$(AWK) -f $(srcdir)/mdoc2man.awk >$(srcdir)/tmux.1.man; \
fi
$(mkdir_p) $(DESTDIR)$(mandir)/man1
$(INSTALL_DATA) $(srcdir)/tmux.1.@MANFORMAT@ \

84
README
View File

@@ -1,18 +1,22 @@
Welcome to tmux!
tmux is a "terminal multiplexer", it enables a number of terminals (or windows)
to be accessed and controlled from a single terminal. tmux is intended to be a
simple, modern, BSD-licensed alternative to programs such as GNU screen.
tmux is a terminal multiplexer: it enables a number of terminals to be created,
accessed, and controlled from a single screen. tmux may be detached from a
screen and continue running in the background, then later reattached.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.
tmux depends on libevent 2.x. Download it from:
* Dependencies
http://libevent.org
tmux depends on libevent 2.x, available from:
https://github.com/libevent/libevent/releases/latest
It also depends on ncurses, available from:
http://invisible-island.net/ncurses/
https://invisible-mirror.net/archives/ncurses/
* Installation
To build and install tmux from a release tarball, use:
@@ -29,45 +33,45 @@ To get and build the latest from version control:
$ sh autogen.sh
$ ./configure && make
For more information see http://git-scm.com. Patches should be sent by email to
the mailing list at tmux-users@googlegroups.com.
(Note that this requires at least a working C compiler, make, autoconf,
automake, pkg-config as well as libevent and ncurses libraries and headers.)
For documentation on using tmux, see the tmux.1 manpage. It can be viewed from
the source tree with:
$ nroff -mdoc tmux.1|less
Some common questions are answered in the FAQ file, a rough todo list is in the
TODO file and an example configuration in example_tmux.conf.
A vim(1) syntax file is available at:
https://github.com/ericpruitt/tmux.vim
https://raw.githubusercontent.com/ericpruitt/tmux.vim/master/vim/syntax/tmux.vim
And a bash(1) completion file at:
https://github.com/imomaliev/tmux-bash-completion
For debugging, running tmux with -v or -vv will generate server and client log
files in the current directory.
tmux mailing lists are available. For general discussion and bug reports:
https://groups.google.com/forum/#!forum/tmux-users
And for Git commit emails:
https://groups.google.com/forum/#!forum/tmux-git
Subscribe by sending an email to <tmux-users+subscribe@googlegroups.com>.
* Contributing
Bug reports, feature suggestions and especially code contributions are most
welcome. Please send by email to:
tmux-users@googlegroups.com
This file and the CHANGES, FAQ, SYNCING and TODO files are licensed under the
ISC license. All other files have a license and copyright notice at their start.
Or open a GitHub issue or pull request.
-- Nicholas Marriott <nicholas.marriott@gmail.com>
* Documentation
For documentation on using tmux, see the tmux.1 manpage. View it from the
source tree with:
$ nroff -mdoc tmux.1|less
A small example configuration is in example_tmux.conf.
A bash(1) completion file is at:
https://github.com/imomaliev/tmux-bash-completion
For debugging, run tmux with -v and -vv to generate server and client log files
in the current directory.
* Support
The tmux mailing list for general discussion and bug reports is:
https://groups.google.com/forum/#!forum/tmux-users
Subscribe by sending an email to:
tmux-users+subscribe@googlegroups.com
* License
This file and the CHANGES files are licensed under the ISC license. All other
files have a license and copyright notice at their start.

62
README.ja Normal file
View File

@@ -0,0 +1,62 @@
tmuxへようこそ!
tmuxはターミナルマルチプレクサーです。複数のターミナルを一つのスクリーン内に作成し、操作することができます。
バックグラウンドで処理を実行中に一度スクリーンから離れて後から復帰することも可能です。
OpenBSD、FreeBSD、NetBSD、Linux、OS X、Solarisで実行できます。
tmuxはlibevent 2.x.に依存します。 下記からダウンロードしてください。
http://libevent.org
また、ncursesも必要です。こちらからどうぞ。
http://invisible-island.net/ncurses/
tarballでのtmuxのビルドとインストール方法。
$ ./configure && make
$ sudo make install
tmuxはutmp(5)をアップデートするためにutempterを使うことができます。もしインストール済みであればオプション「--enable-utempter」をつけて実行してください。
リポジトリから最新バージョンを手に入れるためには下記を実行。
$ git clone https://github.com/tmux/tmux.git
$ cd tmux
$ sh autogen.sh
$ ./configure && make
(ビルドのためにはlibevent、ncurses libraries、headersに加えて、C compiler、make、autoconf、automake、pkg-configが必要です。)
詳しい情報はhttp://git-scm.comをご覧ください。修正はメール<tmux-users@googlegroups.com>宛、もしくはhttps://github.com/tmux/tmux/issuesにて受け付けています。
tmuxのドキュメントについてはtmux.1マニュアルをご覧ください。こちらのコマンドで参照可能です。
$ nroff -mdoc tmux.1|less
サンプル設定は本リポジトリのexample_tmux.confに
また、bash-completionファイルは下記にあります。
https://github.com/imomaliev/tmux-bash-completion
「-v」や「-vv」を指定することでデバッグモードでの起動が可能です。カレントディレクトリにサーバーやクライアントのログファイルが生成されます。
議論やバグレポート用のメーリングリストにはこちらから参加可能です。
https://groups.google.com/forum/#!forum/tmux-users
gitコミットについての連絡先
https://groups.google.com/forum/#!forum/tmux-git
購読は<tmux-users+subscribe@googlegroups.com>までメールをお願いします。
バグレポートや機能追加(特にコードへの貢献)は大歓迎です。こちらにご連絡ください。
tmux-users@googlegroups.com
本ファイル、CHANGES、 FAQ、SYNCINGそしてTODOはISC licenseで保護されています。
その他のファイルのライセンスや著作権については、ファイルの上部に明記されています。
-- Nicholas Marriott <nicholas.marriott@gmail.com>

19
SYNCING
View File

@@ -140,15 +140,13 @@ to compat/ as and when appropriate.
Release tmux for next version
=============================
1. Comment the "enable_debug=yes" line in configure.ac, since releases
don't have debugging enabled, otherwise make(1) aborts when
preparing the distribution.
2. Update and commit README and CHANGES. The former should be checked for
1. Update and commit README and CHANGES. The former should be checked for
anything outdated and updated with a list of things that might break
upgrades and the latter should mention all the major changes since
the last version.
2. Make sure configure.ac has the new version number.
3. Tag with:
% git tag -a 2.X
@@ -157,7 +155,7 @@ Release tmux for next version
Push the tag out with:
% git push 2.X
% git push --tags
4. Build the tarball with 'make dist'.
@@ -168,9 +166,8 @@ Release tmux for next version
Click the "Add release notes", upload the tarball and add a link in the
description field to the CHANGES file.
7. Clone the tmux.github.io repository, and change the RELEASE version in
the Makefile. Commit it, and run 'make' to replace %%VERSION%%. Push
the result out.
6. Clone the tmux.github.io repository, and change the RELEASE version in the
Makefile. Commit it, and run 'make' to replace %%RELEASE%%. Push the
result out.
8. Bump version in tmux/tmux.git configure.ac and uncomment "enable_debug=yes" to
create a debug build by default.
7. Change version back to master in configure.ac.

122
TODO
View File

@@ -1,122 +0,0 @@
- command bits and pieces:
* allow multiple targets: fnmatch for -t/-c, for example detach all
clients with -t*
* add -c for new-session like new-window
* ' and " should be parsed the same (eg "\e" vs '\e') in config
and command prompt
* last-pane across sessions
* resize-pane -p to match split-window -p
* flag to wait-for to have a timeout and/or to stop waiting when the
client gets a signal
- make command sequences more usable
* don't require space after ;
* options for error handling: && and ||?
- options bits and pieces:
* way to set socket path from config file
- format improvements:
* option to quote format (#{q:session_name})
* some way to pad # stuff with spaces
* formats to show if a window is linked into multiple sessions, into
multiple attached sessions, and is the active window in multiple
attached sessions?
- choose mode improvements:
* choose-pane command (augment choose-tree to do this?)
* flag to choose-* for sort order
* two choices (first one then second, for swap-pane and join-pane)
* choose modes should ditch the key bindings and just have fixed keys, and
be more customized to their purpose (d to delete a buffer for choose-buffer,
a preview of buffer contents, etc)
- improve monitor-*:
* straighten out rules for multiple clients
* think about what happens across sessions
* monitor changes within a region
* perhaps monitor /all/ panes in the window not just one
- improve mouse support:
* bind commands to mouse in different areas?
* commands executed when clicking on a pattern (URL)
- warts on current naming:
* display-time but message-fg/bg/attr
* list-* vs show-*
- copy/paste improvements:
* paste w/o trailing whitespace
* command to toggle selection not to move it in copy-mode
* regex searching
* searching in copy mode should unwrap lines, so if you search for "foobar"
then it should be found even if it is now "foo\nbar" (if the WRAP flag
is set on the line)
* capture-pane option to preserve spaces but not join lines
* improve word and line selection in copy mode (for example when dragging
it should select by word. compare how xterm works. GitHub issue 682)
- layout stuff
* way to tag a layout as a number/name
* maybe keep last layout + size around and if size reverts just put it
back
* revamp layouts: they are too complicated, should be more closely
integrated, should support hints, layout sets should just be a
special case of custom layouts, and we should support panes that are
not attached to a cell at all. this could be the time to introduce
panelink to replace layout_cell
* way to set hints/limits about pane size for resizing
* panning over window (window larger than visible)
* a mode where one application can cross two panes (ie x|y, width =
COLUMNS/2 but height = ROWS * 2)
* separate active panes for different clients
- code cleanup
* instead of separate window and session options, just one master
options list with each option having a type (window or session), then
options on window, on session, and global. for window options we look
window->session->global, and for session we look session->global.
problem: what about windows in multiple sessions? there are contexts
where we do not know which session, or where multiple choices makes
no sense... could at least have one global list for all types of
global options and keep separate window,session lists
* the way pane, window, session destroy is handled is too complicated
and the distinction between session.c, window.c and server-fn.c
functions is not clear. could we just have kill_pane(),
kill_window(), unlink_window(), kill_session() that fix up all data
structures (flagging sessions as dead) and return a value to say
whether clients need to be checked for dead sessions? sort of like
session_detach now but more so. or some other scheme to make it
simpler and clearer? also would be nice to remove/rename server-fn.c
* more readable way to work out the various things commands need to
know about the client, notably:
- is this the config file? (cmdq->c == NULL)
- is this a command client? (cmdq->c != NULL &&
cmdq->c->session == NULL)
- is this a control client?
- can i do stdin or stdout to this client?
or even guarantee that cmdq->c != NULL and provide a better way to
tell when in the config file - then we use cmdq->c if we need a
client w/o a session else cmd_current_client
- miscellaneous
* way to keep a job running just read its last line of output for #()
* link panes into multiple windows
* live update: server started with -U connects to server, requests
sessions and windows, receives file descriptors
* there are inconsistencies in what we get from old shell and what
comes from config for new sessions and windows. likewise, panes and
jobs and run-shell and lock command all start with slightly different
environments
* multiline status line? separate command prompt and status line?
* automatic pane logging
* marks in history, automatically add (move?) one when pane is changed
* this doesn't work, need pane reference count probably:
bind -n DoubleClick3Status confirm-before -p "kill-window #I? (y/n)" kill-window
- hooks
* more hooks for various things
* finish after hooks for special commands
* multiple hooks with the same name?
* finish hooks for notifys
* for session_closed, if no sessions at all, perhaps fake up a temporary one

183
alerts.c
View File

@@ -30,13 +30,13 @@ static int alerts_enabled(struct window *, int);
static void alerts_callback(int, short, void *);
static void alerts_reset(struct window *);
static int alerts_action_applies(struct winlink *, const char *);
static int alerts_check_all(struct window *);
static int alerts_check_bell(struct window *);
static int alerts_check_activity(struct window *);
static int alerts_check_silence(struct window *);
static void printflike(2, 3) alerts_set_message(struct session *, const char *,
...);
static void alerts_ring_bell(struct session *);
static void alerts_set_message(struct winlink *, const char *,
const char *);
static TAILQ_HEAD(, window) alerts_list = TAILQ_HEAD_INITIALIZER(alerts_list);
@@ -46,7 +46,6 @@ alerts_timer(__unused int fd, __unused short events, void *arg)
struct window *w = arg;
log_debug("@%u alerts timer expired", w->id);
alerts_reset(w);
alerts_queue(w, WINDOW_SILENCE);
}
@@ -64,17 +63,38 @@ alerts_callback(__unused int fd, __unused short events, __unused void *arg)
TAILQ_REMOVE(&alerts_list, w, alerts_entry);
w->flags &= ~WINDOW_ALERTFLAGS;
window_remove_ref(w);
window_remove_ref(w, __func__);
}
alerts_fired = 0;
}
static int
alerts_action_applies(struct winlink *wl, const char *name)
{
int action;
/*
* {bell,activity,silence}-action determines when to alert: none means
* nothing happens, current means only do something for the current
* window and other means only for windows other than the current.
*/
action = options_get_number(wl->session->options, name);
if (action == ALERT_ANY)
return (1);
if (action == ALERT_CURRENT)
return (wl == wl->session->curw);
if (action == ALERT_OTHER)
return (wl != wl->session->curw);
return (0);
}
static int
alerts_check_all(struct window *w)
{
int alerts;
alerts = alerts_check_bell(w);
alerts = alerts_check_bell(w);
alerts |= alerts_check_activity(w);
alerts |= alerts_check_silence(w);
return (alerts);
@@ -92,8 +112,10 @@ alerts_check_session(struct session *s)
static int
alerts_enabled(struct window *w, int flags)
{
if (flags & WINDOW_BELL)
return (1);
if (flags & WINDOW_BELL) {
if (options_get_number(w->options, "monitor-bell"))
return (1);
}
if (flags & WINDOW_ACTIVITY) {
if (options_get_number(w->options, "monitor-activity"))
return (1);
@@ -119,6 +141,9 @@ alerts_reset(struct window *w)
{
struct timeval tv;
if (!event_initialized(&w->alerts_timer))
evtimer_set(&w->alerts_timer, alerts_timer, w);
w->flags &= ~WINDOW_SILENCE;
event_del(&w->alerts_timer);
@@ -133,85 +158,61 @@ alerts_reset(struct window *w)
void
alerts_queue(struct window *w, int flags)
{
if (w->flags & WINDOW_ACTIVITY)
alerts_reset(w);
if (!event_initialized(&w->alerts_timer))
evtimer_set(&w->alerts_timer, alerts_timer, w);
alerts_reset(w);
if ((w->flags & flags) != flags) {
w->flags |= flags;
log_debug("@%u alerts flags added %#x", w->id, flags);
}
if (!w->alerts_queued) {
w->alerts_queued = 1;
TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
w->references++;
}
if (alerts_enabled(w, flags)) {
if (!w->alerts_queued) {
w->alerts_queued = 1;
TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
window_add_ref(w, __func__);
}
if (!alerts_fired && alerts_enabled(w, flags)) {
log_debug("alerts check queued (by @%u)", w->id);
event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
alerts_fired = 1;
if (!alerts_fired) {
log_debug("alerts check queued (by @%u)", w->id);
event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
alerts_fired = 1;
}
}
}
static int
alerts_check_bell(struct window *w)
{
struct window *ws;
struct winlink *wl;
struct session *s;
struct client *c;
int action, visual;
if (~w->flags & WINDOW_BELL)
return (0);
if (!options_get_number(w->options, "monitor-bell"))
return (0);
TAILQ_FOREACH(wl, &w->winlinks, wentry)
wl->session->flags &= ~SESSION_ALERTED;
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
if (wl->flags & WINLINK_BELL)
continue;
/*
* Bells are allowed even if there is an existing bell (so do
* not check WINLINK_BELL).
*/
s = wl->session;
if (s->curw != wl) {
wl->flags |= WINLINK_BELL;
notify_winlink("alert-bell", s, wl);
server_status_session(s);
}
if (!alerts_action_applies(wl, "bell-action"))
continue;
notify_winlink("alert-bell", wl);
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
action = options_get_number(s->options, "bell-action");
if (action == BELL_NONE)
return (0);
visual = options_get_number(s->options, "visual-bell");
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != s || c->flags & CLIENT_CONTROL)
continue;
ws = c->session->curw->window;
if (action == BELL_CURRENT && ws != w)
action = BELL_NONE;
if (action == BELL_OTHER && ws != w)
action = BELL_NONE;
if (!visual) {
if (action != BELL_NONE)
tty_putcode(&c->tty, TTYC_BEL);
continue;
}
if (action == BELL_CURRENT)
status_message_set(c, "Bell in current window");
else if (action != BELL_NONE) {
status_message_set(c, "Bell in window %d",
wl->idx);
}
}
alerts_set_message(wl, "Bell", "visual-bell");
}
return (WINDOW_BELL);
@@ -235,20 +236,19 @@ alerts_check_activity(struct window *w)
if (wl->flags & WINLINK_ACTIVITY)
continue;
s = wl->session;
if (s->curw == wl)
if (s->curw != wl) {
wl->flags |= WINLINK_ACTIVITY;
server_status_session(s);
}
if (!alerts_action_applies(wl, "activity-action"))
continue;
wl->flags |= WINLINK_ACTIVITY;
notify_winlink("alert-activity", s, wl);
notify_winlink("alert-activity", wl);
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
if (options_get_number(s->options, "bell-on-alert"))
alerts_ring_bell(s);
if (options_get_number(s->options, "visual-activity"))
alerts_set_message(s, "Activity in window %d", wl->idx);
alerts_set_message(wl, "Activity", "visual-activity");
}
return (WINDOW_ACTIVITY);
@@ -262,7 +262,7 @@ alerts_check_silence(struct window *w)
if (~w->flags & WINDOW_SILENCE)
return (0);
if (!options_get_number(w->options, "monitor-silence"))
if (options_get_number(w->options, "monitor-silence") == 0)
return (0);
TAILQ_FOREACH(wl, &w->winlinks, wentry)
@@ -272,51 +272,52 @@ alerts_check_silence(struct window *w)
if (wl->flags & WINLINK_SILENCE)
continue;
s = wl->session;
if (s->curw == wl)
if (s->curw != wl) {
wl->flags |= WINLINK_SILENCE;
server_status_session(s);
}
if (!alerts_action_applies(wl, "silence-action"))
continue;
wl->flags |= WINLINK_SILENCE;
notify_winlink("alert-silence", s, wl);
notify_winlink("alert-silence", wl);
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
if (options_get_number(s->options, "bell-on-alert"))
alerts_ring_bell(s);
if (!options_get_number(s->options, "visual-silence"))
alerts_set_message(s, "Silence in window %d", wl->idx);
alerts_set_message(wl, "Silence", "visual-silence");
}
return (WINDOW_SILENCE);
}
static void
alerts_set_message(struct session *s, const char *fmt, ...)
alerts_set_message(struct winlink *wl, const char *type, const char *option)
{
struct client *c;
va_list ap;
char *message;
int visual;
va_start(ap, fmt);
xvasprintf(&message, fmt, ap);
va_end(ap);
/*
* We have found an alert (bell, activity or silence), so we need to
* pass it on to the user. For each client attached to this session,
* decide whether a bell, message or both is needed.
*
* If visual-{bell,activity,silence} is on, then a message is
* substituted for a bell; if it is off, a bell is sent as normal; both
* mean both a bell and message is sent.
*/
visual = options_get_number(wl->session->options, option);
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == s)
status_message_set(c, "%s", message);
}
if (c->session != wl->session || c->flags & CLIENT_CONTROL)
continue;
free(message);
}
static void
alerts_ring_bell(struct session *s)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == s && !(c->flags & CLIENT_CONTROL))
if (visual == VISUAL_OFF || visual == VISUAL_BOTH)
tty_putcode(&c->tty, TTYC_BEL);
if (visual == VISUAL_OFF)
continue;
if (c->session->curw == wl)
status_message_set(c, "%s in current window", type);
else
status_message_set(c, "%s in window %d", type, wl->idx);
}
}

View File

@@ -28,13 +28,18 @@
* Manipulate command arguments.
*/
struct args_value {
char *value;
TAILQ_ENTRY(args_value) entry;
};
TAILQ_HEAD(args_values, args_value);
struct args_entry {
u_char flag;
char *value;
struct args_values values;
RB_ENTRY(args_entry) entry;
};
static void args_set(struct args *, u_char, const char *);
static struct args_entry *args_find(struct args *, u_char);
static int args_cmp(struct args_entry *, struct args_entry *);
@@ -93,12 +98,18 @@ args_free(struct args *args)
{
struct args_entry *entry;
struct args_entry *entry1;
struct args_value *value;
struct args_value *value1;
cmd_free_argv(args->argc, args->argv);
RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
RB_REMOVE(args_tree, &args->tree, entry);
free(entry->value);
TAILQ_FOREACH_SAFE(value, &entry->values, entry, value1) {
TAILQ_REMOVE(&entry->values, value, entry);
free(value->value);
free(value);
}
free(entry);
}
@@ -124,22 +135,53 @@ args_print_add(char **buf, size_t *len, const char *fmt, ...)
free(s);
}
/* Add value to string. */
static void
args_print_add_value(char **buf, size_t *len, struct args_entry *entry,
struct args_value *value)
{
char *escaped;
if (**buf != '\0')
args_print_add(buf, len, " -%c ", entry->flag);
else
args_print_add(buf, len, "-%c ", entry->flag);
escaped = args_escape(value->value);
args_print_add(buf, len, "%s", escaped);
free(escaped);
}
/* Add argument to string. */
static void
args_print_add_argument(char **buf, size_t *len, const char *argument)
{
char *escaped;
if (**buf != '\0')
args_print_add(buf, len, " ");
escaped = args_escape(argument);
args_print_add(buf, len, "%s", escaped);
free(escaped);
}
/* Print a set of arguments. */
char *
args_print(struct args *args)
{
size_t len;
char *buf, *escaped;
int i, flags;
char *buf;
int i;
struct args_entry *entry;
static const char quoted[] = " #\"';$";
struct args_value *value;
len = 1;
buf = xcalloc(1, len);
/* Process the flags first. */
RB_FOREACH(entry, args_tree, &args->tree) {
if (entry->value != NULL)
if (!TAILQ_EMPTY(&entry->values))
continue;
if (*buf == '\0')
@@ -149,69 +191,79 @@ args_print(struct args *args)
/* Then the flags with arguments. */
RB_FOREACH(entry, args_tree, &args->tree) {
if (entry->value == NULL)
continue;
if (*buf != '\0')
args_print_add(&buf, &len, " -%c ", entry->flag);
else
args_print_add(&buf, &len, "-%c ", entry->flag);
flags = VIS_OCTAL|VIS_TAB|VIS_NL;
if (entry->value[strcspn(entry->value, quoted)] != '\0')
flags |= VIS_DQ;
utf8_stravis(&escaped, entry->value, flags);
if (flags & VIS_DQ)
args_print_add(&buf, &len, "\"%s\"", escaped);
else
args_print_add(&buf, &len, "%s", escaped);
free(escaped);
TAILQ_FOREACH(value, &entry->values, entry)
args_print_add_value(&buf, &len, entry, value);
}
/* And finally the argument vector. */
for (i = 0; i < args->argc; i++) {
if (*buf != '\0')
args_print_add(&buf, &len, " ");
flags = VIS_OCTAL|VIS_TAB|VIS_NL;
if (args->argv[i][strcspn(args->argv[i], quoted)] != '\0')
flags |= VIS_DQ;
utf8_stravis(&escaped, args->argv[i], flags);
if (flags & VIS_DQ)
args_print_add(&buf, &len, "\"%s\"", escaped);
else
args_print_add(&buf, &len, "%s", escaped);
free(escaped);
}
for (i = 0; i < args->argc; i++)
args_print_add_argument(&buf, &len, args->argv[i]);
return (buf);
}
/* Escape an argument. */
char *
args_escape(const char *s)
{
static const char quoted[] = " #\"';${}";
char *escaped, *result;
int flags;
if (*s == '\0')
return (xstrdup(s));
if ((strchr(quoted, s[0]) != NULL || s[0] == '~') && s[1] == '\0') {
xasprintf(&escaped, "\\%c", s[0]);
return (escaped);
}
flags = VIS_OCTAL|VIS_TAB|VIS_NL;
if (s[strcspn(s, quoted)] != '\0')
flags |= VIS_DQ;
utf8_stravis(&escaped, s, flags);
if (flags & VIS_DQ) {
if (*escaped == '~')
xasprintf(&result, "\"\\%s\"", escaped);
else
xasprintf(&result, "\"%s\"", escaped);
} else {
if (*escaped == '~')
xasprintf(&result, "\\%s", escaped);
else
result = xstrdup(escaped);
}
free(escaped);
return (result);
}
/* Return if an argument is present. */
int
args_has(struct args *args, u_char ch)
{
return (args_find(args, ch) == NULL ? 0 : 1);
return (args_find(args, ch) != NULL);
}
/* Set argument value in the arguments tree. */
static void
args_set(struct args *args, u_char ch, const char *value)
void
args_set(struct args *args, u_char ch, const char *s)
{
struct args_entry *entry;
struct args_value *value;
/* Replace existing argument. */
if ((entry = args_find(args, ch)) != NULL) {
free(entry->value);
entry->value = NULL;
} else {
entry = args_find(args, ch);
if (entry == NULL) {
entry = xcalloc(1, sizeof *entry);
entry->flag = ch;
TAILQ_INIT(&entry->values);
RB_INSERT(args_tree, &args->tree, entry);
}
if (value != NULL)
entry->value = xstrdup(value);
if (s != NULL) {
value = xcalloc(1, sizeof *value);
value->value = xstrdup(s);
TAILQ_INSERT_TAIL(&entry->values, value, entry);
}
}
/* Get argument value. Will be NULL if it isn't present. */
@@ -222,7 +274,34 @@ args_get(struct args *args, u_char ch)
if ((entry = args_find(args, ch)) == NULL)
return (NULL);
return (entry->value);
return (TAILQ_LAST(&entry->values, args_values)->value);
}
/* Get first value in argument. */
const char *
args_first_value(struct args *args, u_char ch, struct args_value **value)
{
struct args_entry *entry;
if ((entry = args_find(args, ch)) == NULL)
return (NULL);
*value = TAILQ_FIRST(&entry->values);
if (*value == NULL)
return (NULL);
return ((*value)->value);
}
/* Get next value in argument. */
const char *
args_next_value(struct args_value **value)
{
if (*value == NULL)
return (NULL);
*value = TAILQ_NEXT(*value, entry);
if (*value == NULL)
return (NULL);
return ((*value)->value);
}
/* Convert an argument value to a number. */
@@ -233,13 +312,15 @@ args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
const char *errstr;
long long ll;
struct args_entry *entry;
struct args_value *value;
if ((entry = args_find(args, ch)) == NULL) {
*cause = xstrdup("missing");
return (0);
}
value = TAILQ_LAST(&entry->values, args_values);
ll = strtonum(entry->value, minval, maxval, &errstr);
ll = strtonum(value->value, minval, maxval, &errstr);
if (errstr != NULL) {
*cause = xstrdup(errstr);
return (0);

View File

@@ -25,13 +25,13 @@
const char *
attributes_tostring(int attr)
{
static char buf[128];
static char buf[512];
size_t len;
if (attr == 0)
return ("none");
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s",
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s",
(attr & GRID_ATTR_BRIGHT) ? "bright," : "",
(attr & GRID_ATTR_DIM) ? "dim," : "",
(attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "",
@@ -39,7 +39,12 @@ attributes_tostring(int attr)
(attr & GRID_ATTR_REVERSE) ? "reverse," : "",
(attr & GRID_ATTR_HIDDEN) ? "hidden," : "",
(attr & GRID_ATTR_ITALICS) ? "italics," : "",
(attr & GRID_ATTR_STRIKETHROUGH) ? "strikethrough," : "");
(attr & GRID_ATTR_STRIKETHROUGH) ? "strikethrough," : "",
(attr & GRID_ATTR_UNDERSCORE_2) ? "double-underscore," : "",
(attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "",
(attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-underscore," : "",
(attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : "",
(attr & GRID_ATTR_OVERLINE) ? "overline," : "");
if (len > 0)
buf[len - 1] = '\0';
@@ -52,6 +57,26 @@ attributes_fromstring(const char *str)
const char delimiters[] = " ,|";
int attr;
size_t end;
u_int i;
struct {
const char* name;
int attr;
} table[] = {
{ "bright", GRID_ATTR_BRIGHT },
{ "bold", GRID_ATTR_BRIGHT },
{ "dim", GRID_ATTR_DIM },
{ "underscore", GRID_ATTR_UNDERSCORE },
{ "blink", GRID_ATTR_BLINK },
{ "reverse", GRID_ATTR_REVERSE },
{ "hidden", GRID_ATTR_HIDDEN },
{ "italics", GRID_ATTR_ITALICS },
{ "strikethrough", GRID_ATTR_STRIKETHROUGH },
{ "double-underscore", GRID_ATTR_UNDERSCORE_2 },
{ "curly-underscore", GRID_ATTR_UNDERSCORE_3 },
{ "dotted-underscore", GRID_ATTR_UNDERSCORE_4 },
{ "dashed-underscore", GRID_ATTR_UNDERSCORE_5 },
{ "overline", GRID_ATTR_OVERLINE }
};
if (*str == '\0' || strcspn(str, delimiters) == 0)
return (-1);
@@ -64,24 +89,15 @@ attributes_fromstring(const char *str)
attr = 0;
do {
end = strcspn(str, delimiters);
if ((end == 6 && strncasecmp(str, "bright", end) == 0) ||
(end == 4 && strncasecmp(str, "bold", end) == 0))
attr |= GRID_ATTR_BRIGHT;
else if (end == 3 && strncasecmp(str, "dim", end) == 0)
attr |= GRID_ATTR_DIM;
else if (end == 10 && strncasecmp(str, "underscore", end) == 0)
attr |= GRID_ATTR_UNDERSCORE;
else if (end == 5 && strncasecmp(str, "blink", end) == 0)
attr |= GRID_ATTR_BLINK;
else if (end == 7 && strncasecmp(str, "reverse", end) == 0)
attr |= GRID_ATTR_REVERSE;
else if (end == 6 && strncasecmp(str, "hidden", end) == 0)
attr |= GRID_ATTR_HIDDEN;
else if (end == 7 && strncasecmp(str, "italics", end) == 0)
attr |= GRID_ATTR_ITALICS;
else if (end == 13 && strncasecmp(str, "strikethrough", end) == 0)
attr |= GRID_ATTR_STRIKETHROUGH;
else
for (i = 0; i < nitems(table); i++) {
if (end != strlen(table[i].name))
continue;
if (strncasecmp(str, table[i].name, end) == 0) {
attr |= table[i].attr;
break;
}
}
if (i == nitems(table))
return (-1);
str += end + strspn(str + end, delimiters);
} while (*str != '\0');

176
cfg.c
View File

@@ -23,15 +23,23 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
static char *cfg_file;
int cfg_finished;
static char **cfg_causes;
static u_int cfg_ncauses;
struct client *cfg_client;
struct client *cfg_client;
static char *cfg_file;
int cfg_finished;
static char **cfg_causes;
static u_int cfg_ncauses;
static struct cmdq_item *cfg_item;
static enum cmd_retval
cfg_client_done(__unused struct cmdq_item *item, __unused void *data)
{
if (!cfg_finished)
return (CMD_RETURN_WAIT);
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cfg_done(__unused struct cmdq_item *item, __unused void *data)
@@ -43,8 +51,11 @@ cfg_done(__unused struct cmdq_item *item, __unused void *data)
if (!RB_EMPTY(&sessions))
cfg_show_causes(RB_MIN(sessions, &sessions));
if (cfg_client != NULL)
server_client_unref(cfg_client);
if (cfg_item != NULL)
cfg_item->flags &= ~CMDQ_WAITING;
status_prompt_load_history();
return (CMD_RETURN_NORMAL);
}
@@ -59,112 +70,87 @@ void
start_cfg(void)
{
const char *home;
int quiet = 0;
int flags = 0;
struct client *c;
cfg_client = TAILQ_FIRST(&clients);
if (cfg_client != NULL)
cfg_client->references++;
/*
* Configuration files are loaded without a client, so commands are run
* in the global queue with item->client NULL.
*
* However, we must block the initial client (but just the initial
* client) so that its command runs after the configuration is loaded.
* Because start_cfg() is called so early, we can be sure the client's
* command queue is currently empty and our callback will be at the
* front - we need to get in before MSG_COMMAND.
*/
cfg_client = c = TAILQ_FIRST(&clients);
if (c != NULL) {
cfg_item = cmdq_get_callback(cfg_client_done, NULL);
cmdq_append(c, cfg_item);
}
load_cfg(TMUX_CONF, cfg_client, NULL, 1);
if (cfg_file == NULL)
load_cfg(TMUX_CONF, NULL, NULL, CMD_PARSE_QUIET, NULL);
if (cfg_file == NULL && (home = find_home()) != NULL) {
xasprintf(&cfg_file, "%s/.tmux.conf", home);
quiet = 1;
flags = CMD_PARSE_QUIET;
}
if (cfg_file != NULL)
load_cfg(cfg_file, cfg_client, NULL, quiet);
load_cfg(cfg_file, NULL, NULL, flags, NULL);
cmdq_append(cfg_client, cmdq_get_callback(cfg_done, NULL));
cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
}
int
load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
struct cmdq_item **new_item)
{
FILE *f;
const char delim[3] = { '\\', '\\', '\0' };
u_int found = 0;
size_t line = 0;
char *buf, *cause1, *p, *q, *s;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
int condition = 0;
struct format_tree *ft;
struct cmd_parse_input pi;
struct cmd_parse_result *pr;
struct cmdq_item *new_item0;
if (new_item != NULL)
*new_item = NULL;
log_debug("loading %s", path);
if ((f = fopen(path, "rb")) == NULL) {
if (errno == ENOENT && quiet)
if (errno == ENOENT && (flags & CMD_PARSE_QUIET))
return (0);
cfg_add_cause("%s: %s", path, strerror(errno));
return (-1);
}
while ((buf = fparseln(f, NULL, &line, delim, 0)) != NULL) {
log_debug("%s: %s", path, buf);
memset(&pi, 0, sizeof pi);
pi.flags = flags;
pi.file = path;
pi.line = 1;
p = buf;
while (isspace((u_char)*p))
p++;
if (*p == '\0') {
free(buf);
continue;
}
q = p + strlen(p) - 1;
while (q != p && isspace((u_char)*q))
*q-- = '\0';
if (condition != 0 && strcmp(p, "%endif") == 0) {
condition = 0;
continue;
}
if (strncmp(p, "%if ", 4) == 0) {
if (condition != 0) {
cfg_add_cause("%s:%zu: nested %%if", path,
line);
continue;
}
ft = format_create(NULL, FORMAT_NONE, FORMAT_NOJOBS);
s = p + 3;
while (isspace((u_char)*s))
s++;
s = format_expand(ft, s);
if (*s != '\0' && (s[0] != '0' || s[1] != '\0'))
condition = 1;
else
condition = -1;
free(s);
format_free(ft);
continue;
}
if (condition == -1)
continue;
cmdlist = cmd_string_parse(p, path, line, &cause1);
if (cmdlist == NULL) {
free(buf);
if (cause1 == NULL)
continue;
cfg_add_cause("%s:%zu: %s", path, line, cause1);
free(cause1);
continue;
}
free(buf);
if (cmdlist == NULL)
continue;
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
if (item != NULL)
cmdq_insert_after(item, new_item);
else
cmdq_append(c, new_item);
cmd_list_free(cmdlist);
found++;
}
pr = cmd_parse_from_file(f, &pi);
fclose(f);
if (pr->status == CMD_PARSE_EMPTY)
return (0);
if (pr->status == CMD_PARSE_ERROR) {
cfg_add_cause("%s", pr->error);
free(pr->error);
return (-1);
}
if (flags & CMD_PARSE_PARSEONLY) {
cmd_list_free(pr->cmdlist);
return (0);
}
return (found);
new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
if (item != NULL)
cmdq_insert_after(item, new_item0);
else
cmdq_append(c, new_item0);
cmd_list_free(pr->cmdlist);
if (new_item != NULL)
*new_item = new_item0;
return (0);
}
void
@@ -200,15 +186,17 @@ cfg_print_causes(struct cmdq_item *item)
void
cfg_show_causes(struct session *s)
{
struct window_pane *wp;
u_int i;
struct window_pane *wp;
struct window_mode_entry *wme;
u_int i;
if (s == NULL || cfg_ncauses == 0)
return;
wp = s->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp);
wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
for (i = 0; i < cfg_ncauses; i++) {
window_copy_add(wp, "%s", cfg_causes[i]);
free(cfg_causes[i]);

View File

@@ -17,11 +17,10 @@
*/
#include <sys/types.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <errno.h>
#include <event.h>
@@ -63,7 +62,7 @@ static void client_write(int, const char *, size_t);
static void client_signal(int);
static void client_dispatch(struct imsg *, void *);
static void client_dispatch_attached(struct imsg *);
static void client_dispatch_wait(struct imsg *, const char *);
static void client_dispatch_wait(struct imsg *);
static const char *client_exit_message(void);
/*
@@ -156,7 +155,7 @@ retry:
close(lockfd);
return (-1);
}
fd = server_start(base, lockfd, lockfile);
fd = server_start(client_proc, base, lockfd, lockfile);
}
if (locked && lockfd >= 0) {
@@ -214,17 +213,15 @@ client_exit_message(void)
/* Client main loop. */
int
client_main(struct event_base *base, int argc, char **argv, int flags,
const char *shellcmd)
client_main(struct event_base *base, int argc, char **argv, int flags)
{
struct cmd_parse_result *pr;
struct cmd *cmd;
struct cmd_list *cmdlist;
struct msg_command_data *data;
int cmdflags, fd, i;
const char *ttynam, *cwd;
pid_t ppid;
enum msgtype msg;
char *cause, path[PATH_MAX];
struct termios tio, saved_tio;
size_t size;
@@ -236,7 +233,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
/* Set up the initial command. */
cmdflags = 0;
if (shellcmd != NULL) {
if (shell_command != NULL) {
msg = MSG_SHELL;
cmdflags = CMD_STARTSERVER;
} else if (argc == 0) {
@@ -250,18 +247,20 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
* later in server) but it is necessary to get the start server
* flag.
*/
cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause);
if (cmdlist != NULL) {
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
pr = cmd_parse_from_arguments(argc, argv, NULL);
if (pr->status == CMD_PARSE_SUCCESS) {
TAILQ_FOREACH(cmd, &pr->cmdlist->list, qentry) {
if (cmd->entry->flags & CMD_STARTSERVER)
cmdflags |= CMD_STARTSERVER;
}
cmd_list_free(cmdlist);
}
cmd_list_free(pr->cmdlist);
} else
free(pr->error);
}
/* Create client process structure (starts logging). */
client_proc = proc_start("client", base, 0, client_signal);
client_proc = proc_start("client");
proc_set_signals(client_proc, client_signal);
/* Initialize the client socket and start the server. */
fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
@@ -275,14 +274,11 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
}
return (1);
}
client_peer = proc_add_peer(client_proc, fd, client_dispatch,
(void *)shellcmd);
client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL);
/* Save these before pledge(). */
if ((cwd = getcwd(path, sizeof path)) == NULL) {
if ((cwd = find_home()) == NULL)
cwd = "/";
}
if ((cwd = find_cwd()) == NULL && (cwd = find_home()) == NULL)
cwd = "/";
if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
ttynam = "";
@@ -339,6 +335,10 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
size = 0;
for (i = 0; i < argc; i++)
size += strlen(argv[i]) + 1;
if (size > MAX_IMSGSIZE - (sizeof *data)) {
fprintf(stderr, "command too long\n");
return (1);
}
data = xmalloc((sizeof *data) + size);
/* Prepare command for server. */
@@ -367,7 +367,6 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
if (client_exittype == MSG_EXEC) {
if (client_flags & CLIENT_CONTROLCONTROL)
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
clear_signals(0);
client_exec(client_execshell, client_execcmd);
}
@@ -451,6 +450,7 @@ client_write(int fd, const char *data, size_t size)
{
ssize_t used;
log_debug("%s: %.*s", __func__, (int)size, data);
while (size != 0) {
used = write(fd, data, size);
if (used == -1) {
@@ -483,6 +483,8 @@ client_exec(const char *shell, const char *shellcmd)
xasprintf(&argv0, "%s", name);
setenv("SHELL", shell, 1);
proc_clear_signals(client_proc, 1);
setblocking(STDIN_FILENO, 1);
setblocking(STDOUT_FILENO, 1);
setblocking(STDERR_FILENO, 1);
@@ -534,7 +536,7 @@ client_signal(int sig)
/* Callback for client read events. */
static void
client_dispatch(struct imsg *imsg, void *arg)
client_dispatch(struct imsg *imsg, __unused void *arg)
{
if (imsg == NULL) {
client_exitreason = CLIENT_EXIT_LOST_SERVER;
@@ -546,12 +548,12 @@ client_dispatch(struct imsg *imsg, void *arg)
if (client_attached)
client_dispatch_attached(imsg);
else
client_dispatch_wait(imsg, arg);
client_dispatch_wait(imsg);
}
/* Dispatch imsgs when in wait state (before MSG_READY). */
static void
client_dispatch_wait(struct imsg *imsg, const char *shellcmd)
client_dispatch_wait(struct imsg *imsg)
{
char *data;
ssize_t datalen;
@@ -630,8 +632,7 @@ client_dispatch_wait(struct imsg *imsg, const char *shellcmd)
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_SHELL string");
clear_signals(0);
client_exec(data, shellcmd);
client_exec(data, shell_command);
/* NOTREACHED */
case MSG_DETACH:
case MSG_DETACHKILL:

View File

@@ -40,20 +40,23 @@ const struct cmd_entry cmd_attach_session_entry = {
.args = { "c:dErt:", 0, 0 },
.usage = "[-dEr] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION_WITHPANE,
/* -t is special */
.flags = CMD_STARTSERVER,
.exec = cmd_attach_session_exec
};
enum cmd_retval
cmd_attach_session(struct cmdq_item *item, int dflag, int rflag,
const char *cflag, int Eflag)
cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
int rflag, const char *cflag, int Eflag)
{
struct session *s = item->state.tflag.s;
struct cmd_find_state *current = &item->shared->current;
enum cmd_find_type type;
int flags;
struct client *c = item->client, *c_loop;
struct winlink *wl = item->state.tflag.wl;
struct window_pane *wp = item->state.tflag.wp;
struct session *s;
struct winlink *wl;
struct window_pane *wp;
char *cause;
if (RB_EMPTY(&sessions)) {
@@ -69,10 +72,27 @@ cmd_attach_session(struct cmdq_item *item, int dflag, int rflag,
return (CMD_RETURN_ERROR);
}
if (tflag != NULL && tflag[strcspn(tflag, ":.")] != '\0') {
type = CMD_FIND_PANE;
flags = 0;
} else {
type = CMD_FIND_SESSION;
flags = CMD_FIND_PREFER_UNATTACHED;
}
if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
return (CMD_RETURN_ERROR);
s = item->target.s;
wl = item->target.wl;
wp = item->target.wp;
if (wl != NULL) {
if (wp != NULL)
window_set_active_pane(wp->window, wp);
window_set_active_pane(wp->window, wp, 1);
session_set_current(s, wl);
if (wp != NULL)
cmd_find_from_winlink_pane(current, wl, wp, 0);
else
cmd_find_from_winlink(current, wl, 0);
}
if (cflag != NULL) {
@@ -80,6 +100,7 @@ cmd_attach_session(struct cmdq_item *item, int dflag, int rflag,
s->cwd = format_single(item, cflag, c, s, wl, wp);
}
c->last_session = c->session;
if (c->session != NULL) {
if (dflag) {
TAILQ_FOREACH(c_loop, &clients, entry) {
@@ -92,8 +113,9 @@ cmd_attach_session(struct cmdq_item *item, int dflag, int rflag,
environ_update(s->options, c->environ, s->environ);
c->session = s;
if (!item->repeat)
if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
@@ -121,6 +143,7 @@ cmd_attach_session(struct cmdq_item *item, int dflag, int rflag,
c->session = s;
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
@@ -145,6 +168,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
return (cmd_attach_session(item, args_has(args, 'd'),
args_has(args, 'r'), args_get(args, 'c'), args_has(args, 'E')));
return (cmd_attach_session(item, args_get(args, 't'),
args_has(args, 'd'), args_has(args, 'r'), args_get(args, 'c'),
args_has(args, 'E')));
}

View File

@@ -44,15 +44,16 @@ const struct cmd_entry cmd_bind_key_entry = {
static enum cmd_retval
cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
char *cause;
struct cmd_list *cmdlist;
key_code key;
const char *tablename;
struct args *args = self->args;
key_code key;
const char *tablename;
struct cmd_parse_result *pr;
char **argv = args->argv;
int argc = args->argc;
key = key_string_lookup_string(args->argv[0]);
key = key_string_lookup_string(argv[0]);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
cmdq_error(item, "unknown key: %s", args->argv[0]);
cmdq_error(item, "unknown key: %s", argv[0]);
return (CMD_RETURN_ERROR);
}
@@ -63,14 +64,21 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
else
tablename = "prefix";
cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0,
&cause);
if (cmdlist == NULL) {
cmdq_error(item, "%s", cause);
free(cause);
if (argc == 2)
pr = cmd_parse_from_string(argv[1], NULL);
else
pr = cmd_parse_from_arguments(argc - 1, argv + 1, NULL);
switch (pr->status) {
case CMD_PARSE_EMPTY:
cmdq_error(item, "empty command");
return (CMD_RETURN_ERROR);
case CMD_PARSE_ERROR:
cmdq_error(item, "%s", pr->error);
free(pr->error);
return (CMD_RETURN_ERROR);
case CMD_PARSE_SUCCESS:
break;
}
key_bindings_add(tablename, key, args_has(args, 'r'), cmdlist);
key_bindings_add(tablename, key, args_has(args, 'r'), pr->cmdlist);
return (CMD_RETURN_NORMAL);
}

View File

@@ -35,10 +35,11 @@ const struct cmd_entry cmd_break_pane_entry = {
.alias = "breakp",
.args = { "dPF:n:s:t:", 0, 0 },
.usage = "[-dP] [-F format] [-n window-name] [-s src-pane] [-t dst-window]",
.usage = "[-dP] [-F format] [-n window-name] [-s src-pane] "
"[-t dst-window]",
.sflag = CMD_PANE,
.tflag = CMD_WINDOW_INDEX,
.source = { 's', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
.flags = 0,
.exec = cmd_break_pane_exec
@@ -48,14 +49,15 @@ static enum cmd_retval
cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct winlink *wl = item->state.sflag.wl;
struct session *src_s = item->state.sflag.s;
struct session *dst_s = item->state.tflag.s;
struct window_pane *wp = item->state.sflag.wp;
struct cmd_find_state *current = &item->shared->current;
struct client *c = cmd_find_client(item, NULL, 1);
struct winlink *wl = item->source.wl;
struct session *src_s = item->source.s;
struct session *dst_s = item->target.s;
struct window_pane *wp = item->source.wp;
struct window *w = wl->window;
char *name, *cause;
int idx = item->state.tflag.idx;
int idx = item->target.idx;
const char *template;
char *cp;
@@ -74,7 +76,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
window_lost_pane(w, wp);
layout_close_pane(wp);
w = wp->window = window_create(dst_s->sx, dst_s->sy);
w = wp->window = window_create(w->sx, w->sy);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp;
@@ -93,8 +95,10 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
if (idx == -1)
idx = -1 - options_get_number(dst_s->options, "base-index");
wl = session_attach(dst_s, w, idx, &cause); /* can't fail */
if (!args_has(self->args, 'd'))
if (!args_has(self->args, 'd')) {
session_select(dst_s, wl->idx);
cmd_find_from_session(current, dst_s, 0);
}
server_redraw_session(src_s);
if (src_s != dst_s)

View File

@@ -41,9 +41,9 @@ const struct cmd_entry cmd_capture_pane_entry = {
.args = { "ab:CeE:JpPqS:t:", 0, 0 },
.usage = "[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] "
"[-S start-line]" CMD_TARGET_PANE_USAGE,
"[-S start-line] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_capture_pane_exec
@@ -56,7 +56,7 @@ const struct cmd_entry cmd_clear_history_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_capture_pane_exec
@@ -193,14 +193,13 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c;
struct window_pane *wp = item->state.tflag.wp;
struct window_pane *wp = item->target.wp;
char *buf, *cause;
const char *bufname;
size_t len;
if (self->entry == &cmd_clear_history_entry) {
if (wp->mode == &window_copy_mode)
window_pane_reset_mode(wp);
window_pane_reset_mode_all(wp);
grid_clear_history(wp->base.grid);
return (CMD_RETURN_NORMAL);
}

View File

@@ -1,101 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Enter choice mode to choose a buffer.
*/
#define CHOOSE_BUFFER_TEMPLATE \
"#{buffer_name}: #{buffer_size} bytes: #{buffer_sample}"
static enum cmd_retval cmd_choose_buffer_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer",
.alias = NULL,
.args = { "F:t:", 0, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_choose_buffer_exec
};
static enum cmd_retval
cmd_choose_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct winlink *wl = item->state.tflag.wl;
struct window_choose_data *cdata;
struct paste_buffer *pb;
char *action, *action_data;
const char *template;
u_int idx;
if (c == NULL) {
cmdq_error(item, "no client available");
return (CMD_RETURN_ERROR);
}
if ((template = args_get(args, 'F')) == NULL)
template = CHOOSE_BUFFER_TEMPLATE;
if (paste_get_top(NULL) == NULL)
return (CMD_RETURN_NORMAL);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (CMD_RETURN_NORMAL);
if (args->argc != 0)
action = xstrdup(args->argv[0]);
else
action = xstrdup("paste-buffer -b '%%'");
idx = 0;
pb = NULL;
while ((pb = paste_walk(pb)) != NULL) {
cdata = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = idx;
cdata->ft_template = xstrdup(template);
format_defaults_paste_buffer(cdata->ft, pb);
xasprintf(&action_data, "%s", paste_buffer_name(pb));
cdata->command = cmd_template_replace(action, action_data, 1);
free(action_data);
window_choose_add(wl->window->active, cdata);
idx++;
}
free(action);
window_choose_ready(wl->window->active, 0, NULL);
return (CMD_RETURN_NORMAL);
}

View File

@@ -1,135 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Enter choice mode to choose a client.
*/
#define CHOOSE_CLIENT_TEMPLATE \
"#{client_name}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}]" \
"#{?client_utf8, (utf8),}#{?client_readonly, (ro),} " \
"(last used #{t:client_activity})"
static enum cmd_retval cmd_choose_client_exec(struct cmd *,
struct cmdq_item *);
static void cmd_choose_client_callback(struct window_choose_data *);
const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client",
.alias = NULL,
.args = { "F:t:", 0, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_choose_client_exec
};
struct cmd_choose_client_data {
struct client *client;
};
static enum cmd_retval
cmd_choose_client_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct client *c1;
struct window_choose_data *cdata;
struct winlink *wl = item->state.tflag.wl;
const char *template;
char *action;
u_int idx, cur;
if (c == NULL) {
cmdq_error(item, "no client available");
return (CMD_RETURN_ERROR);
}
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (CMD_RETURN_NORMAL);
if ((template = args_get(args, 'F')) == NULL)
template = CHOOSE_CLIENT_TEMPLATE;
if (args->argc != 0)
action = xstrdup(args->argv[0]);
else
action = xstrdup("detach-client -t '%%'");
cur = idx = 0;
TAILQ_FOREACH(c1, &clients, entry) {
if (c1->session == NULL)
continue;
if (c1 == item->client)
cur = idx;
cdata = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = idx;
cdata->ft_template = xstrdup(template);
format_add(cdata->ft, "line", "%u", idx);
format_defaults(cdata->ft, c1, NULL, NULL, NULL);
cdata->command = cmd_template_replace(action, c1->name, 1);
window_choose_add(wl->window->active, cdata);
idx++;
}
free(action);
window_choose_ready(wl->window->active, cur,
cmd_choose_client_callback);
return (CMD_RETURN_NORMAL);
}
static void
cmd_choose_client_callback(struct window_choose_data *cdata)
{
struct client *c;
u_int idx;
if (cdata == NULL)
return;
if (cdata->start_client->flags & CLIENT_DEAD)
return;
idx = 0;
TAILQ_FOREACH(c, &clients, entry) {
if (idx == cdata->idx)
break;
idx++;
}
if (c == NULL || c->session == NULL)
return;
window_choose_data_run(cdata);
}

View File

@@ -18,66 +18,51 @@
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
#define CMD_CHOOSE_TREE_WINDOW_ACTION "select-window -t '%%'"
#define CMD_CHOOSE_TREE_SESSION_ACTION "switch-client -t '%%'"
/*
* Enter choice mode to choose a session and/or window.
* Enter a mode.
*/
#define CHOOSE_TREE_SESSION_TEMPLATE \
"#{session_name}: #{session_windows} windows" \
"#{?session_grouped, (group ,}" \
"#{session_group}#{?session_grouped,),}" \
"#{?session_attached, (attached),}"
#define CHOOSE_TREE_WINDOW_TEMPLATE \
"#{window_index}: #{window_name}#{window_flags} " \
"\"#{pane_title}\""
static enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_choose_tree_entry = {
.name = "choose-tree",
.alias = NULL,
.args = { "S:W:swub:c:t:", 0, 1 },
.usage = "[-suw] [-b session-template] [-c window template] "
"[-S format] [-W format] " CMD_TARGET_WINDOW_USAGE,
.args = { "F:Gf:NO:st:wZ", 0, 1 },
.usage = "[-GNsw] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE " [template]",
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_choose_tree_exec
};
const struct cmd_entry cmd_choose_session_entry = {
.name = "choose-session",
const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client",
.alias = NULL,
.args = { "F:t:", 0, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
.args = { "F:f:NO:t:Z", 0, 1 },
.usage = "[-N] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE " [template]",
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_choose_tree_exec
};
const struct cmd_entry cmd_choose_window_entry = {
.name = "choose-window",
const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer",
.alias = NULL,
.args = { "F:t:", 0, 1 },
.usage = CMD_TARGET_WINDOW_USAGE "[-F format] [template]",
.args = { "F:f:NO:t:Z", 0, 1 },
.usage = "[-N] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE " [template]",
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_choose_tree_exec
@@ -87,167 +72,20 @@ static enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct winlink *wl = item->state.tflag.wl, *wm;
struct session *s = item->state.tflag.s, *s2;
struct window_choose_data *wcd = NULL;
const char *ses_template, *win_template;
char *final_win_action, *cur_win_template;
char *final_win_template_middle;
char *final_win_template_last;
const char *ses_action, *win_action;
u_int cur_win, idx_ses, win_ses, win_max;
u_int wflag, sflag;
struct window_pane *wp = item->target.wp;
const struct window_mode *mode;
ses_template = win_template = NULL;
ses_action = win_action = NULL;
if (c == NULL) {
cmdq_error(item, "no client available");
return (CMD_RETURN_ERROR);
}
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (CMD_RETURN_NORMAL);
/* Sort out which command this is. */
wflag = sflag = 0;
if (self->entry == &cmd_choose_session_entry) {
sflag = 1;
if ((ses_template = args_get(args, 'F')) == NULL)
ses_template = CHOOSE_TREE_SESSION_TEMPLATE;
if (args->argc != 0)
ses_action = args->argv[0];
else
ses_action = CMD_CHOOSE_TREE_SESSION_ACTION;
} else if (self->entry == &cmd_choose_window_entry) {
wflag = 1;
if ((win_template = args_get(args, 'F')) == NULL)
win_template = CHOOSE_TREE_WINDOW_TEMPLATE;
if (args->argc != 0)
win_action = args->argv[0];
else
win_action = CMD_CHOOSE_TREE_WINDOW_ACTION;
} else {
wflag = args_has(args, 'w');
sflag = args_has(args, 's');
if ((ses_action = args_get(args, 'b')) == NULL)
ses_action = CMD_CHOOSE_TREE_SESSION_ACTION;
if ((win_action = args_get(args, 'c')) == NULL)
win_action = CMD_CHOOSE_TREE_WINDOW_ACTION;
if ((ses_template = args_get(args, 'S')) == NULL)
ses_template = CHOOSE_TREE_SESSION_TEMPLATE;
if ((win_template = args_get(args, 'W')) == NULL)
win_template = CHOOSE_TREE_WINDOW_TEMPLATE;
}
/*
* If not asking for windows and sessions, assume no "-ws" given and
* hence display the entire tree outright.
*/
if (!wflag && !sflag)
wflag = sflag = 1;
/*
* If we're drawing in tree mode, including sessions, then pad the
* window template, otherwise just render the windows as a flat list
* without any padding.
*/
if (wflag && sflag) {
xasprintf(&final_win_template_middle,
" \001tq\001> %s", win_template);
xasprintf(&final_win_template_last,
" \001mq\001> %s", win_template);
} else if (wflag) {
final_win_template_middle = xstrdup(win_template);
final_win_template_last = xstrdup(win_template);
if (self->entry == &cmd_choose_buffer_entry) {
if (paste_get_top(NULL) == NULL)
return (CMD_RETURN_NORMAL);
mode = &window_buffer_mode;
} else if (self->entry == &cmd_choose_client_entry) {
if (server_client_how_many() == 0)
return (CMD_RETURN_NORMAL);
mode = &window_client_mode;
} else
final_win_template_middle = final_win_template_last = NULL;
idx_ses = cur_win = -1;
RB_FOREACH(s2, sessions, &sessions) {
idx_ses++;
/*
* If we're just choosing windows, jump straight there. Note
* that this implies the current session, so only choose
* windows when the session matches this one.
*/
if (wflag && !sflag) {
if (s != s2)
continue;
goto windows_only;
}
wcd = window_choose_add_session(wl->window->active,
c, s2, ses_template, ses_action, idx_ses);
/* If we're just choosing sessions, skip choosing windows. */
if (sflag && !wflag) {
if (s == s2)
cur_win = idx_ses;
continue;
}
windows_only:
win_ses = win_max = -1;
RB_FOREACH(wm, winlinks, &s2->windows)
win_max++;
RB_FOREACH(wm, winlinks, &s2->windows) {
win_ses++;
if (sflag && wflag)
idx_ses++;
if (wm == s2->curw && s == s2) {
if (wflag && !sflag) {
/*
* Then we're only counting windows.
* So remember which is the current
* window in the list.
*/
cur_win = win_ses;
} else
cur_win = idx_ses;
}
xasprintf(&final_win_action, "%s %s %s",
wcd != NULL ? wcd->command : "",
wcd != NULL ? ";" : "", win_action);
if (win_ses != win_max)
cur_win_template = final_win_template_middle;
else
cur_win_template = final_win_template_last;
window_choose_add_window(wl->window->active,
c, s2, wm, cur_win_template,
final_win_action,
(wflag && !sflag) ? win_ses : idx_ses);
free(final_win_action);
}
/*
* If we're just drawing windows, don't consider moving on to
* other sessions as we only list windows in this session.
*/
if (wflag && !sflag)
break;
}
free(final_win_template_middle);
free(final_win_template_last);
window_choose_ready(wl->window->active, cur_win, NULL);
if (args_has(args, 'u')) {
window_choose_expand_all(wl->window->active);
window_choose_set_current(wl->window->active, cur_win);
}
mode = &window_tree_mode;
window_pane_set_mode(wp, mode, &item->target, args);
return (CMD_RETURN_NORMAL);
}

View File

@@ -32,7 +32,8 @@
static enum cmd_retval cmd_command_prompt_exec(struct cmd *,
struct cmdq_item *);
static int cmd_command_prompt_callback(void *, const char *, int);
static int cmd_command_prompt_callback(struct client *, void *,
const char *, int);
static void cmd_command_prompt_free(void *);
const struct cmd_entry cmd_command_prompt_entry = {
@@ -43,24 +44,21 @@ const struct cmd_entry cmd_command_prompt_entry = {
.usage = "[-1Ni] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
"[template]",
.tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_command_prompt_exec
};
struct cmd_command_prompt_cdata {
struct client *c;
int flags;
int flags;
char *inputs;
char *next_input;
char *inputs;
char *next_input;
char *prompts;
char *next_prompt;
char *prompts;
char *next_prompt;
char *template;
int idx;
char *template;
int idx;
};
static enum cmd_retval
@@ -69,15 +67,17 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
struct args *args = self->args;
const char *inputs, *prompts;
struct cmd_command_prompt_cdata *cdata;
struct client *c = item->state.c;
struct client *c;
char *prompt, *ptr, *input = NULL;
size_t n;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (c->prompt_string != NULL)
return (CMD_RETURN_NORMAL);
cdata = xcalloc(1, sizeof *cdata);
cdata->c = c;
cdata->inputs = NULL;
cdata->next_input = NULL;
@@ -129,26 +129,15 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_command_prompt_error(struct cmdq_item *item, void *data)
{
char *error = data;
cmdq_error(item, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static int
cmd_command_prompt_callback(void *data, const char *s, int done)
cmd_command_prompt_callback(struct client *c, void *data, const char *s,
int done)
{
struct cmd_command_prompt_cdata *cdata = data;
struct client *c = cdata->c;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
char *cause, *new_template, *prompt, *ptr;
char *new_template, *prompt, *ptr;
char *input = NULL;
struct cmd_parse_result *pr;
if (s == NULL)
return (0);
@@ -175,24 +164,26 @@ cmd_command_prompt_callback(void *data, const char *s, int done)
return (1);
}
cmdlist = cmd_string_parse(new_template, NULL, 0, &cause);
if (cmdlist == NULL) {
if (cause != NULL) {
new_item = cmdq_get_callback(cmd_command_prompt_error,
cause);
} else
new_item = NULL;
} else {
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist);
}
if (new_item != NULL)
pr = cmd_parse_from_string(new_template, NULL);
switch (pr->status) {
case CMD_PARSE_EMPTY:
new_item = NULL;
break;
case CMD_PARSE_ERROR:
new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item);
break;
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
cmd_list_free(pr->cmdlist);
cmdq_append(c, new_item);
break;
}
if (!done)
free(new_template);
if (c->prompt_callbackfn != (void *)&cmd_command_prompt_callback)
if (c->prompt_inputcb != cmd_command_prompt_callback)
return (1);
return (0);
}

View File

@@ -31,7 +31,8 @@
static enum cmd_retval cmd_confirm_before_exec(struct cmd *,
struct cmdq_item *);
static int cmd_confirm_before_callback(void *, const char *, int);
static int cmd_confirm_before_callback(struct client *, void *,
const char *, int);
static void cmd_confirm_before_free(void *);
const struct cmd_entry cmd_confirm_before_entry = {
@@ -41,15 +42,12 @@ const struct cmd_entry cmd_confirm_before_entry = {
.args = { "p:t:", 1, 1 },
.usage = "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
.tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_confirm_before_exec
};
struct cmd_confirm_before_data {
char *cmd;
struct client *client;
char *cmd;
};
static enum cmd_retval
@@ -57,10 +55,13 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_confirm_before_data *cdata;
struct client *c = item->state.c;
struct client *c;
char *cmd, *copy, *new_prompt, *ptr;
const char *prompt;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if ((prompt = args_get(args, 'p')) != NULL)
xasprintf(&new_prompt, "%s ", prompt);
else {
@@ -73,9 +74,6 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(args->argv[0]);
cdata->client = c;
cdata->client->references++;
status_prompt_set(c, new_prompt, NULL,
cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
PROMPT_SINGLE);
@@ -84,48 +82,38 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_confirm_before_error(struct cmdq_item *item, void *data)
{
char *error = data;
cmdq_error(item, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static int
cmd_confirm_before_callback(void *data, const char *s, __unused int done)
cmd_confirm_before_callback(struct client *c, void *data, const char *s,
__unused int done)
{
struct cmd_confirm_before_data *cdata = data;
struct client *c = cdata->client;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
char *cause;
struct cmd_parse_result *pr;
if (c->flags & CLIENT_DEAD)
return (0);
if (s == NULL || *s == '\0')
return (0);
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
if (tolower((u_char)s[0]) != 'y' || s[1] != '\0')
return (0);
cmdlist = cmd_string_parse(cdata->cmd, NULL, 0, &cause);
if (cmdlist == NULL) {
if (cause != NULL) {
new_item = cmdq_get_callback(cmd_confirm_before_error,
cause);
} else
new_item = NULL;
} else {
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist);
}
if (new_item != NULL)
pr = cmd_parse_from_string(cdata->cmd, NULL);
switch (pr->status) {
case CMD_PARSE_EMPTY:
new_item = NULL;
break;
case CMD_PARSE_ERROR:
new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item);
break;
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
cmd_list_free(pr->cmdlist);
cmdq_append(c, new_item);
break;
}
return (0);
}
@@ -134,9 +122,6 @@ static void
cmd_confirm_before_free(void *data)
{
struct cmd_confirm_before_data *cdata = data;
struct client *c = cdata->client;
server_client_unref(c);
free(cdata->cmd);
free(cdata);

View File

@@ -33,7 +33,7 @@ const struct cmd_entry cmd_copy_mode_entry = {
.args = { "Met:u", 0, 0 },
.usage = "[-Mu] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_copy_mode_exec
@@ -46,7 +46,7 @@ const struct cmd_entry cmd_clock_mode_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_copy_mode_exec
@@ -56,33 +56,28 @@ static enum cmd_retval
cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmdq_shared *shared = item->shared;
struct client *c = item->client;
struct session *s;
struct window_pane *wp = item->state.tflag.wp;
struct window_pane *wp = item->target.wp;
if (args_has(args, 'M')) {
if ((wp = cmd_mouse_pane(&item->mouse, &s, NULL)) == NULL)
if ((wp = cmd_mouse_pane(&shared->mouse, &s, NULL)) == NULL)
return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
}
if (self->entry == &cmd_clock_mode_entry) {
window_pane_set_mode(wp, &window_clock_mode);
window_pane_set_mode(wp, &window_clock_mode, NULL, NULL);
return (CMD_RETURN_NORMAL);
}
if (wp->mode != &window_copy_mode) {
if (window_pane_set_mode(wp, &window_copy_mode) != 0)
return (CMD_RETURN_NORMAL);
window_copy_init_from_pane(wp, args_has(self->args, 'e'));
if (!window_pane_set_mode(wp, &window_copy_mode, NULL, args)) {
if (args_has(args, 'M'))
window_copy_start_drag(c, &shared->mouse);
}
if (args_has(args, 'M')) {
if (wp->mode != NULL && wp->mode != &window_copy_mode)
return (CMD_RETURN_NORMAL);
window_copy_start_drag(c, &item->mouse);
}
if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
if (args_has(self->args, 'u'))
window_copy_pageup(wp, 0);
return (CMD_RETURN_NORMAL);

View File

@@ -37,8 +37,7 @@ const struct cmd_entry cmd_detach_client_entry = {
.usage = "[-aP] [-E shell-command] "
"[-s target-session] " CMD_TARGET_CLIENT_USAGE,
.sflag = CMD_SESSION,
.tflag = CMD_CLIENT,
.source = { 's', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_READONLY,
.exec = cmd_detach_client_exec
@@ -51,8 +50,6 @@ const struct cmd_entry cmd_suspend_client_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_detach_client_exec
};
@@ -61,15 +58,16 @@ static enum cmd_retval
cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c, *cloop;
struct client *c, *cloop;
struct session *s;
enum msgtype msgtype;
const char *cmd = args_get(args, 'E');
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (self->entry == &cmd_suspend_client_entry) {
tty_stop_tty(&c->tty);
c->flags |= CLIENT_SUSPENDED;
proc_send(c->peer, MSG_SUSPEND, -1, NULL, 0);
server_client_suspend(c);
return (CMD_RETURN_NORMAL);
}
@@ -79,7 +77,9 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
msgtype = MSG_DETACH;
if (args_has(args, 's')) {
s = item->state.sflag.s;
s = item->source.s;
if (s == NULL)
return (CMD_RETURN_NORMAL);
TAILQ_FOREACH(cloop, &clients, entry) {
if (cloop->session == s) {
if (cmd != NULL)

178
cmd-display-menu.c Normal file
View File

@@ -0,0 +1,178 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Display a menu on a client.
*/
static enum cmd_retval cmd_display_menu_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_display_menu_entry = {
.name = "display-menu",
.alias = "menu",
.args = { "c:t:T:x:y:", 1, -1 },
.usage = "[-c target-client] " CMD_TARGET_PANE_USAGE " [-T title] "
"[-x position] [-y position] name key command ...",
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_display_menu_exec
};
static enum cmd_retval
cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
struct cmd_find_state *fs = &item->target;
struct menu *menu = NULL;
struct style_range *sr;
struct menu_item menu_item;
const char *xp, *yp, *key;
char *title, *name;
int at, flags, i;
u_int px, py, ox, oy, sx, sy;
if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (c->overlay_draw != NULL)
return (CMD_RETURN_NORMAL);
at = status_at_line(c);
if (args_has(args, 'T'))
title = format_single(NULL, args_get(args, 'T'), c, s, wl, wp);
else
title = xstrdup("");
menu = menu_create(title);
for (i = 0; i != args->argc; /* nothing */) {
name = args->argv[i++];
if (*name == '\0') {
menu_add_item(menu, NULL, item, c, fs);
continue;
}
if (args->argc - i < 2) {
cmdq_error(item, "not enough arguments");
free(title);
menu_free(menu);
return (CMD_RETURN_ERROR);
}
key = args->argv[i++];
menu_item.name = name;
menu_item.key = key_string_lookup_string(key);
menu_item.command = args->argv[i++];
menu_add_item(menu, &menu_item, item, c, fs);
}
free(title);
if (menu == NULL) {
cmdq_error(item, "invalid menu arguments");
return (CMD_RETURN_ERROR);
}
if (menu->count == 0) {
menu_free(menu);
return (CMD_RETURN_NORMAL);
}
xp = args_get(args, 'x');
if (xp == NULL)
px = 0;
else if (strcmp(xp, "R") == 0)
px = c->tty.sx - 1;
else if (strcmp(xp, "P") == 0) {
tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
if (wp->xoff >= ox)
px = wp->xoff - ox;
else
px = 0;
} else if (strcmp(xp, "M") == 0 && item->shared->mouse.valid) {
if (item->shared->mouse.x > (menu->width + 4) / 2)
px = item->shared->mouse.x - (menu->width + 4) / 2;
else
px = 0;
}
else if (strcmp(xp, "W") == 0) {
if (at == -1)
px = 0;
else {
TAILQ_FOREACH(sr, &c->status.entries[0].ranges, entry) {
if (sr->type != STYLE_RANGE_WINDOW)
continue;
if (sr->argument == (u_int)wl->idx)
break;
}
if (sr != NULL)
px = sr->start;
else
px = 0;
}
} else
px = strtoul(xp, NULL, 10);
if (px + menu->width + 4 >= c->tty.sx)
px = c->tty.sx - menu->width - 4;
yp = args_get(args, 'y');
if (yp == NULL)
py = 0;
else if (strcmp(yp, "P") == 0) {
tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
if (wp->yoff + wp->sy >= oy)
py = wp->yoff + wp->sy - oy;
else
py = 0;
} else if (strcmp(yp, "M") == 0 && item->shared->mouse.valid)
py = item->shared->mouse.y + menu->count + 2;
else if (strcmp(yp, "S") == 0) {
if (at == -1)
py = c->tty.sy;
else if (at == 0)
py = status_line_size(c) + menu->count + 2;
else
py = at;
} else
py = strtoul(yp, NULL, 10);
if (py < menu->count + 2)
py = 0;
else
py -= menu->count + 2;
if (py + menu->count + 2 >= c->tty.sy)
py = c->tty.sy - menu->count - 2;
flags = 0;
if (!item->shared->mouse.valid)
flags |= MENU_NOMOUSE;
if (menu_display(menu, flags, item, px, py, c, fs, NULL, NULL) != 0)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}

View File

@@ -39,28 +39,45 @@ const struct cmd_entry cmd_display_message_entry = {
.name = "display-message",
.alias = "display",
.args = { "c:pt:F:", 0, 1 },
.usage = "[-p] [-c target-client] [-F format] "
.args = { "ac:Ipt:F:v", 0, 1 },
.usage = "[-aIpv] [-c target-client] [-F format] "
CMD_TARGET_PANE_USAGE " [message]",
.cflag = CMD_CLIENT_CANFAIL,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_display_message_exec
};
static void
cmd_display_message_each(const char *key, const char *value, void *arg)
{
struct cmdq_item *item = arg;
cmdq_print(item, "%s=%s", key, value);
}
static enum cmd_retval
cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct window_pane *wp = item->state.tflag.wp;
struct client *c, *target_c;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
const char *template;
char *msg;
char *msg, *cause;
struct format_tree *ft;
int flags;
if (args_has(args, 'I')) {
if (window_pane_start_input(wp, item, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_WAIT);
}
if (args_has(args, 'F') && args->argc != 0) {
cmdq_error(item, "only one of -F or argument must be given");
@@ -73,10 +90,31 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
if (template == NULL)
template = DISPLAY_MESSAGE_TEMPLATE;
ft = format_create(item, FORMAT_NONE, 0);
format_defaults(ft, c, s, wl, wp);
/*
* -c is intended to be the client where the message should be
* displayed if -p is not given. But it makes sense to use it for the
* formats too, assuming it matches the session. If it doesn't, use the
* best client for the session.
*/
c = cmd_find_client(item, args_get(args, 'c'), 1);
if (c != NULL && c->session == s)
target_c = c;
else
target_c = cmd_find_best_client(s);
if (args_has(self->args, 'v'))
flags = FORMAT_VERBOSE;
else
flags = 0;
ft = format_create(item->client, item, FORMAT_NONE, flags);
format_defaults(ft, target_c, s, wl, wp);
msg = format_expand_time(ft, template, time(NULL));
if (args_has(args, 'a')) {
if (item != NULL)
format_each(ft, cmd_display_message_each, item);
return (CMD_RETURN_NORMAL);
}
msg = format_expand_time(ft, template);
if (args_has(self->args, 'p'))
cmdq_print(item, "%s", msg);
else if (c != NULL)

View File

@@ -18,8 +18,8 @@
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -30,86 +30,253 @@
static enum cmd_retval cmd_display_panes_exec(struct cmd *,
struct cmdq_item *);
static void cmd_display_panes_callback(struct client *,
struct window_pane *);
const struct cmd_entry cmd_display_panes_entry = {
.name = "display-panes",
.alias = "displayp",
.args = { "t:", 0, 1 },
.usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.args = { "bd:t:", 0, 1 },
.usage = "[-b] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
.flags = CMD_AFTERHOOK,
.exec = cmd_display_panes_exec
};
static enum cmd_retval
cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
struct cmd_display_panes_data {
struct cmdq_item *item;
char *command;
};
static void
cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
struct window_pane *wp)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct client *c = ctx->c;
struct tty *tty = &c->tty;
struct session *s = c->session;
struct options *oo = s->options;
struct window *w = wp->window;
struct grid_cell gc;
u_int idx, px, py, i, j, xoff, yoff, sx, sy;
int colour, active_colour;
char buf[16], *ptr;
size_t len;
if (c->identify_callback != NULL)
return (CMD_RETURN_NORMAL);
if (wp->xoff + wp->sx <= ctx->ox ||
wp->xoff >= ctx->ox + ctx->sx ||
wp->yoff + wp->sy <= ctx->oy ||
wp->yoff >= ctx->oy + ctx->sy)
return;
c->identify_callback = cmd_display_panes_callback;
if (args->argc != 0)
c->identify_callback_data = xstrdup(args->argv[0]);
if (wp->xoff >= ctx->ox && wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
/* All visible. */
xoff = wp->xoff - ctx->ox;
sx = wp->sx;
} else if (wp->xoff < ctx->ox &&
wp->xoff + wp->sx > ctx->ox + ctx->sx) {
/* Both left and right not visible. */
xoff = 0;
sx = ctx->sx;
} else if (wp->xoff < ctx->ox) {
/* Left not visible. */
xoff = 0;
sx = wp->sx - (ctx->ox - wp->xoff);
} else {
/* Right not visible. */
xoff = wp->xoff - ctx->ox;
sx = wp->sx - xoff;
}
if (wp->yoff >= ctx->oy && wp->yoff + wp->sy <= ctx->oy + ctx->sy) {
/* All visible. */
yoff = wp->yoff - ctx->oy;
sy = wp->sy;
} else if (wp->yoff < ctx->oy &&
wp->yoff + wp->sy > ctx->oy + ctx->sy) {
/* Both top and bottom not visible. */
yoff = 0;
sy = ctx->sy;
} else if (wp->yoff < ctx->oy) {
/* Top not visible. */
yoff = 0;
sy = wp->sy - (ctx->oy - wp->yoff);
} else {
/* Bottom not visible. */
yoff = wp->yoff - ctx->oy;
sy = wp->sy - yoff;
}
if (ctx->statustop)
yoff += ctx->statuslines;
px = sx / 2;
py = sy / 2;
if (window_pane_index(wp, &idx) != 0)
fatalx("index not found");
len = xsnprintf(buf, sizeof buf, "%u", idx);
if (sx < len)
return;
colour = options_get_number(oo, "display-panes-colour");
active_colour = options_get_number(oo, "display-panes-active-colour");
if (sx < len * 6 || sy < 5) {
tty_cursor(tty, xoff + px - len / 2, yoff + py);
goto draw_text;
}
px -= len * 3;
py -= 2;
memcpy(&gc, &grid_default_cell, sizeof gc);
if (w->active == wp)
gc.bg = active_colour;
else
c->identify_callback_data = xstrdup("select-pane -t '%%'");
gc.bg = colour;
gc.flags |= GRID_FLAG_NOPALETTE;
server_client_set_identify(c);
tty_attributes(tty, &gc, wp);
for (ptr = buf; *ptr != '\0'; ptr++) {
if (*ptr < '0' || *ptr > '9')
continue;
idx = *ptr - '0';
return (CMD_RETURN_NORMAL);
}
for (j = 0; j < 5; j++) {
for (i = px; i < px + 5; i++) {
tty_cursor(tty, xoff + i, yoff + py + j);
if (window_clock_table[idx][j][i - px])
tty_putc(tty, ' ');
}
}
px += 6;
}
static enum cmd_retval
cmd_display_panes_error(struct cmdq_item *item, void *data)
{
char *error = data;
len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy);
if (sx < len || sy < 6)
return;
tty_cursor(tty, xoff + sx - len, yoff);
cmdq_error(item, "%s", error);
free(error);
draw_text:
memcpy(&gc, &grid_default_cell, sizeof gc);
if (w->active == wp)
gc.fg = active_colour;
else
gc.fg = colour;
gc.flags |= GRID_FLAG_NOPALETTE;
return (CMD_RETURN_NORMAL);
tty_attributes(tty, &gc, wp);
tty_puts(tty, buf);
tty_cursor(tty, 0, 0);
}
static void
cmd_display_panes_callback(struct client *c, struct window_pane *wp)
cmd_display_panes_draw(struct client *c, struct screen_redraw_ctx *ctx)
{
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
char *template, *cmd, *expanded, *cause;
struct window *w = c->session->curw->window;
struct window_pane *wp;
template = c->identify_callback_data;
if (wp == NULL)
goto out;
xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(template, expanded, 1);
log_debug("%s: %s @%u", __func__, c->name, w->id);
cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);
if (cmdlist == NULL) {
if (cause != NULL) {
new_item = cmdq_get_callback(cmd_display_panes_error,
cause);
} else
new_item = NULL;
} else {
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist);
TAILQ_FOREACH(wp, &w->panes, entry) {
if (window_pane_visible(wp))
cmd_display_panes_draw_pane(ctx, wp);
}
}
if (new_item != NULL)
static void
cmd_display_panes_free(struct client *c)
{
struct cmd_display_panes_data *cdata = c->overlay_data;
if (cdata->item != NULL)
cdata->item->flags &= ~CMDQ_WAITING;
free(cdata->command);
free(cdata);
}
static int
cmd_display_panes_key(struct client *c, struct key_event *event)
{
struct cmd_display_panes_data *cdata = c->overlay_data;
struct cmdq_item *new_item;
char *cmd, *expanded;
struct window *w = c->session->curw->window;
struct window_pane *wp;
struct cmd_parse_result *pr;
if (event->key < '0' || event->key > '9')
return (1);
wp = window_pane_at_index(w, event->key - '0');
if (wp == NULL)
return (1);
window_unzoom(w);
xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(cdata->command, expanded, 1);
pr = cmd_parse_from_string(cmd, NULL);
switch (pr->status) {
case CMD_PARSE_EMPTY:
new_item = NULL;
break;
case CMD_PARSE_ERROR:
new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item);
break;
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
cmd_list_free(pr->cmdlist);
cmdq_append(c, new_item);
break;
}
free(cmd);
free(expanded);
out:
free(c->identify_callback_data);
c->identify_callback_data = NULL;
c->identify_callback = NULL;
return (1);
}
static enum cmd_retval
cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c;
struct session *s;
u_int delay;
char *cause;
struct cmd_display_panes_data *cdata;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
s = c->session;
if (c->overlay_draw != NULL)
return (CMD_RETURN_NORMAL);
if (args_has(args, 'd')) {
delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "delay %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
} else
delay = options_get_number(s->options, "display-panes-time");
cdata = xmalloc(sizeof *cdata);
if (args->argc != 0)
cdata->command = xstrdup(args->argv[0]);
else
cdata->command = xstrdup("select-pane -t '%%'");
if (args_has(args, 'b'))
cdata->item = NULL;
else
cdata->item = item;
server_client_set_overlay(c, delay, cmd_display_panes_draw,
cmd_display_panes_key, cmd_display_panes_free, cdata);
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}

View File

@@ -18,9 +18,7 @@
#include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -28,213 +26,71 @@
* Find window containing text.
*/
#define FIND_WINDOW_TEMPLATE \
"#{window_index}: #{window_name} " \
"[#{window_width}x#{window_height}] " \
"(#{window_panes} panes) #{window_find_matches}"
static enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmdq_item *);
static void cmd_find_window_callback(struct window_choose_data *);
/* Flags for determining matching behavior. */
#define CMD_FIND_WINDOW_BY_TITLE 0x1
#define CMD_FIND_WINDOW_BY_CONTENT 0x2
#define CMD_FIND_WINDOW_BY_NAME 0x4
#define CMD_FIND_WINDOW_ALL \
(CMD_FIND_WINDOW_BY_TITLE | \
CMD_FIND_WINDOW_BY_CONTENT | \
CMD_FIND_WINDOW_BY_NAME)
const struct cmd_entry cmd_find_window_entry = {
.name = "find-window",
.alias = "findw",
.args = { "F:CNt:T", 1, 4 },
.usage = "[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string",
.args = { "CNt:TZ", 1, 1 },
.usage = "[-CNTZ] " CMD_TARGET_PANE_USAGE " match-string",
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_find_window_exec
};
struct cmd_find_window_data {
struct winlink *wl;
char *list_ctx;
u_int pane_id;
TAILQ_ENTRY(cmd_find_window_data) entry;
};
TAILQ_HEAD(cmd_find_window_list, cmd_find_window_data);
static u_int cmd_find_window_match_flags(struct args *);
static void cmd_find_window_match(struct cmd_find_window_list *, int,
struct winlink *, const char *, const char *);
static u_int
cmd_find_window_match_flags(struct args *args)
{
u_int match_flags = 0;
/* Turn on flags based on the options. */
if (args_has(args, 'T'))
match_flags |= CMD_FIND_WINDOW_BY_TITLE;
if (args_has(args, 'C'))
match_flags |= CMD_FIND_WINDOW_BY_CONTENT;
if (args_has(args, 'N'))
match_flags |= CMD_FIND_WINDOW_BY_NAME;
/* If none of the flags were set, default to matching anything. */
if (match_flags == 0)
match_flags = CMD_FIND_WINDOW_ALL;
return (match_flags);
}
static void
cmd_find_window_match(struct cmd_find_window_list *find_list,
int match_flags, struct winlink *wl, const char *str,
const char *searchstr)
{
struct cmd_find_window_data *find_data;
struct window_pane *wp;
u_int i, line;
char *sres;
find_data = xcalloc(1, sizeof *find_data);
i = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
i++;
if ((match_flags & CMD_FIND_WINDOW_BY_NAME) &&
fnmatch(searchstr, wl->window->name, 0) == 0) {
find_data->list_ctx = xstrdup("");
break;
}
if ((match_flags & CMD_FIND_WINDOW_BY_TITLE) &&
fnmatch(searchstr, wp->base.title, 0) == 0) {
xasprintf(&find_data->list_ctx,
"pane %u title: \"%s\"", i - 1, wp->base.title);
break;
}
if (match_flags & CMD_FIND_WINDOW_BY_CONTENT &&
(sres = window_pane_search(wp, str, &line)) != NULL) {
xasprintf(&find_data->list_ctx,
"pane %u line %u: \"%s\"", i - 1, line + 1, sres);
free(sres);
break;
}
}
if (find_data->list_ctx != NULL) {
find_data->wl = wl;
find_data->pane_id = i - 1;
TAILQ_INSERT_TAIL(find_list, find_data, entry);
} else
free(find_data);
}
static enum cmd_retval
cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct window_choose_data *cdata;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl, *wm;
struct cmd_find_window_list find_list;
struct cmd_find_window_data *find_data;
struct cmd_find_window_data *find_data1;
char *str, *searchstr;
const char *template;
u_int i, match_flags;
struct args *args = self->args, *new_args;
struct window_pane *wp = item->target.wp;
const char *s = args->argv[0];
char *filter, *argv = { NULL };
int C, N, T;
if (c == NULL) {
cmdq_error(item, "no client available");
return (CMD_RETURN_ERROR);
}
C = args_has(args, 'C');
N = args_has(args, 'N');
T = args_has(args, 'T');
if ((template = args_get(args, 'F')) == NULL)
template = FIND_WINDOW_TEMPLATE;
if (!C && !N && !T)
C = N = T = 1;
match_flags = cmd_find_window_match_flags(args);
str = args->argv[0];
if (C && N && T) {
xasprintf(&filter,
"#{||:"
"#{C:%s},#{||:#{m:*%s*,#{window_name}},"
"#{m:*%s*,#{pane_title}}}}",
s, s, s);
} else if (C && N) {
xasprintf(&filter,
"#{||:#{C:%s},#{m:*%s*,#{window_name}}}",
s, s);
} else if (C && T) {
xasprintf(&filter,
"#{||:#{C:%s},#{m:*%s*,#{pane_title}}}",
s, s);
} else if (N && T) {
xasprintf(&filter,
"#{||:#{m:*%s*,#{window_name}},#{m:*%s*,#{pane_title}}}",
s, s);
} else if (C)
xasprintf(&filter, "#{C:%s}", s);
else if (N)
xasprintf(&filter, "#{m:*%s*,#{window_name}}", s);
else
xasprintf(&filter, "#{m:*%s*,#{pane_title}}", s);
TAILQ_INIT(&find_list);
new_args = args_parse("", 1, &argv);
if (args_has(args, 'Z'))
args_set(new_args, 'Z', NULL);
args_set(new_args, 'f', filter);
xasprintf(&searchstr, "*%s*", str);
RB_FOREACH(wm, winlinks, &s->windows)
cmd_find_window_match(&find_list, match_flags, wm, str, searchstr);
free(searchstr);
window_pane_set_mode(wp, &window_tree_mode, &item->target, new_args);
if (TAILQ_EMPTY(&find_list)) {
cmdq_error(item, "no windows matching: %s", str);
return (CMD_RETURN_ERROR);
}
args_free(new_args);
free(filter);
if (TAILQ_NEXT(TAILQ_FIRST(&find_list), entry) == NULL) {
if (session_select(s, TAILQ_FIRST(&find_list)->wl->idx) == 0)
server_redraw_session(s);
recalculate_sizes();
goto out;
}
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
goto out;
i = 0;
TAILQ_FOREACH(find_data, &find_list, entry) {
cdata = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = find_data->wl->idx;
cdata->wl = find_data->wl;
cdata->ft_template = xstrdup(template);
cdata->pane_id = find_data->pane_id;
format_add(cdata->ft, "line", "%u", i);
format_add(cdata->ft, "window_find_matches", "%s",
find_data->list_ctx);
format_defaults(cdata->ft, NULL, s, find_data->wl, NULL);
window_choose_add(wl->window->active, cdata);
i++;
}
window_choose_ready(wl->window->active, 0, cmd_find_window_callback);
out:
TAILQ_FOREACH_SAFE(find_data, &find_list, entry, find_data1) {
free(find_data->list_ctx);
TAILQ_REMOVE(&find_list, find_data, entry);
free(find_data);
}
return (CMD_RETURN_NORMAL);
}
static void
cmd_find_window_callback(struct window_choose_data *cdata)
{
struct session *s;
struct window_pane *wp;
if (cdata == NULL)
return;
s = cdata->start_session;
if (!session_alive(s))
return;
wp = window_pane_at_index(cdata->wl->window, cdata->pane_id);
if (wp != NULL && window_pane_visible(wp))
window_set_active_pane(cdata->wl->window, wp);
if (session_select(s, cdata->idx) == 0) {
server_redraw_session(s);
recalculate_sizes();
}
}

View File

@@ -26,21 +26,15 @@
#include "tmux.h"
static struct session *cmd_find_try_TMUX(struct client *, struct window *);
static int cmd_find_client_better(struct client *, struct client *);
static struct client *cmd_find_best_client(struct client **, u_int);
static int cmd_find_session_better(struct session *, struct session *,
int);
static struct session *cmd_find_best_session(struct session **, u_int, int);
static int cmd_find_best_session_with_window(struct cmd_find_state *);
static int cmd_find_best_winlink_with_window(struct cmd_find_state *);
static int cmd_find_current_session_with_client(struct cmd_find_state *);
static int cmd_find_current_session(struct cmd_find_state *);
static struct client *cmd_find_current_client(struct cmdq_item *);
static const char *cmd_find_map_table(const char *[][2], const char *);
static void cmd_find_log_state(const char *, struct cmd_find_state *);
static int cmd_find_get_session(struct cmd_find_state *, const char *);
static int cmd_find_get_window(struct cmd_find_state *, const char *, int);
static int cmd_find_get_window_with_session(struct cmd_find_state *,
@@ -83,7 +77,7 @@ static const char *cmd_find_pane_table[][2] = {
/* Get session from TMUX if present. */
static struct session *
cmd_find_try_TMUX(struct client *c, struct window *w)
cmd_find_try_TMUX(struct client *c)
{
struct environ_entry *envent;
char tmp[256];
@@ -99,15 +93,33 @@ cmd_find_try_TMUX(struct client *c, struct window *w)
return (NULL);
if (pid != getpid())
return (NULL);
log_debug("client %p TMUX is %s (session @%u)", c, envent->value,
session);
log_debug("%s: client %p TMUX %s (session $%u)", __func__, c,
envent->value, session);
s = session_find_by_id(session);
if (s == NULL || (w != NULL && !session_has(s, w)))
return (NULL);
if (s != NULL)
log_debug("%s: session $%u still exists", __func__, s->id);
return (s);
}
/* Find pane containing client if any. */
static struct window_pane *
cmd_find_inside_pane(struct client *c)
{
struct window_pane *wp;
if (c == NULL)
return (NULL);
RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
if (wp->fd != -1 && strcmp(wp->tty, c->ttyname) == 0)
break;
}
if (wp != NULL)
log_debug("%s: got pane %%%u (%s)", __func__, wp->id, wp->tty);
return (wp);
}
/* Is this client better? */
static int
cmd_find_client_better(struct client *c, struct client *than)
@@ -117,28 +129,23 @@ cmd_find_client_better(struct client *c, struct client *than)
return (timercmp(&c->activity_time, &than->activity_time, >));
}
/* Find best client from a list, or all if list is NULL. */
static struct client *
cmd_find_best_client(struct client **clist, u_int csize)
/* Find best client for session. */
struct client *
cmd_find_best_client(struct session *s)
{
struct client *c_loop, *c;
u_int i;
if (s->attached == 0)
s = NULL;
c = NULL;
if (clist != NULL) {
for (i = 0; i < csize; i++) {
if (clist[i]->session == NULL)
continue;
if (cmd_find_client_better(clist[i], c))
c = clist[i];
}
} else {
TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session == NULL)
continue;
if (cmd_find_client_better(c_loop, c))
c = c_loop;
}
TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session == NULL)
continue;
if (s != NULL && c_loop->session != s)
continue;
if (cmd_find_client_better(c_loop, c))
c = c_loop;
}
return (c);
}
@@ -152,10 +159,10 @@ cmd_find_session_better(struct session *s, struct session *than, int flags)
if (than == NULL)
return (1);
if (flags & CMD_FIND_PREFER_UNATTACHED) {
attached = (~than->flags & SESSION_UNATTACHED);
if (attached && (s->flags & SESSION_UNATTACHED))
attached = (than->attached != 0);
if (attached && s->attached == 0)
return (1);
else if (!attached && (~s->flags & SESSION_UNATTACHED))
else if (!attached && s->attached != 0)
return (0);
}
return (timercmp(&s->activity_time, &than->activity_time, >));
@@ -168,6 +175,8 @@ cmd_find_best_session(struct session **slist, u_int ssize, int flags)
struct session *s_loop, *s;
u_int i;
log_debug("%s: %u sessions to try", __func__, ssize);
s = NULL;
if (slist != NULL) {
for (i = 0; i < ssize; i++) {
@@ -191,11 +200,7 @@ cmd_find_best_session_with_window(struct cmd_find_state *fs)
u_int ssize;
struct session *s;
if (fs->item != NULL && fs->item->client != NULL) {
fs->s = cmd_find_try_TMUX(fs->item->client, fs->w);
if (fs->s != NULL)
return (cmd_find_best_winlink_with_window(fs));
}
log_debug("%s: window is @%u", __func__, fs->w->id);
ssize = 0;
RB_FOREACH(s, sessions, &sessions) {
@@ -218,7 +223,7 @@ fail:
}
/*
* Find the best winlink for a window (the current if it contains the pane,
* Find the best winlink for a window (the current if it contains the window,
* otherwise the first).
*/
static int
@@ -226,6 +231,8 @@ cmd_find_best_winlink_with_window(struct cmd_find_state *fs)
{
struct winlink *wl, *wl_loop;
log_debug("%s: window is @%u", __func__, fs->w->id);
wl = NULL;
if (fs->s->curw != NULL && fs->s->curw->window == fs->w)
wl = fs->s->curw;
@@ -244,146 +251,6 @@ cmd_find_best_winlink_with_window(struct cmd_find_state *fs)
return (0);
}
/* Find current session when we have an unattached client. */
static int
cmd_find_current_session_with_client(struct cmd_find_state *fs)
{
struct window_pane *wp;
/*
* If this is running in a pane, we can use that to limit the list of
* sessions to those containing that pane (we still use the current
* window in the best session).
*/
if (fs->item != NULL) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
if (strcmp(wp->tty, fs->item->client->ttyname) == 0)
break;
}
} else
wp = NULL;
/* Not running in a pane. We know nothing. Find the best session. */
if (wp == NULL)
goto unknown_pane;
/* Find the best session and winlink containing this pane. */
fs->w = wp->window;
if (cmd_find_best_session_with_window(fs) != 0) {
if (wp != NULL) {
/*
* The window may have been destroyed but the pane
* still on all_window_panes due to something else
* holding a reference.
*/
goto unknown_pane;
}
return (-1);
}
/* Use the current window and pane from this session. */
fs->wl = fs->s->curw;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = fs->w->active;
return (0);
unknown_pane:
fs->s = NULL;
if (fs->item != NULL)
fs->s = cmd_find_try_TMUX(fs->item->client, NULL);
if (fs->s == NULL)
fs->s = cmd_find_best_session(NULL, 0, fs->flags);
if (fs->s == NULL)
return (-1);
fs->wl = fs->s->curw;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = fs->w->active;
return (0);
}
/*
* Work out the best current state. If this function succeeds, the state is
* guaranteed to be completely filled in.
*/
static int
cmd_find_current_session(struct cmd_find_state *fs)
{
/* If we know the current client, use it. */
if (fs->item != NULL && fs->item->client != NULL) {
log_debug("%s: have client %p%s", __func__, fs->item->client,
fs->item->client->session == NULL ? "" : " (with session)");
if (fs->item->client->session == NULL)
return (cmd_find_current_session_with_client(fs));
fs->s = fs->item->client->session;
fs->wl = fs->s->curw;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = fs->w->active;
return (0);
}
/* We know nothing, find the best session and client. */
fs->s = cmd_find_best_session(NULL, 0, fs->flags);
if (fs->s == NULL)
return (-1);
fs->wl = fs->s->curw;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = fs->w->active;
return (0);
}
/* Work out the best current client. */
static struct client *
cmd_find_current_client(struct cmdq_item *item)
{
struct cmd_find_state current;
struct session *s;
struct client *c, **clist = NULL;
u_int csize;
/* If the queue client has a session, use it. */
if (item->client != NULL && item->client->session != NULL) {
log_debug("%s: using item %p client %p", __func__, item,
item->client);
return (item->client);
}
/* Otherwise find the current session. */
cmd_find_clear_state(&current, item, 0);
if (cmd_find_current_session(&current) != 0)
return (NULL);
/* If it is attached, find the best of it's clients. */
s = current.s;
log_debug("%s: current session $%u %s", __func__, s->id, s->name);
if (~s->flags & SESSION_UNATTACHED) {
csize = 0;
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != s)
continue;
clist = xreallocarray(clist, csize + 1, sizeof *clist);
clist[csize++] = c;
}
if (csize != 0) {
c = cmd_find_best_client(clist, csize);
if (c != NULL) {
free(clist);
return (c);
}
}
free(clist);
}
/* Otherwise pick best of all clients. */
return (cmd_find_best_client(NULL, 0));
}
/* Maps string in table. */
static const char *
cmd_find_map_table(const char *table[][2], const char *s)
@@ -537,7 +404,7 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window)
return (-1);
fs->idx = s->curw->idx + n;
} else {
if (n < s->curw->idx)
if (n > s->curw->idx)
return (-1);
fs->idx = s->curw->idx - n;
}
@@ -584,15 +451,16 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window)
if (window[0] != '+' && window[0] != '-') {
idx = strtonum(window, 0, INT_MAX, &errstr);
if (errstr == NULL) {
if (fs->flags & CMD_FIND_WINDOW_INDEX) {
fs->idx = idx;
return (0);
}
fs->wl = winlink_find_by_index(&fs->s->windows, idx);
if (fs->wl != NULL) {
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
return (0);
}
if (fs->flags & CMD_FIND_WINDOW_INDEX) {
fs->idx = idx;
return (0);
}
}
}
@@ -657,7 +525,7 @@ cmd_find_get_pane(struct cmd_find_state *fs, const char *pane, int only)
/* Check for pane ids starting with %. */
if (*pane == '%') {
fs->wp = window_pane_find_by_id_str(pane);
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
fs->w = fs->wp->window;
return (cmd_find_best_session_with_window(fs));
@@ -694,7 +562,7 @@ cmd_find_get_pane_with_session(struct cmd_find_state *fs, const char *pane)
/* Check for pane ids starting with %. */
if (*pane == '%') {
fs->wp = window_pane_find_by_id_str(pane);
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
fs->w = fs->wp->window;
return (cmd_find_best_winlink_with_window(fs));
@@ -726,7 +594,7 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
/* Check for pane ids starting with %. */
if (*pane == '%') {
fs->wp = window_pane_find_by_id_str(pane);
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
if (fs->wp->window != fs->w)
return (-1);
@@ -735,30 +603,28 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
/* Try special characters. */
if (strcmp(pane, "!") == 0) {
if (fs->w->last == NULL)
return (-1);
fs->wp = fs->w->last;
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
return (0);
} else if (strcmp(pane, "{up-of}") == 0) {
fs->wp = window_pane_find_up(fs->w->active);
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
return (0);
} else if (strcmp(pane, "{down-of}") == 0) {
fs->wp = window_pane_find_down(fs->w->active);
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
return (0);
} else if (strcmp(pane, "{left-of}") == 0) {
fs->wp = window_pane_find_left(fs->w->active);
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
return (0);
} else if (strcmp(pane, "{right-of}") == 0) {
fs->wp = window_pane_find_right(fs->w->active);
if (fs->wp == NULL || window_pane_outside(fs->wp))
if (fs->wp == NULL)
return (-1);
return (0);
}
@@ -774,7 +640,7 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
fs->wp = window_pane_next_by_number(fs->w, wp, n);
else
fs->wp = window_pane_previous_by_number(fs->w, wp, n);
if (fs->wp != NULL && !window_pane_outside(fs->wp))
if (fs->wp != NULL)
return (0);
}
@@ -782,13 +648,13 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
idx = strtonum(pane, 0, INT_MAX, &errstr);
if (errstr == NULL) {
fs->wp = window_pane_at_index(fs->w, idx);
if (fs->wp != NULL && !window_pane_outside(fs->wp))
if (fs->wp != NULL)
return (0);
}
/* Try as a description. */
fs->wp = window_find_string(fs->w, pane);
if (fs->wp != NULL && !window_pane_outside(fs->wp))
if (fs->wp != NULL)
return (0);
return (-1);
@@ -796,18 +662,16 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
/* Clear state. */
void
cmd_find_clear_state(struct cmd_find_state *fs, struct cmdq_item *item,
int flags)
cmd_find_clear_state(struct cmd_find_state *fs, int flags)
{
memset(fs, 0, sizeof *fs);
fs->item = item;
fs->flags = flags;
fs->idx = -1;
}
/* Check if state is empty/ */
/* Check if state is empty. */
int
cmd_find_empty_state(struct cmd_find_state *fs)
{
@@ -838,9 +702,7 @@ cmd_find_valid_state(struct cmd_find_state *fs)
if (fs->w != fs->wl->window)
return (0);
if (!window_has_pane(fs->w, fs->wp))
return (0);
return (!window_pane_outside(fs->wp));
return (window_has_pane(fs->w, fs->wp));
}
/* Copy a state. */
@@ -855,11 +717,11 @@ cmd_find_copy_state(struct cmd_find_state *dst, struct cmd_find_state *src)
}
/* Log the result. */
void
static void
cmd_find_log_state(const char *prefix, struct cmd_find_state *fs)
{
if (fs->s != NULL)
log_debug("%s: s=$%u", prefix, fs->s->id);
log_debug("%s: s=$%u %s", prefix, fs->s->id, fs->s->name);
else
log_debug("%s: s=none", prefix);
if (fs->wl != NULL) {
@@ -878,10 +740,10 @@ cmd_find_log_state(const char *prefix, struct cmd_find_state *fs)
}
/* Find state from a session. */
int
cmd_find_from_session(struct cmd_find_state *fs, struct session *s)
void
cmd_find_from_session(struct cmd_find_state *fs, struct session *s, int flags)
{
cmd_find_clear_state(fs, NULL, 0);
cmd_find_clear_state(fs, flags);
fs->s = s;
fs->wl = fs->s->curw;
@@ -889,36 +751,35 @@ cmd_find_from_session(struct cmd_find_state *fs, struct session *s)
fs->wp = fs->w->active;
cmd_find_log_state(__func__, fs);
return (0);
}
/* Find state from a winlink. */
int
cmd_find_from_winlink(struct cmd_find_state *fs, struct session *s,
struct winlink *wl)
void
cmd_find_from_winlink(struct cmd_find_state *fs, struct winlink *wl, int flags)
{
cmd_find_clear_state(fs, NULL, 0);
cmd_find_clear_state(fs, flags);
fs->s = s;
fs->s = wl->session;
fs->wl = wl;
fs->w = wl->window;
fs->wp = wl->window->active;
cmd_find_log_state(__func__, fs);
return (0);
}
/* Find state from a session and window. */
int
cmd_find_from_session_window(struct cmd_find_state *fs, struct session *s,
struct window *w)
struct window *w, int flags)
{
cmd_find_clear_state(fs, NULL, 0);
cmd_find_clear_state(fs, flags);
fs->s = s;
fs->w = w;
if (cmd_find_best_winlink_with_window(fs) != 0)
if (cmd_find_best_winlink_with_window(fs) != 0) {
cmd_find_clear_state(fs, flags);
return (-1);
}
fs->wp = fs->w->active;
cmd_find_log_state(__func__, fs);
@@ -927,28 +788,46 @@ cmd_find_from_session_window(struct cmd_find_state *fs, struct session *s,
/* Find state from a window. */
int
cmd_find_from_window(struct cmd_find_state *fs, struct window *w)
cmd_find_from_window(struct cmd_find_state *fs, struct window *w, int flags)
{
cmd_find_clear_state(fs, NULL, 0);
cmd_find_clear_state(fs, flags);
fs->w = w;
if (cmd_find_best_session_with_window(fs) != 0)
if (cmd_find_best_session_with_window(fs) != 0) {
cmd_find_clear_state(fs, flags);
return (-1);
if (cmd_find_best_winlink_with_window(fs) != 0)
}
if (cmd_find_best_winlink_with_window(fs) != 0) {
cmd_find_clear_state(fs, flags);
return (-1);
}
fs->wp = fs->w->active;
cmd_find_log_state(__func__, fs);
return (0);
}
/* Find state from a winlink and pane. */
void
cmd_find_from_winlink_pane(struct cmd_find_state *fs, struct winlink *wl,
struct window_pane *wp, int flags)
{
cmd_find_clear_state(fs, flags);
fs->s = wl->session;
fs->wl = wl;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = wp;
cmd_find_log_state(__func__, fs);
}
/* Find state from a pane. */
int
cmd_find_from_pane(struct cmd_find_state *fs, struct window_pane *wp)
cmd_find_from_pane(struct cmd_find_state *fs, struct window_pane *wp, int flags)
{
if (cmd_find_from_window(fs, wp->window) != 0)
return (-1);
if (window_pane_outside(wp))
if (cmd_find_from_window(fs, wp->window, flags) != 0)
return (-1);
fs->wp = wp;
@@ -956,56 +835,198 @@ cmd_find_from_pane(struct cmd_find_state *fs, struct window_pane *wp)
return (0);
}
/* Find current state. */
/* Find state from nothing. */
int
cmd_find_current(struct cmd_find_state *fs, struct cmdq_item *item, int flags)
cmd_find_from_nothing(struct cmd_find_state *fs, int flags)
{
cmd_find_clear_state(fs, item, flags);
if (cmd_find_current_session(fs) != 0) {
if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "no current session");
cmd_find_clear_state(fs, flags);
fs->s = cmd_find_best_session(NULL, 0, flags);
if (fs->s == NULL) {
cmd_find_clear_state(fs, flags);
return (-1);
}
fs->wl = fs->s->curw;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = fs->w->active;
cmd_find_log_state(__func__, fs);
return (0);
}
/* Find state from mouse. */
int
cmd_find_from_mouse(struct cmd_find_state *fs, struct mouse_event *m, int flags)
{
cmd_find_clear_state(fs, flags);
if (!m->valid)
return (-1);
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
if (fs->wp == NULL) {
cmd_find_clear_state(fs, flags);
return (-1);
}
fs->w = fs->wl->window;
cmd_find_log_state(__func__, fs);
return (0);
}
/* Find state from client. */
int
cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
{
struct session *s;
struct winlink *wl;
struct window_pane *wp;
/* If no client, treat as from nothing. */
if (c == NULL)
return (cmd_find_from_nothing(fs, flags));
/* If this is an attached client, all done. */
if (c->session != NULL) {
cmd_find_from_session(fs, c->session, flags);
return (0);
}
cmd_find_clear_state(fs, flags);
/*
* If this is an unattached client running in a pane, we can use that
* to limit the list of sessions to those containing that pane.
*/
wp = cmd_find_inside_pane(c);
if (wp == NULL)
goto unknown_pane;
/* If we have a session in TMUX, see if it has this pane. */
s = cmd_find_try_TMUX(c);
if (s != NULL) {
RB_FOREACH(wl, winlinks, &s->windows) {
if (window_has_pane(wl->window, wp))
break;
}
if (wl != NULL) {
log_debug("%s: session $%u has pane %%%u", __func__,
s->id, wp->id);
fs->s = s;
fs->wl = s->curw; /* use current session */
fs->w = fs->wl->window;
fs->wp = fs->w->active; /* use active pane */
cmd_find_log_state(__func__, fs);
return (0);
} else {
log_debug("%s: session $%u does not have pane %%%u",
__func__, s->id, wp->id);
}
}
/*
* Don't have a session, or it doesn't have this pane. Try all
* sessions.
*/
fs->w = wp->window;
if (cmd_find_best_session_with_window(fs) != 0) {
/*
* The window may have been destroyed but the pane
* still on all_window_panes due to something else
* holding a reference.
*/
goto unknown_pane;
}
fs->wl = fs->s->curw;
fs->w = fs->wl->window;
fs->wp = fs->w->active; /* use active pane */
cmd_find_log_state(__func__, fs);
return (0);
unknown_pane:
/*
* We're not running in a known pane, but maybe this client has TMUX
* in the environment. That'd give us a session.
*/
s = cmd_find_try_TMUX(c);
if (s != NULL) {
cmd_find_from_session(fs, s, flags);
return (0);
}
/* Otherwise we need to guess. */
return (cmd_find_from_nothing(fs, flags));
}
/*
* Split target into pieces and resolve for the given type. Fills in the given
* state. Returns 0 on success or -1 on error.
*/
int
cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
struct cmdq_item *item, const char *target, enum cmd_find_type type,
int flags)
cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
const char *target, enum cmd_find_type type, int flags)
{
struct mouse_event *m;
char *colon, *period, *copy = NULL;
const char *session, *window, *pane;
struct cmd_find_state current;
char *colon, *period, *copy = NULL, tmp[256];
const char *session, *window, *pane, *s;
int window_only = 0, pane_only = 0;
/* Can fail flag implies quiet. */
if (flags & CMD_FIND_CANFAIL)
flags |= CMD_FIND_QUIET;
/* Log the arguments. */
if (target == NULL)
log_debug("%s: target none, type %d", __func__, type);
if (type == CMD_FIND_PANE)
s = "pane";
else if (type == CMD_FIND_WINDOW)
s = "window";
else if (type == CMD_FIND_SESSION)
s = "session";
else
log_debug("%s: target %s, type %d", __func__, target, type);
log_debug("%s: item %p, flags %#x", __func__, item, flags);
s = "unknown";
*tmp = '\0';
if (flags & CMD_FIND_PREFER_UNATTACHED)
strlcat(tmp, "PREFER_UNATTACHED,", sizeof tmp);
if (flags & CMD_FIND_QUIET)
strlcat(tmp, "QUIET,", sizeof tmp);
if (flags & CMD_FIND_WINDOW_INDEX)
strlcat(tmp, "WINDOW_INDEX,", sizeof tmp);
if (flags & CMD_FIND_DEFAULT_MARKED)
strlcat(tmp, "DEFAULT_MARKED,", sizeof tmp);
if (flags & CMD_FIND_EXACT_SESSION)
strlcat(tmp, "EXACT_SESSION,", sizeof tmp);
if (flags & CMD_FIND_EXACT_WINDOW)
strlcat(tmp, "EXACT_WINDOW,", sizeof tmp);
if (flags & CMD_FIND_CANFAIL)
strlcat(tmp, "CANFAIL,", sizeof tmp);
if (*tmp != '\0')
tmp[strlen(tmp) - 1] = '\0';
log_debug("%s: target %s, type %s, item %p, flags %s", __func__,
target == NULL ? "none" : target, s, item, tmp);
/* Clear new state. */
cmd_find_clear_state(fs, item, flags);
cmd_find_clear_state(fs, flags);
/* Find current state. */
if (server_check_marked() && (flags & CMD_FIND_DEFAULT_MARKED)) {
fs->current = &marked_pane;
log_debug("%s: current is marked pane", __func__);
} else if (cmd_find_valid_state(&item->current)) {
fs->current = &item->current;
} else if (cmd_find_valid_state(&item->shared->current)) {
fs->current = &item->shared->current;
log_debug("%s: current is from queue", __func__);
} else if (cmd_find_from_client(&current, item->client, flags) == 0) {
fs->current = &current;
log_debug("%s: current is from client", __func__);
} else {
fs->current = current;
log_debug("%s: current is from argument", __func__);
if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "no current target");
goto error;
}
if (!cmd_find_empty_state(fs->current) &&
!cmd_find_valid_state(fs->current))
if (!cmd_find_valid_state(fs->current))
fatalx("invalid current find state");
/* An empty or NULL target is the current. */
@@ -1014,16 +1035,20 @@ cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
/* Mouse target is a plain = or {mouse}. */
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
m = &item->mouse;
m = &item->shared->mouse;
switch (type) {
case CMD_FIND_PANE:
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
if (fs->wp != NULL && !window_pane_outside(fs->wp))
if (fs->wp != NULL) {
fs->w = fs->wl->window;
break;
break;
}
/* FALLTHROUGH */
case CMD_FIND_WINDOW:
case CMD_FIND_SESSION:
fs->wl = cmd_mouse_window(m, &fs->s);
if (fs->wl == NULL && fs->s != NULL)
fs->wl = fs->s->curw;
if (fs->wl != NULL) {
fs->w = fs->wl->window;
fs->wp = fs->w->active;
@@ -1125,9 +1150,16 @@ cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
if (pane != NULL)
pane = cmd_find_map_table(cmd_find_pane_table, pane);
log_debug("target %s (flags %#x): session=%s, window=%s, pane=%s",
target, flags, session == NULL ? "none" : session,
window == NULL ? "none" : window, pane == NULL ? "none" : pane);
if (session != NULL || window != NULL || pane != NULL) {
log_debug("%s: target %s is %s%s%s%s%s%s",
__func__, target,
session == NULL ? "" : "session ",
session == NULL ? "" : session,
window == NULL ? "" : "window ",
window == NULL ? "" : window,
pane == NULL ? "" : "pane ",
pane == NULL ? "" : pane);
}
/* No pane is allowed if want an index. */
if (pane != NULL && (flags & CMD_FIND_WINDOW_INDEX)) {
@@ -1156,7 +1188,8 @@ cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
/* This will fill in winlink and window. */
if (cmd_find_get_window_with_session(fs, window) != 0)
goto no_window;
fs->wp = fs->wl->window->active;
if (fs->wl != NULL) /* can be NULL if index only */
fs->wp = fs->wl->window->active;
goto found;
}
@@ -1196,7 +1229,8 @@ cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
/* This will fill in session, winlink and window. */
if (cmd_find_get_window(fs, window, window_only) != 0)
goto no_window;
fs->wp = fs->wl->window->active;
if (fs->wl != NULL) /* can be NULL if index only */
fs->wp = fs->wl->window->active;
goto found;
}
@@ -1220,6 +1254,8 @@ error:
log_debug("%s: error", __func__);
free(copy);
if (flags & CMD_FIND_CANFAIL)
return (0);
return (-1);
found:
@@ -1231,20 +1267,49 @@ found:
no_session:
if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "can't find session %s", session);
cmdq_error(item, "can't find session: %s", session);
goto error;
no_window:
if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "can't find window %s", window);
cmdq_error(item, "can't find window: %s", window);
goto error;
no_pane:
if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "can't find pane %s", pane);
cmdq_error(item, "can't find pane: %s", pane);
goto error;
}
/* Find the current client. */
static struct client *
cmd_find_current_client(struct cmdq_item *item, int quiet)
{
struct client *c;
struct session *s;
struct window_pane *wp;
struct cmd_find_state fs;
if (item->client != NULL && item->client->session != NULL)
return (item->client);
c = NULL;
if ((wp = cmd_find_inside_pane(item->client)) != NULL) {
cmd_find_clear_state(&fs, CMD_FIND_QUIET);
fs.w = wp->window;
if (cmd_find_best_session_with_window(&fs) == 0)
c = cmd_find_best_client(fs.s);
} else {
s = cmd_find_best_session(NULL, 0, CMD_FIND_QUIET);
if (s != NULL)
c = cmd_find_best_client(s);
}
if (c == NULL && !quiet)
cmdq_error(item, "no current client");
log_debug("%s: no target, return %p", __func__, c);
return (c);
}
/* Find the target client or report an error and return NULL. */
struct client *
cmd_find_client(struct cmdq_item *item, const char *target, int quiet)
@@ -1254,13 +1319,8 @@ cmd_find_client(struct cmdq_item *item, const char *target, int quiet)
size_t size;
/* A NULL argument means the current client. */
if (item != NULL && target == NULL) {
c = cmd_find_current_client(item);
if (c == NULL && !quiet)
cmdq_error(item, "no current client");
log_debug("%s: no target, return %p", __func__, c);
return (c);
}
if (target == NULL)
return (cmd_find_current_client(item, quiet));
copy = xstrdup(target);
/* Trim a single trailing colon if any. */
@@ -1287,7 +1347,7 @@ cmd_find_client(struct cmdq_item *item, const char *target, int quiet)
/* If no client found, report an error. */
if (c == NULL && !quiet)
cmdq_error(item, "can't find client %s", copy);
cmdq_error(item, "can't find client: %s", copy);
free(copy);
log_debug("%s: target %s, return %p", __func__, target, c);

View File

@@ -31,7 +31,6 @@
static enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmdq_item *);
static enum cmd_retval cmd_if_shell_error(struct cmdq_item *, void *);
static void cmd_if_shell_callback(struct job *);
static void cmd_if_shell_free(void *);
@@ -43,15 +42,14 @@ const struct cmd_entry cmd_if_shell_entry = {
.usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command "
"[command]",
.tflag = CMD_PANE_CANFAIL,
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = 0,
.exec = cmd_if_shell_exec
};
struct cmd_if_shell_data {
char *file;
u_int line;
struct cmd_parse_input input;
char *cmd_if;
char *cmd_else;
@@ -65,70 +63,89 @@ static enum cmd_retval
cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct mouse_event *m = &item->shared->mouse;
struct cmd_if_shell_data *cdata;
char *shellcmd, *cmd, *cause;
struct cmd_list *cmdlist;
char *shellcmd, *cmd;
struct cmdq_item *new_item;
struct client *c = item->state.c;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct window_pane *wp = item->state.tflag.wp;
const char *cwd;
if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
else if (s != NULL)
cwd = s->cwd;
else
cwd = NULL;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
struct cmd_parse_input pi;
struct cmd_parse_result *pr;
shellcmd = format_single(item, args->argv[0], c, s, wl, wp);
if (args_has(args, 'F')) {
cmd = NULL;
if (*shellcmd != '0' && *shellcmd != '\0')
cmd = args->argv[1];
else if (args->argc == 3)
cmd = args->argv[2];
else
cmd = NULL;
free(shellcmd);
if (cmd == NULL)
return (CMD_RETURN_NORMAL);
cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);
if (cmdlist == NULL) {
if (cause != NULL) {
cmdq_error(item, "%s", cause);
free(cause);
}
memset(&pi, 0, sizeof pi);
if (self->file != NULL)
pi.file = self->file;
pi.line = self->line;
pi.item = item;
pi.c = c;
cmd_find_copy_state(&pi.fs, &item->target);
pr = cmd_parse_from_string(cmd, &pi);
switch (pr->status) {
case CMD_PARSE_EMPTY:
break;
case CMD_PARSE_ERROR:
cmdq_error(item, "%s", pr->error);
free(pr->error);
return (CMD_RETURN_ERROR);
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, NULL, m, 0);
cmdq_insert_after(item, new_item);
cmd_list_free(pr->cmdlist);
break;
}
new_item = cmdq_get_command(cmdlist, NULL, &item->mouse, 0);
cmdq_insert_after(item, new_item);
cmd_list_free(cmdlist);
return (CMD_RETURN_NORMAL);
}
cdata = xcalloc(1, sizeof *cdata);
if (self->file != NULL) {
cdata->file = xstrdup(self->file);
cdata->line = self->line;
}
cdata->cmd_if = xstrdup(args->argv[1]);
if (args->argc == 3)
cdata->cmd_else = xstrdup(args->argv[2]);
else
cdata->cmd_else = NULL;
memcpy(&cdata->mouse, m, sizeof cdata->mouse);
cdata->client = item->client;
cdata->client->references++;
if (cdata->client != NULL)
cdata->client->references++;
if (!args_has(args, 'b'))
cdata->item = item;
else
cdata->item = NULL;
memcpy(&cdata->mouse, &item->mouse, sizeof cdata->mouse);
job_run(shellcmd, s, cwd, cmd_if_shell_callback, cmd_if_shell_free,
cdata);
memset(&cdata->input, 0, sizeof cdata->input);
if (self->file != NULL)
cdata->input.file = xstrdup(self->file);
cdata->input.line = self->line;
cdata->input.item = cdata->item;
cdata->input.c = c;
if (cdata->input.c != NULL)
cdata->input.c->references++;
cmd_find_copy_state(&cdata->input.fs, &item->target);
if (job_run(shellcmd, s, server_client_get_cwd(item->client, s), NULL,
cmd_if_shell_callback, cmd_if_shell_free, cdata, 0) == NULL) {
cmdq_error(item, "failed to run command: %s", shellcmd);
free(shellcmd);
free(cdata);
return (CMD_RETURN_ERROR);
}
free(shellcmd);
if (args_has(args, 'b'))
@@ -136,45 +153,39 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_WAIT);
}
static enum cmd_retval
cmd_if_shell_error(struct cmdq_item *item, void *data)
{
char *error = data;
cmdq_error(item, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static void
cmd_if_shell_callback(struct job *job)
{
struct cmd_if_shell_data *cdata = job->data;
struct cmd_if_shell_data *cdata = job_get_data(job);
struct client *c = cdata->client;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
char *cause, *cmd, *file = cdata->file;
u_int line = cdata->line;
struct mouse_event *m = &cdata->mouse;
struct cmdq_item *new_item = NULL;
char *cmd;
int status;
struct cmd_parse_result *pr;
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
status = job_get_status(job);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
cmd = cdata->cmd_else;
else
cmd = cdata->cmd_if;
if (cmd == NULL)
goto out;
cmdlist = cmd_string_parse(cmd, file, line, &cause);
if (cmdlist == NULL) {
if (cause != NULL)
new_item = cmdq_get_callback(cmd_if_shell_error, cause);
else
new_item = NULL;
} else {
new_item = cmdq_get_command(cmdlist, NULL, &cdata->mouse, 0);
cmd_list_free(cmdlist);
pr = cmd_parse_from_string(cmd, &cdata->input);
switch (pr->status) {
case CMD_PARSE_EMPTY:
break;
case CMD_PARSE_ERROR:
if (cdata->item != NULL)
cmdq_error(cdata->item, "%s", pr->error);
free(pr->error);
break;
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, NULL, m, 0);
cmd_list_free(pr->cmdlist);
break;
}
if (new_item != NULL) {
if (cdata->item == NULL)
cmdq_append(c, new_item);
@@ -192,11 +203,15 @@ cmd_if_shell_free(void *data)
{
struct cmd_if_shell_data *cdata = data;
server_client_unref(cdata->client);
if (cdata->client != NULL)
server_client_unref(cdata->client);
free(cdata->cmd_else);
free(cdata->cmd_if);
free(cdata->file);
if (cdata->input.c != NULL)
server_client_unref(cdata->input.c);
free((void *)cdata->input.file);
free(cdata);
}

View File

@@ -37,8 +37,8 @@ const struct cmd_entry cmd_join_pane_entry = {
.args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.sflag = CMD_PANE_MARKED,
.tflag = CMD_PANE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_join_pane_exec
@@ -51,8 +51,8 @@ const struct cmd_entry cmd_move_pane_entry = {
.args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.sflag = CMD_PANE,
.tflag = CMD_PANE,
.source = { 's', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_join_pane_exec
@@ -62,6 +62,7 @@ static enum cmd_retval
cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
struct session *dst_s;
struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w;
@@ -70,22 +71,22 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
int size, percentage, dst_idx;
enum layout_type type;
struct layout_cell *lc;
int not_same_window;
int not_same_window, flags;
if (self->entry == &cmd_join_pane_entry)
not_same_window = 1;
else
not_same_window = 0;
dst_s = item->state.tflag.s;
dst_wl = item->state.tflag.wl;
dst_wp = item->state.tflag.wp;
dst_s = item->target.s;
dst_wl = item->target.wl;
dst_wp = item->target.wp;
dst_w = dst_wl->window;
dst_idx = dst_wl->idx;
server_unzoom_window(dst_w);
src_wl = item->state.sflag.wl;
src_wp = item->state.sflag.wp;
src_wl = item->source.wl;
src_wp = item->source.wp;
src_w = src_wl->window;
server_unzoom_window(src_w);
@@ -122,7 +123,11 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
else
size = (dst_wp->sx * percentage) / 100;
}
lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b'), 0);
if (args_has(args, 'b'))
flags = SPAWN_BEFORE;
else
flags = 0;
lc = layout_split_pane(dst_wp, type, size, flags);
if (lc == NULL) {
cmdq_error(item, "create pane failed: pane too small");
return (CMD_RETURN_ERROR);
@@ -143,8 +148,9 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
server_redraw_window(dst_w);
if (!args_has(args, 'd')) {
window_set_active_pane(dst_w, src_wp);
window_set_active_pane(dst_w, src_wp, 1);
session_select(dst_s, dst_idx);
cmd_find_from_session(current, dst_s, 0);
server_redraw_session(dst_s);
} else
server_status_session(dst_s);

View File

@@ -35,7 +35,7 @@ const struct cmd_entry cmd_kill_pane_entry = {
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_kill_pane_exec
@@ -44,12 +44,11 @@ const struct cmd_entry cmd_kill_pane_entry = {
static enum cmd_retval
cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct winlink *wl = item->state.tflag.wl;
struct window_pane *loopwp, *tmpwp, *wp = item->state.tflag.wp;
server_unzoom_window(wl->window);
struct winlink *wl = item->target.wl;
struct window_pane *loopwp, *tmpwp, *wp = item->target.wp;
if (args_has(self->args, 'a')) {
server_unzoom_window(wl->window);
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
if (loopwp == wp)
continue;
@@ -60,13 +59,6 @@ cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
if (window_count_panes(wl->window) == 1) {
server_kill_window(wl->window);
recalculate_sizes();
} else {
layout_close_pane(wp);
window_remove_pane(wl->window, wp);
server_redraw_window(wl->window);
}
server_kill_pane(wp);
return (CMD_RETURN_NORMAL);
}

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_kill_session_entry = {
.args = { "aCt:", 0, 0 },
.usage = "[-aC] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0,
.exec = cmd_kill_session_exec
@@ -49,7 +49,7 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
struct session *s, *sloop, *stmp;
struct winlink *wl;
s = item->state.tflag.s;
s = item->target.s;
if (args_has(args, 'C')) {
RB_FOREACH(wl, winlinks, &s->windows) {
@@ -61,12 +61,12 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) {
if (sloop != s) {
server_destroy_session(sloop);
session_destroy(sloop);
session_destroy(sloop, 1, __func__);
}
}
} else {
server_destroy_session(s);
session_destroy(s);
session_destroy(s, 1, __func__);
}
return (CMD_RETURN_NORMAL);
}

View File

@@ -33,7 +33,7 @@ const struct cmd_entry cmd_kill_window_entry = {
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_kill_window_exec
@@ -46,7 +46,7 @@ const struct cmd_entry cmd_unlink_window_entry = {
.args = { "kt:", 0, 0 },
.usage = "[-k] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_kill_window_exec
@@ -56,9 +56,9 @@ static enum cmd_retval
cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl, *wl2, *wl3;
struct winlink *wl = item->target.wl, *wl2, *wl3;
struct window *w = wl->window;
struct session *s = item->state.tflag.s;
struct session *s = item->target.s;
if (self->entry == &cmd_unlink_window_entry) {
if (!args_has(self->args, 'k') && !session_is_linked(s, w)) {

View File

@@ -57,7 +57,7 @@ cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item)
pb = NULL;
while ((pb = paste_walk(pb)) != NULL) {
ft = format_create(item, FORMAT_NONE, 0);
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults_paste_buffer(ft, pb);
line = format_expand(ft, template);

View File

@@ -42,7 +42,7 @@ const struct cmd_entry cmd_list_clients_entry = {
.args = { "F:t:", 0, 0 },
.usage = "[-F format] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_READONLY|CMD_AFTERHOOK,
.exec = cmd_list_clients_exec
@@ -60,7 +60,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
char *line;
if (args_has(args, 't'))
s = item->state.tflag.s;
s = item->target.s;
else
s = NULL;
@@ -72,7 +72,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
if (c->session == NULL || (s != NULL && s != c->session))
continue;
ft = format_create(item, FORMAT_NONE, 0);
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", idx);
format_defaults(ft, c, NULL, NULL, NULL);

View File

@@ -60,8 +60,8 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
struct args *args = self->args;
struct key_table *table;
struct key_binding *bd;
const char *key, *tablename, *r;
char *cp, tmp[BUFSIZ];
const char *tablename, *r;
char *key, *cp, tmp[BUFSIZ];
int repeat, width, tablewidth, keywidth;
if (self->entry == &cmd_list_commands_entry)
@@ -75,13 +75,17 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
repeat = 0;
tablewidth = keywidth = 0;
RB_FOREACH(table, key_tables, &key_tables) {
if (tablename != NULL && strcmp(table->name, tablename) != 0)
table = key_bindings_first_table ();
while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table);
continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
key = key_string_lookup_key(bd->key);
}
bd = key_bindings_first(table);
while (bd != NULL) {
key = args_escape(key_string_lookup_key(bd->key));
if (bd->can_repeat)
if (bd->flags & KEY_BINDING_REPEAT)
repeat = 1;
width = utf8_cstrwidth(table->name);
@@ -90,18 +94,26 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
width = utf8_cstrwidth(key);
if (width > keywidth)
keywidth = width;
free(key);
bd = key_bindings_next(table, bd);
}
table = key_bindings_next_table(table);
}
RB_FOREACH(table, key_tables, &key_tables) {
if (tablename != NULL && strcmp(table->name, tablename) != 0)
table = key_bindings_first_table ();
while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table);
continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
key = key_string_lookup_key(bd->key);
}
bd = key_bindings_first(table);
while (bd != NULL) {
key = args_escape(key_string_lookup_key(bd->key));
if (!repeat)
r = "";
else if (bd->can_repeat)
else if (bd->flags & KEY_BINDING_REPEAT)
r = "-r ";
else
r = " ";
@@ -117,12 +129,16 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
strlcat(tmp, " ", sizeof tmp);
free(cp);
cp = cmd_list_print(bd->cmdlist);
cp = cmd_list_print(bd->cmdlist, 1);
strlcat(tmp, cp, sizeof tmp);
free(cp);
cmdq_print(item, "bind-key %s", tmp);
free(key);
bd = key_bindings_next(table, bd);
}
table = key_bindings_next_table(table);
}
return (CMD_RETURN_NORMAL);
@@ -144,7 +160,7 @@ cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
"#{command_list_usage}";
}
ft = format_create(item, FORMAT_NONE, 0);
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, NULL, NULL, NULL, NULL);
for (entryp = cmd_table; *entryp != NULL; entryp++) {

View File

@@ -41,7 +41,7 @@ const struct cmd_entry cmd_list_panes_entry = {
.args = { "asF:t:", 0, 0 },
.usage = "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_list_panes_exec
@@ -51,8 +51,8 @@ static enum cmd_retval
cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
if (args_has(args, 'a'))
cmd_list_panes_server(self, item);
@@ -123,7 +123,7 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
n = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
ft = format_create(item, FORMAT_NONE, 0);
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, wp);

View File

@@ -30,8 +30,7 @@
#define LIST_SESSIONS_TEMPLATE \
"#{session_name}: #{session_windows} windows " \
"(created #{t:session_created}) " \
"[#{session_width}x#{session_height}]" \
"(created #{t:session_created})" \
"#{?session_grouped, (group ,}" \
"#{session_group}#{?session_grouped,),}" \
"#{?session_attached, (attached),}"
@@ -65,7 +64,7 @@ cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
n = 0;
RB_FOREACH(s, sessions, &sessions) {
ft = format_create(item, FORMAT_NONE, 0);
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, NULL, NULL);

View File

@@ -52,7 +52,7 @@ const struct cmd_entry cmd_list_windows_entry = {
.args = { "F:at:", 0, 0 },
.usage = "[-a] [-F format] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_list_windows_exec
@@ -66,7 +66,7 @@ cmd_list_windows_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'a'))
cmd_list_windows_server(self, item);
else
cmd_list_windows_session(self, item->state.tflag.s, item, 0);
cmd_list_windows_session(self, item->target.s, item, 0);
return (CMD_RETURN_NORMAL);
}
@@ -86,7 +86,7 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
{
struct args *args = self->args;
struct winlink *wl;
u_int n;
u_int n;
struct format_tree *ft;
const char *template;
char *line;
@@ -105,7 +105,7 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
n = 0;
RB_FOREACH(wl, winlinks, &s->windows) {
ft = format_create(item, FORMAT_NONE, 0);
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, NULL);

View File

@@ -23,62 +23,37 @@
#include "tmux.h"
static u_int cmd_list_next_group = 1;
struct cmd_list *
cmd_list_parse(int argc, char **argv, const char *file, u_int line,
char **cause)
cmd_list_new(void)
{
struct cmd_list *cmdlist;
struct cmd *cmd;
int i, lastsplit;
size_t arglen, new_argc;
char **copy_argv, **new_argv;
copy_argv = cmd_copy_argv(argc, argv);
cmdlist = xcalloc(1, sizeof *cmdlist);
cmdlist->references = 1;
cmdlist->group = cmd_list_next_group++;
TAILQ_INIT(&cmdlist->list);
lastsplit = 0;
for (i = 0; i < argc; i++) {
arglen = strlen(copy_argv[i]);
if (arglen == 0 || copy_argv[i][arglen - 1] != ';')
continue;
copy_argv[i][arglen - 1] = '\0';
if (arglen > 1 && copy_argv[i][arglen - 2] == '\\') {
copy_argv[i][arglen - 2] = ';';
continue;
}
new_argc = i - lastsplit;
new_argv = copy_argv + lastsplit;
if (arglen != 1)
new_argc++;
cmd = cmd_parse(new_argc, new_argv, file, line, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
lastsplit = i + 1;
}
if (lastsplit != argc) {
cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit,
file, line, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
}
cmd_free_argv(argc, copy_argv);
return (cmdlist);
}
bad:
cmd_list_free(cmdlist);
cmd_free_argv(argc, copy_argv);
return (NULL);
void
cmd_list_append(struct cmd_list *cmdlist, struct cmd *cmd)
{
cmd->group = cmdlist->group;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
}
void
cmd_list_move(struct cmd_list *cmdlist, struct cmd_list *from)
{
struct cmd *cmd, *cmd1;
TAILQ_FOREACH_SAFE(cmd, &from->list, qentry, cmd1) {
TAILQ_REMOVE(&from->list, cmd, qentry);
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
}
cmdlist->group = cmd_list_next_group++;
}
void
@@ -91,16 +66,14 @@ cmd_list_free(struct cmd_list *cmdlist)
TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) {
TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
args_free(cmd->args);
free(cmd->file);
free(cmd);
cmd_free(cmd);
}
free(cmdlist);
}
char *
cmd_list_print(struct cmd_list *cmdlist)
cmd_list_print(struct cmd_list *cmdlist, int escaped)
{
struct cmd *cmd;
char *buf, *this;
@@ -112,12 +85,16 @@ cmd_list_print(struct cmd_list *cmdlist)
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
this = cmd_print(cmd);
len += strlen(this) + 3;
len += strlen(this) + 4;
buf = xrealloc(buf, len);
strlcat(buf, this, len);
if (TAILQ_NEXT(cmd, qentry) != NULL)
strlcat(buf, " ; ", len);
if (TAILQ_NEXT(cmd, qentry) != NULL) {
if (escaped)
strlcat(buf, " \\; ", len);
else
strlcat(buf, " ; ", len);
}
free(this);
}

View File

@@ -56,10 +56,14 @@ cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_load_buffer_data *cdata;
struct client *c = item->client;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
FILE *f;
const char *path, *bufname;
char *pdata, *new_pdata, *cause, *file;
const char *bufname;
char *pdata = NULL, *new_pdata, *cause;
char *path, *file;
size_t psize;
int ch, error;
@@ -67,8 +71,11 @@ cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'b'))
bufname = args_get(args, 'b');
path = args->argv[0];
path = format_single(item, args->argv[0], c, s, wl, wp);
if (strcmp(path, "-") == 0) {
free(path);
c = item->client;
cdata = xcalloc(1, sizeof *cdata);
cdata->item = item;
@@ -78,19 +85,21 @@ cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
error = server_set_stdin_callback(c, cmd_load_buffer_callback,
cdata, &cause);
if (error != 0) {
cmdq_error(item, "%s: %s", path, cause);
cmdq_error(item, "-: %s", cause);
free(cause);
free(cdata);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_WAIT);
}
file = server_client_get_path(c, path);
file = server_client_get_path(item->client, path);
free(path);
f = fopen(file, "rb");
if (f == NULL) {
cmdq_error(item, "%s: %s", file, strerror(errno));
free(file);
return (CMD_RETURN_ERROR);
goto error;
}
pdata = NULL;
@@ -127,6 +136,7 @@ error:
free(pdata);
if (f != NULL)
fclose(f);
free(file);
return (CMD_RETURN_ERROR);
}

View File

@@ -44,7 +44,7 @@ const struct cmd_entry cmd_lock_session_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_lock_server_exec
@@ -57,22 +57,25 @@ const struct cmd_entry cmd_lock_client_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = CMD_AFTERHOOK,
.exec = cmd_lock_server_exec
};
static enum cmd_retval
cmd_lock_server_exec(struct cmd *self, __unused struct cmdq_item *item)
cmd_lock_server_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c;
if (self->entry == &cmd_lock_server_entry)
server_lock();
else if (self->entry == &cmd_lock_session_entry)
server_lock_session(item->state.tflag.s);
else
server_lock_client(item->state.c);
server_lock_session(item->target.s);
else {
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
server_lock_client(c);
}
recalculate_sizes();
return (CMD_RETURN_NORMAL);

View File

@@ -35,8 +35,8 @@ const struct cmd_entry cmd_move_window_entry = {
.args = { "adkrs:t:", 0, 0 },
.usage = "[-dkr] " CMD_SRCDST_WINDOW_USAGE,
.sflag = CMD_WINDOW,
.tflag = CMD_MOVEW_R,
.source = { 's', CMD_FIND_WINDOW, 0 },
/* -t is special */
.flags = 0,
.exec = cmd_move_window_exec
@@ -49,8 +49,8 @@ const struct cmd_entry cmd_link_window_entry = {
.args = { "adks:t:", 0, 0 },
.usage = "[-dk] " CMD_SRCDST_WINDOW_USAGE,
.sflag = CMD_WINDOW,
.tflag = CMD_WINDOW_INDEX,
.source = { 's', CMD_FIND_WINDOW, 0 },
/* -t is special */
.flags = 0,
.exec = cmd_move_window_exec
@@ -60,18 +60,31 @@ static enum cmd_retval
cmd_move_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct session *src = item->state.sflag.s;
struct session *dst = item->state.tflag.s;
struct winlink *wl = item->state.sflag.wl;
const char *tflag = args_get(args, 't');
struct session *src;
struct session *dst;
struct winlink *wl;
char *cause;
int idx = item->state.tflag.idx, kflag, dflag, sflag;
int idx, kflag, dflag, sflag;
if (args_has(args, 'r')) {
session_renumber_windows(dst);
if (cmd_find_target(&item->target, item, tflag,
CMD_FIND_SESSION, CMD_FIND_QUIET) != 0)
return (CMD_RETURN_ERROR);
session_renumber_windows(item->target.s);
recalculate_sizes();
server_status_session(item->target.s);
return (CMD_RETURN_NORMAL);
}
if (cmd_find_target(&item->target, item, tflag, CMD_FIND_WINDOW,
CMD_FIND_WINDOW_INDEX) != 0)
return (CMD_RETURN_ERROR);
src = item->source.s;
dst = item->target.s;
wl = item->source.wl;
idx = item->target.idx;
kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd');

View File

@@ -44,7 +44,7 @@ const struct cmd_entry cmd_new_session_entry = {
"[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
"[-y height] [command]",
.tflag = CMD_SESSION_CANFAIL,
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_STARTSERVER,
.exec = cmd_new_session_exec
@@ -57,7 +57,7 @@ const struct cmd_entry cmd_has_session_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0,
.exec = cmd_new_session_exec
@@ -69,22 +69,22 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
struct args *args = self->args;
struct client *c = item->client;
struct session *s, *as, *groupwith;
struct window *w;
struct environ *env;
struct options *oo;
struct termios tio, *tiop;
struct session_group *sg;
const char *newname, *errstr, *template, *group, *prefix;
const char *path, *cmd, *cwd, *to_free = NULL;
char **argv, *cause, *cp;
int detached, already_attached, idx, argc;
u_int sx, sy;
struct environ_entry *envent;
struct cmd_find_state fs;
const char *errstr, *template, *group, *prefix, *tmp;
char *cause, *cwd = NULL, *cp, *newname = NULL;
int detached, already_attached, is_control = 0;
u_int sx, sy, dsx, dsy;
struct spawn_context sc;
enum cmd_retval retval;
struct cmd_find_state fs;
if (self->entry == &cmd_has_session_entry) {
/*
* cmd_prepare() will fail if the session cannot be found,
* hence always return success here.
* cmd_find_target() will fail if the session cannot be found,
* so always return success here.
*/
return (CMD_RETURN_NORMAL);
}
@@ -94,38 +94,34 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
newname = args_get(args, 's');
if (newname != NULL) {
if (args_has(args, 's')) {
newname = format_single(item, args_get(args, 's'), c, NULL,
NULL, NULL);
if (!session_check_name(newname)) {
cmdq_error(item, "bad session name: %s", newname);
return (CMD_RETURN_ERROR);
goto fail;
}
if ((as = session_find(newname)) != NULL) {
if (args_has(args, 'A')) {
/*
* This item is now destined for
* attach-session. Because attach-session will
* have already been prepared, copy this
* session into its tflag so it can be used.
*/
cmd_find_from_session(&item->state.tflag, as);
return (cmd_attach_session(item,
args_has(args, 'D'), 0, NULL,
args_has(args, 'E')));
retval = cmd_attach_session(item,
newname, args_has(args, 'D'),
0, NULL, args_has(args, 'E'));
free(newname);
return (retval);
}
cmdq_error(item, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR);
goto fail;
}
}
/* Is this going to be part of a session group? */
group = args_get(args, 't');
if (group != NULL) {
groupwith = item->state.tflag.s;
groupwith = item->target.s;
if (groupwith == NULL) {
if (!session_check_name(group)) {
cmdq_error(item, "bad group name: %s", group);
goto error;
goto fail;
}
sg = session_group_find(group);
} else
@@ -146,6 +142,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
detached = args_has(args, 'd');
if (c == NULL)
detached = 1;
else if (c->flags & CLIENT_CONTROL)
is_control = 1;
/* Is this client already attached? */
already_attached = 0;
@@ -153,13 +151,10 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
already_attached = 1;
/* Get the new session working directory. */
if (args_has(args, 'c')) {
cwd = args_get(args, 'c');
to_free = cwd = format_single(item, cwd, c, NULL, NULL, NULL);
} else if (c != NULL && c->session == NULL && c->cwd != NULL)
cwd = c->cwd;
if ((tmp = args_get(args, 'c')) != NULL)
cwd = format_single(item, tmp, c, NULL, NULL, NULL);
else
cwd = ".";
cwd = xstrdup(server_client_get_cwd(c, NULL));
/*
* If this is a new client, check for nesting and save the termios
@@ -174,7 +169,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (server_client_check_nested(item->client)) {
cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force");
return (CMD_RETURN_ERROR);
goto fail;
}
if (tcgetattr(c->tty.fd, &tio) != 0)
fatal("tcgetattr failed");
@@ -187,85 +182,97 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (server_client_open(c, &cause) != 0) {
cmdq_error(item, "open terminal failed: %s", cause);
free(cause);
goto error;
goto fail;
}
}
/* Get default session size. */
if (args_has(args, 'x')) {
tmp = args_get(args, 'x');
if (strcmp(tmp, "-") == 0) {
if (c != NULL)
dsx = c->tty.sx;
else
dsx = 80;
} else {
dsx = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "width %s", errstr);
goto fail;
}
}
}
if (args_has(args, 'y')) {
tmp = args_get(args, 'y');
if (strcmp(tmp, "-") == 0) {
if (c != NULL)
dsy = c->tty.sy;
else
dsy = 24;
} else {
dsy = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
goto fail;
}
}
}
/* Find new session size. */
if (c != NULL) {
if (!detached && !is_control) {
sx = c->tty.sx;
sy = c->tty.sy;
if (sy > 0 && options_get_number(global_s_options, "status"))
sy--;
} else {
sx = 80;
sy = 24;
}
if (detached && args_has(args, 'x')) {
sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "width %s", errstr);
goto error;
tmp = options_get_string(global_s_options, "default-size");
if (sscanf(tmp, "%ux%u", &sx, &sy) != 2) {
sx = 80;
sy = 24;
}
if (args_has(args, 'x'))
sx = dsx;
if (args_has(args, 'y'))
sy = dsy;
}
if (detached && args_has(args, 'y')) {
sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
goto error;
}
}
if (sy > 0 && options_get_number(global_s_options, "status"))
sy--;
if (sx == 0)
sx = 1;
if (sy == 0)
sy = 1;
/* Figure out the command for the new window. */
argc = -1;
argv = NULL;
if (!args_has(args, 't') && args->argc != 0) {
argc = args->argc;
argv = args->argv;
} else if (sg == NULL && groupwith == NULL) {
cmd = options_get_string(global_s_options, "default-command");
if (cmd != NULL && *cmd != '\0') {
argc = 1;
argv = (char **)&cmd;
} else {
argc = 0;
argv = NULL;
}
/* Create the new session. */
oo = options_create(global_s_options);
if (args_has(args, 'x') || args_has(args, 'y')) {
if (!args_has(args, 'x'))
dsx = sx;
if (!args_has(args, 'y'))
dsy = sy;
options_set_string(oo, "default-size", 0, "%ux%u", dsx, dsy);
}
path = NULL;
if (c != NULL && c->session == NULL)
envent = environ_find(c->environ, "PATH");
else
envent = environ_find(global_environ, "PATH");
if (envent != NULL)
path = envent->value;
/* Construct the environment. */
env = environ_create();
if (c != NULL && !args_has(args, 'E'))
environ_update(global_s_options, c->environ, env);
s = session_create(prefix, newname, cwd, env, oo, tiop);
/* Create the new session. */
idx = -1 - options_get_number(global_s_options, "base-index");
s = session_create(prefix, newname, argc, argv, path, cwd, env, tiop,
idx, sx, sy, &cause);
environ_free(env);
if (s == NULL) {
cmdq_error(item, "create session failed: %s", cause);
/* Spawn the initial window. */
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
sc.name = args_get(args, 'n');
sc.argc = args->argc;
sc.argv = args->argv;
sc.idx = -1;
sc.cwd = args_get(args, 'c');
sc.flags = 0;
if (spawn_window(&sc, &cause) == NULL) {
session_destroy(s, 0, __func__);
cmdq_error(item, "create window failed: %s", cause);
free(cause);
goto error;
}
/* Set the initial window name if one given. */
if (argc >= 0 && args_has(args, 'n')) {
w = s->curw->window;
window_set_name(w, args_get(args, 'n'));
options_set_number(w->options, "automatic-rename", 0);
goto fail;
}
/*
@@ -297,8 +304,9 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
} else if (c->session != NULL)
c->last_session = c->session;
c->session = s;
if (!item->repeat)
if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
@@ -324,19 +332,20 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
free(cp);
}
if (!detached)
if (!detached) {
c->flags |= CLIENT_ATTACHED;
cmd_find_from_session(&item->shared->current, s, 0);
}
if (to_free != NULL)
free((void *)to_free);
cmd_find_from_session(&fs, s);
hooks_insert(s->hooks, item, &fs, "after-new-session");
cmd_find_from_session(&fs, s, 0);
cmdq_insert_hook(s, item, &fs, "after-new-session");
free(cwd);
free(newname);
return (CMD_RETURN_NORMAL);
error:
if (to_free != NULL)
free((void *)to_free);
fail:
free(cwd);
free(newname);
return (CMD_RETURN_ERROR);
}

View File

@@ -38,11 +38,11 @@ const struct cmd_entry cmd_new_window_entry = {
.name = "new-window",
.alias = "neww",
.args = { "ac:dF:kn:Pt:", 0, -1 },
.usage = "[-adkP] [-c start-directory] [-F format] [-n window-name] "
CMD_TARGET_WINDOW_USAGE " [command]",
.args = { "ac:de:F:kn:Pt:", 0, -1 },
.usage = "[-adkP] [-c start-directory] [-e environment] [-F format] "
"[-n window-name] " CMD_TARGET_WINDOW_USAGE " [command]",
.tflag = CMD_WINDOW_INDEX,
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
.flags = 0,
.exec = cmd_new_window_exec
@@ -52,86 +52,54 @@ static enum cmd_retval
cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct client *c = item->state.c;
int idx = item->state.tflag.idx;
const char *cmd, *path, *template, *cwd, *to_free;
char **argv, *cause, *cp;
int argc, detached;
struct environ_entry *envent;
struct cmd_find_state *current = &item->shared->current;
struct spawn_context sc;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
int idx = item->target.idx;
struct winlink *new_wl;
char *cause = NULL, *cp;
const char *template, *add;
struct cmd_find_state fs;
struct args_value *value;
if (args_has(args, 'a')) {
if ((idx = winlink_shuffle_up(s, wl)) == -1) {
cmdq_error(item, "no free window indexes");
return (CMD_RETURN_ERROR);
}
}
detached = args_has(args, 'd');
if (args->argc == 0) {
cmd = options_get_string(s->options, "default-command");
if (cmd != NULL && *cmd != '\0') {
argc = 1;
argv = (char **)&cmd;
} else {
argc = 0;
argv = NULL;
}
} else {
argc = args->argc;
argv = args->argv;
if (args_has(args, 'a') && (idx = winlink_shuffle_up(s, wl)) == -1) {
cmdq_error(item, "couldn't get a window index");
return (CMD_RETURN_ERROR);
}
path = NULL;
if (item->client != NULL && item->client->session == NULL)
envent = environ_find(item->client->environ, "PATH");
else
envent = environ_find(s->environ, "PATH");
if (envent != NULL)
path = envent->value;
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
to_free = NULL;
if (args_has(args, 'c')) {
cwd = args_get(args, 'c');
to_free = cwd = format_single(item, cwd, c, s, NULL, NULL);
} else if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
else
cwd = s->cwd;
sc.name = args_get(args, 'n');
sc.argc = args->argc;
sc.argv = args->argv;
sc.environ = environ_create();
wl = NULL;
if (idx != -1)
wl = winlink_find_by_index(&s->windows, idx);
if (wl != NULL && args_has(args, 'k')) {
/*
* Can't use session_detach as it will destroy session if this
* makes it empty.
*/
notify_session_window("window-unlinked", s, wl->window);
wl->flags &= ~WINLINK_ALERTFLAGS;
winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl);
/* Force select/redraw if current. */
if (wl == s->curw) {
detached = 0;
s->curw = NULL;
}
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
add = args_next_value(&value);
}
if (idx == -1)
idx = -1 - options_get_number(s->options, "base-index");
wl = session_new(s, args_get(args, 'n'), argc, argv, path, cwd, idx,
&cause);
if (wl == NULL) {
sc.idx = idx;
sc.cwd = args_get(args, 'c');
sc.flags = 0;
if (args_has(args, 'd'))
sc.flags |= SPAWN_DETACHED;
if (args_has(args, 'k'))
sc.flags |= SPAWN_KILL;
if ((new_wl = spawn_window(&sc, &cause)) == NULL) {
cmdq_error(item, "create window failed: %s", cause);
free(cause);
goto error;
return (CMD_RETURN_ERROR);
}
if (!detached) {
session_select(s, wl->idx);
if (!args_has(args, 'd') || new_wl == s->curw) {
cmd_find_from_winlink(current, new_wl, 0);
server_redraw_session_group(s);
} else
server_status_session_group(s);
@@ -139,21 +107,14 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = NEW_WINDOW_TEMPLATE;
cp = format_single(item, template, c, s, wl, NULL);
cp = format_single(item, template, c, s, new_wl, NULL);
cmdq_print(item, "%s", cp);
free(cp);
}
if (to_free != NULL)
free((void *)to_free);
cmd_find_from_winlink(&fs, s, wl);
hooks_insert(s->hooks, item, &fs, "after-new-window");
cmd_find_from_winlink(&fs, new_wl, 0);
cmdq_insert_hook(s, item, &fs, "after-new-window");
environ_free(sc.environ);
return (CMD_RETURN_NORMAL);
error:
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_ERROR);
}

1471
cmd-parse.y Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -37,7 +37,7 @@ const struct cmd_entry cmd_paste_buffer_entry = {
.usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " "
CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_paste_buffer_exec
@@ -47,7 +47,7 @@ static enum cmd_retval
cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct window_pane *wp = item->state.tflag.wp;
struct window_pane *wp = item->target.wp;
struct paste_buffer *pb;
const char *sepstr, *bufname, *bufdata, *bufend, *line;
size_t seplen, bufsize;

View File

@@ -21,6 +21,7 @@
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -34,16 +35,18 @@
static enum cmd_retval cmd_pipe_pane_exec(struct cmd *, struct cmdq_item *);
static void cmd_pipe_pane_read_callback(struct bufferevent *, void *);
static void cmd_pipe_pane_write_callback(struct bufferevent *, void *);
static void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *);
const struct cmd_entry cmd_pipe_pane_entry = {
.name = "pipe-pane",
.alias = "pipep",
.args = { "ot:", 0, 1 },
.usage = "[-o] " CMD_TARGET_PANE_USAGE " [command]",
.args = { "IOot:", 0, 1 },
.usage = "[-IOo] " CMD_TARGET_PANE_USAGE " [command]",
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_pipe_pane_exec
@@ -53,13 +56,14 @@ static enum cmd_retval
cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct window_pane *wp = item->state.tflag.wp;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct client *c = cmd_find_client(item, NULL, 1);
struct window_pane *wp = item->target.wp;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
char *cmd;
int old_fd, pipe_fd[2], null_fd;
int old_fd, pipe_fd[2], null_fd, in, out;
struct format_tree *ft;
sigset_t set, oldset;
/* Destroy the old pipe. */
old_fd = wp->pipe_fd;
@@ -67,6 +71,11 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
bufferevent_free(wp->pipe_event);
close(wp->pipe_fd);
wp->pipe_fd = -1;
if (window_pane_destroy_ready(wp)) {
server_destroy_pane(wp, 1);
return (CMD_RETURN_NORMAL);
}
}
/* If no pipe command, that is enough. */
@@ -82,6 +91,15 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(self->args, 'o') && old_fd != -1)
return (CMD_RETURN_NORMAL);
/* What do we want to do? Neither -I or -O is -O. */
if (args_has(self->args, 'I')) {
in = 1;
out = args_has(self->args, 'O');
} else {
in = 0;
out = 1;
}
/* Open the new pipe. */
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) {
cmdq_error(item, "socketpair error: %s", strerror(errno));
@@ -89,65 +107,119 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
}
/* Expand the command. */
ft = format_create(item, FORMAT_NONE, 0);
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, c, s, wl, wp);
cmd = format_expand_time(ft, args->argv[0], time(NULL));
cmd = format_expand_time(ft, args->argv[0]);
format_free(ft);
/* Fork the child. */
sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, &oldset);
switch (fork()) {
case -1:
sigprocmask(SIG_SETMASK, &oldset, NULL);
cmdq_error(item, "fork error: %s", strerror(errno));
free(cmd);
return (CMD_RETURN_ERROR);
case 0:
/* Child process. */
proc_clear_signals(server_proc, 1);
sigprocmask(SIG_SETMASK, &oldset, NULL);
close(pipe_fd[0]);
clear_signals(1);
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
_exit(1);
if (pipe_fd[1] != STDIN_FILENO)
close(pipe_fd[1]);
null_fd = open(_PATH_DEVNULL, O_WRONLY, 0);
if (dup2(null_fd, STDOUT_FILENO) == -1)
_exit(1);
if (out) {
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
_exit(1);
} else {
if (dup2(null_fd, STDIN_FILENO) == -1)
_exit(1);
}
if (in) {
if (dup2(pipe_fd[1], STDOUT_FILENO) == -1)
_exit(1);
if (pipe_fd[1] != STDOUT_FILENO)
close(pipe_fd[1]);
} else {
if (dup2(null_fd, STDOUT_FILENO) == -1)
_exit(1);
}
if (dup2(null_fd, STDERR_FILENO) == -1)
_exit(1);
if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO)
close(null_fd);
closefrom(STDERR_FILENO + 1);
execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
_exit(1);
default:
/* Parent process. */
sigprocmask(SIG_SETMASK, &oldset, NULL);
close(pipe_fd[1]);
wp->pipe_fd = pipe_fd[0];
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
wp->pipe_event = bufferevent_new(wp->pipe_fd,
NULL, NULL, cmd_pipe_pane_error_callback, wp);
bufferevent_enable(wp->pipe_event, EV_WRITE);
if (wp->fd != -1)
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
else
wp->pipe_off = 0;
setblocking(wp->pipe_fd, 0);
wp->pipe_event = bufferevent_new(wp->pipe_fd,
cmd_pipe_pane_read_callback,
cmd_pipe_pane_write_callback,
cmd_pipe_pane_error_callback,
wp);
if (wp->pipe_event == NULL)
fatalx("out of memory");
if (out)
bufferevent_enable(wp->pipe_event, EV_WRITE);
if (in)
bufferevent_enable(wp->pipe_event, EV_READ);
free(cmd);
return (CMD_RETURN_NORMAL);
}
}
static void
cmd_pipe_pane_read_callback(__unused struct bufferevent *bufev, void *data)
{
struct window_pane *wp = data;
struct evbuffer *evb = wp->pipe_event->input;
size_t available;
available = EVBUFFER_LENGTH(evb);
log_debug("%%%u pipe read %zu", wp->id, available);
bufferevent_write(wp->event, EVBUFFER_DATA(evb), available);
evbuffer_drain(evb, available);
if (window_pane_destroy_ready(wp))
server_destroy_pane(wp, 1);
}
static void
cmd_pipe_pane_write_callback(__unused struct bufferevent *bufev, void *data)
{
struct window_pane *wp = data;
log_debug("%%%u pipe empty", wp->id);
if (window_pane_destroy_ready(wp))
server_destroy_pane(wp, 1);
}
static void
cmd_pipe_pane_error_callback(__unused struct bufferevent *bufev,
__unused short what, void *data)
{
struct window_pane *wp = data;
log_debug("%%%u pipe error", wp->id);
bufferevent_free(wp->pipe_event);
close(wp->pipe_fd);
wp->pipe_fd = -1;
if (window_pane_destroy_ready(wp))
server_destroy_pane(wp, 1);
}

View File

@@ -32,11 +32,14 @@ static struct cmdq_list global_queue = TAILQ_HEAD_INITIALIZER(global_queue);
static const char *
cmdq_name(struct client *c)
{
static char s[32];
static char s[256];
if (c == NULL)
return ("<global>");
xsnprintf(s, sizeof s, "<%p>", c);
if (c->name != NULL)
xsnprintf(s, sizeof s, "<%s>", c->name);
else
xsnprintf(s, sizeof s, "<%p>", c);
return (s);
}
@@ -66,6 +69,7 @@ cmdq_append(struct client *c, struct cmdq_item *item)
item->queue = queue;
TAILQ_INSERT_TAIL(queue, item, entry);
log_debug("%s %s: %s", __func__, cmdq_name(c), item->name);
item = next;
} while (item != NULL);
@@ -81,57 +85,107 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
do {
next = item->next;
item->next = NULL;
item->next = after->next;
after->next = item;
if (c != NULL)
c->references++;
item->client = c;
item->queue = queue;
if (after->next != NULL)
TAILQ_INSERT_AFTER(queue, after->next, item, entry);
else
TAILQ_INSERT_AFTER(queue, after, item, entry);
after->next = item;
TAILQ_INSERT_AFTER(queue, after, item, entry);
log_debug("%s %s: %s after %s", __func__, cmdq_name(c),
item->name, after->name);
after = item;
item = next;
} while (item != NULL);
}
/* Insert a hook. */
void
cmdq_insert_hook(struct session *s, struct cmdq_item *item,
struct cmd_find_state *fs, const char *fmt, ...)
{
struct options *oo;
va_list ap;
char *name;
struct cmdq_item *new_item;
struct options_entry *o;
struct options_array_item *a;
struct cmd_list *cmdlist;
if (item->flags & CMDQ_NOHOOKS)
return;
if (s == NULL)
oo = global_s_options;
else
oo = s->options;
va_start(ap, fmt);
xvasprintf(&name, fmt, ap);
va_end(ap);
o = options_get(oo, name);
if (o == NULL) {
free(name);
return;
}
log_debug("running hook %s (parent %p)", name, item);
a = options_array_first(o);
while (a != NULL) {
cmdlist = options_array_item_value(a)->cmdlist;
if (cmdlist == NULL) {
a = options_array_next(a);
continue;
}
new_item = cmdq_get_command(cmdlist, fs, NULL, CMDQ_NOHOOKS);
cmdq_format(new_item, "hook", "%s", name);
if (item != NULL) {
cmdq_insert_after(item, new_item);
item = new_item;
} else
cmdq_append(NULL, new_item);
a = options_array_next(a);
}
free(name);
}
/* Remove an item. */
static void
cmdq_remove(struct cmdq_item *item)
{
if (item->formats != NULL)
format_free(item->formats);
if (item->shared != NULL && --item->shared->references == 0) {
if (item->shared->formats != NULL)
format_free(item->shared->formats);
free(item->shared);
}
if (item->client != NULL)
server_client_unref(item->client);
if (item->type == CMDQ_COMMAND)
if (item->cmdlist != NULL)
cmd_list_free(item->cmdlist);
TAILQ_REMOVE(item->queue, item, entry);
free((void *)item->name);
free(item->name);
free(item);
}
/* Set command group. */
static u_int
cmdq_next_group(void)
{
static u_int group;
return (++group);
}
/* Remove all subsequent items that match this item's group. */
static void
cmdq_remove_group(struct cmdq_item *item)
{
struct cmdq_item *this, *next;
if (item->group == 0)
return;
this = TAILQ_NEXT(item, entry);
while (this != NULL) {
next = TAILQ_NEXT(this, entry);
@@ -148,26 +202,35 @@ cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
{
struct cmdq_item *item, *first = NULL, *last = NULL;
struct cmd *cmd;
u_int group = cmdq_next_group();
char *tmp;
struct cmdq_shared *shared = NULL;
u_int group = 0;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
xasprintf(&tmp, "command[%s]", cmd->entry->name);
if (cmd->group != group) {
shared = xcalloc(1, sizeof *shared);
if (current != NULL)
cmd_find_copy_state(&shared->current, current);
else
cmd_find_clear_state(&shared->current, 0);
if (m != NULL)
memcpy(&shared->mouse, m, sizeof shared->mouse);
group = cmd->group;
}
item = xcalloc(1, sizeof *item);
item->name = tmp;
xasprintf(&item->name, "[%s/%p]", cmd->entry->name, item);
item->type = CMDQ_COMMAND;
item->group = group;
item->group = cmd->group;
item->flags = flags;
item->shared = shared;
item->cmdlist = cmdlist;
item->cmd = cmd;
if (current != NULL)
cmd_find_copy_state(&item->current, current);
if (m != NULL)
memcpy(&item->mouse, m, sizeof item->mouse);
log_debug("%s: %s group %u", __func__, item->name, item->group);
shared->references++;
cmdlist->references++;
if (first == NULL)
@@ -179,41 +242,72 @@ cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
return (first);
}
/* Fill in flag for a command. */
static enum cmd_retval
cmdq_find_flag(struct cmdq_item *item, struct cmd_find_state *fs,
const struct cmd_entry_flag *flag)
{
const char *value;
if (flag->flag == 0) {
cmd_find_clear_state(fs, 0);
return (CMD_RETURN_NORMAL);
}
value = args_get(item->cmd->args, flag->flag);
if (cmd_find_target(fs, item, value, flag->type, flag->flags) != 0) {
cmd_find_clear_state(fs, 0);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
/* Fire command on command queue. */
static enum cmd_retval
cmdq_fire_command(struct cmdq_item *item)
{
struct client *c = item->client;
const char *name = cmdq_name(c);
struct cmdq_shared *shared = item->shared;
struct cmd *cmd = item->cmd;
const struct cmd_entry *entry = cmd->entry;
enum cmd_retval retval;
const char *name;
struct cmd_find_state *fsp, fs;
int flags;
char *tmp;
flags = !!(cmd->flags & CMD_CONTROL);
if (log_get_level() > 1) {
tmp = cmd_print(cmd);
log_debug("%s %s: (%u) %s", __func__, name, item->group, tmp);
free(tmp);
}
flags = !!(shared->flags & CMDQ_SHARED_CONTROL);
cmdq_guard(item, "begin", flags);
if (cmd_prepare_state(cmd, item) != 0) {
retval = CMD_RETURN_ERROR;
goto out;
}
if (item->client == NULL)
item->client = cmd_find_client(item, NULL, CMD_FIND_QUIET);
retval = cmd->entry->exec(cmd, item);
item->client = cmd_find_client(item, NULL, 1);
retval = cmdq_find_flag(item, &item->source, &entry->source);
if (retval == CMD_RETURN_ERROR)
goto out;
retval = cmdq_find_flag(item, &item->target, &entry->target);
if (retval == CMD_RETURN_ERROR)
goto out;
if (cmd->entry->flags & CMD_AFTERHOOK) {
name = cmd->entry->name;
if (cmd_find_valid_state(&item->state.tflag))
fsp = &item->state.tflag;
else {
if (cmd_find_current(&fs, item, CMD_FIND_QUIET) != 0)
goto out;
retval = entry->exec(cmd, item);
if (retval == CMD_RETURN_ERROR)
goto out;
if (entry->flags & CMD_AFTERHOOK) {
if (cmd_find_valid_state(&item->target))
fsp = &item->target;
else if (cmd_find_valid_state(&item->shared->current))
fsp = &item->shared->current;
else if (cmd_find_from_client(&fs, item->client, 0) == 0)
fsp = &fs;
}
hooks_insert(fsp->s->hooks, item, fsp, "after-%s", name);
else
goto out;
cmdq_insert_hook(fsp->s, item, fsp, "after-%s", entry->name);
}
out:
@@ -230,12 +324,9 @@ struct cmdq_item *
cmdq_get_callback1(const char *name, cmdq_cb cb, void *data)
{
struct cmdq_item *item;
char *tmp;
xasprintf(&tmp, "callback[%s]", name);
item = xcalloc(1, sizeof *item);
item->name = tmp;
xasprintf(&item->name, "[%s/%p]", name, item);
item->type = CMDQ_CALLBACK;
item->group = 0;
@@ -247,6 +338,25 @@ cmdq_get_callback1(const char *name, cmdq_cb cb, void *data)
return (item);
}
/* Generic error callback. */
static enum cmd_retval
cmdq_error_callback(struct cmdq_item *item, void *data)
{
char *error = data;
cmdq_error(item, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
/* Get an error callback for the command queue. */
struct cmdq_item *
cmdq_get_error(const char *error)
{
return (cmdq_get_callback(cmdq_error_callback, xstrdup(error)));
}
/* Fire callback on callback queue. */
static enum cmd_retval
cmdq_fire_callback(struct cmdq_item *item)
@@ -258,19 +368,17 @@ cmdq_fire_callback(struct cmdq_item *item)
void
cmdq_format(struct cmdq_item *item, const char *key, const char *fmt, ...)
{
struct cmdq_shared *shared = item->shared;
va_list ap;
struct cmdq_item *loop;
char *value;
va_start(ap, fmt);
xvasprintf(&value, fmt, ap);
va_end(ap);
for (loop = item; loop != NULL; loop = item->next) {
if (loop->formats == NULL)
loop->formats = format_create(NULL, FORMAT_NONE, 0);
format_add(loop->formats, key, "%s", value);
}
if (shared->formats == NULL)
shared->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
format_add(shared->formats, key, "%s", value);
free(value);
}
@@ -319,8 +427,7 @@ cmdq_next(struct client *c)
item->time = time(NULL);
item->number = ++number;
switch (item->type)
{
switch (item->type) {
case CMDQ_COMMAND:
retval = cmdq_fire_command(item);
@@ -375,10 +482,11 @@ cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
void
cmdq_print(struct cmdq_item *item, const char *fmt, ...)
{
struct client *c = item->client;
struct window *w;
va_list ap;
char *tmp, *msg;
struct client *c = item->client;
struct window_pane *wp;
struct window_mode_entry *wme;
va_list ap;
char *tmp, *msg;
va_start(ap, fmt);
@@ -396,13 +504,11 @@ cmdq_print(struct cmdq_item *item, const char *fmt, ...)
evbuffer_add(c->stdout_data, "\n", 1);
server_client_push_stdout(c);
} else {
w = c->session->curw->window;
if (w->active->mode != &window_copy_mode) {
window_pane_reset_mode(w->active);
window_pane_set_mode(w->active, &window_copy_mode);
window_copy_init_for_output(w->active);
}
window_copy_vadd(w->active, fmt, ap);
wp = c->session->curw->window->active;
wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
window_copy_vadd(wp, fmt, ap);
}
va_end(ap);
@@ -423,6 +529,8 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
msglen = xvasprintf(&msg, fmt, ap);
va_end(ap);
log_debug("%s: %s", __func__, msg);
if (c == NULL)
cfg_add_cause("%s:%u: %s", cmd->file, cmd->line, msg);
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {

View File

@@ -18,6 +18,8 @@
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
@@ -31,10 +33,8 @@ const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client",
.alias = "refresh",
.args = { "C:St:", 0, 0 },
.usage = "[-S] [-C size] " CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.args = { "cC:DlLRSt:U", 0, 1 },
.usage = "[-cDlLRSU] [-C size] " CMD_TARGET_CLIENT_USAGE " [adjustment]",
.flags = CMD_AFTERHOOK,
.exec = cmd_refresh_client_exec
@@ -44,21 +44,81 @@ static enum cmd_retval
cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
const char *size;
u_int w, h;
struct client *c;
struct tty *tty;
struct window *w;
const char *size, *errstr;
u_int x, y, adjust;
if (args_has(args, 'C')) {
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
tty = &c->tty;
if (args_has(args, 'c') ||
args_has(args, 'L') ||
args_has(args, 'R') ||
args_has(args, 'U') ||
args_has(args, 'D'))
{
if (args->argc == 0)
adjust = 1;
else {
adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "adjustment %s", errstr);
return (CMD_RETURN_ERROR);
}
}
if (args_has(args, 'c'))
c->pan_window = NULL;
else {
w = c->session->curw->window;
if (c->pan_window != w) {
c->pan_window = w;
c->pan_ox = tty->oox;
c->pan_oy = tty->ooy;
}
if (args_has(args, 'L')) {
if (c->pan_ox > adjust)
c->pan_ox -= adjust;
else
c->pan_ox = 0;
} else if (args_has(args, 'R')) {
c->pan_ox += adjust;
if (c->pan_ox > w->sx - tty->osx)
c->pan_ox = w->sx - tty->osx;
} else if (args_has(args, 'U')) {
if (c->pan_oy > adjust)
c->pan_oy -= adjust;
else
c->pan_oy = 0;
} else if (args_has(args, 'D')) {
c->pan_oy += adjust;
if (c->pan_oy > w->sy - tty->osy)
c->pan_oy = w->sy - tty->osy;
}
}
tty_update_client_offset(c);
server_redraw_client(c);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'l')) {
if (c->session != NULL)
tty_putcode_ptr2(&c->tty, TTYC_MS, "", "?");
} else if (args_has(args, 'C')) {
if ((size = args_get(args, 'C')) == NULL) {
cmdq_error(item, "missing size");
return (CMD_RETURN_ERROR);
}
if (sscanf(size, "%u,%u", &w, &h) != 2) {
if (sscanf(size, "%u,%u", &x, &y) != 2 &&
sscanf(size, "%ux%u", &x, &y)) {
cmdq_error(item, "bad size argument");
return (CMD_RETURN_ERROR);
}
if (w < PANE_MINIMUM || w > 5000 ||
h < PANE_MINIMUM || h > 5000) {
if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
cmdq_error(item, "size too small or too big");
return (CMD_RETURN_ERROR);
}
@@ -66,15 +126,18 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}
if (tty_set_size(&c->tty, w, h))
recalculate_sizes();
} else if (args_has(args, 'S')) {
tty_set_size(&c->tty, x, y);
c->flags |= CLIENT_SIZECHANGED;
recalculate_sizes();
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'S')) {
c->flags |= CLIENT_STATUSFORCE;
server_status_client(c);
} else {
c->flags |= CLIENT_STATUSFORCE;
server_redraw_client(c);
}
return (CMD_RETURN_NORMAL);
}

View File

@@ -37,7 +37,7 @@ const struct cmd_entry cmd_rename_session_entry = {
.args = { "t:", 1, 1 },
.usage = CMD_TARGET_SESSION_USAGE " new-name",
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_rename_session_exec
@@ -46,26 +46,31 @@ const struct cmd_entry cmd_rename_session_entry = {
static enum cmd_retval
cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct session *s = item->state.tflag.s;
const char *newname;
struct args *args = self->args;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
char *newname;
newname = args->argv[0];
if (strcmp(newname, s->name) == 0)
newname = format_single(item, args->argv[0], c, s, NULL, NULL);
if (strcmp(newname, s->name) == 0) {
free(newname);
return (CMD_RETURN_NORMAL);
}
if (!session_check_name(newname)) {
cmdq_error(item, "bad session name: %s", newname);
free(newname);
return (CMD_RETURN_ERROR);
}
if (session_find(newname) != NULL) {
cmdq_error(item, "duplicate session: %s", newname);
free(newname);
return (CMD_RETURN_ERROR);
}
RB_REMOVE(sessions, &sessions, s);
free(s->name);
s->name = xstrdup(newname);
s->name = newname;
RB_INSERT(sessions, &sessions, s);
server_status_session(s);

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_rename_window_entry = {
.args = { "t:", 1, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " new-name",
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_rename_window_exec
@@ -46,12 +46,17 @@ static enum cmd_retval
cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
char *newname;
window_set_name(wl->window, args->argv[0]);
newname = format_single(item, args->argv[0], c, s, wl, NULL);
window_set_name(wl->window, newname);
options_set_number(wl->window->options, "automatic-rename", 0);
server_status_window(wl->window);
free(newname);
return (CMD_RETURN_NORMAL);
}

View File

@@ -39,7 +39,7 @@ const struct cmd_entry cmd_resize_pane_entry = {
.usage = "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
"[adjustment]",
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_resize_pane_exec
@@ -49,23 +49,24 @@ static enum cmd_retval
cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct window_pane *wp = item->state.tflag.wp;
struct winlink *wl = item->state.tflag.wl;
struct cmdq_shared *shared = item->shared;
struct window_pane *wp = item->target.wp;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct client *c = item->client;
struct session *s = item->state.tflag.s;
struct session *s = item->target.s;
const char *errstr;
char *cause;
u_int adjust;
int x, y;
if (args_has(args, 'M')) {
if (cmd_mouse_window(&item->mouse, &s) == NULL)
if (cmd_mouse_window(&shared->mouse, &s) == NULL)
return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update;
cmd_resize_pane_mouse_update(c, &item->mouse);
cmd_resize_pane_mouse_update(c, &shared->mouse);
return (CMD_RETURN_NORMAL);
}
@@ -90,9 +91,8 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
}
}
if (args_has(self->args, 'x')) {
x = args_strtonum(self->args, 'x', PANE_MINIMUM, INT_MAX,
&cause);
if (args_has(args, 'x')) {
x = args_strtonum(args, 'x', PANE_MINIMUM, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
@@ -100,9 +100,8 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
}
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
}
if (args_has(self->args, 'y')) {
y = args_strtonum(self->args, 'y', PANE_MINIMUM, INT_MAX,
&cause);
if (args_has(args, 'y')) {
y = args_strtonum(args, 'y', PANE_MINIMUM, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "height %s", cause);
free(cause);
@@ -111,13 +110,13 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
}
if (args_has(self->args, 'L'))
if (args_has(args, 'L'))
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust, 1);
else if (args_has(self->args, 'R'))
else if (args_has(args, 'R'))
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust, 1);
else if (args_has(self->args, 'U'))
else if (args_has(args, 'U'))
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, -adjust, 1);
else if (args_has(self->args, 'D'))
else if (args_has(args, 'D'))
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust, 1);
server_redraw_window(wl->window);
@@ -128,47 +127,64 @@ static void
cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m)
{
struct winlink *wl;
struct window_pane *wp;
int found;
u_int y, ly;
struct window *w;
u_int y, ly, x, lx;
static const int offsets[][2] = {
{ 0, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
};
struct layout_cell *cells[nitems(offsets)], *lc;
u_int ncells = 0, i, j, resizes = 0;
enum layout_type type;
wl = cmd_mouse_window(m, NULL);
if (wl == NULL) {
c->tty.mouse_drag_update = NULL;
return;
}
w = wl->window;
y = m->y;
y = m->y + m->oy; x = m->x + m->ox;
if (m->statusat == 0 && y > 0)
y--;
else if (m->statusat > 0 && y >= (u_int)m->statusat)
y = m->statusat - 1;
ly = m->ly;
ly = m->ly + m->oy; lx = m->lx + m->ox;
if (m->statusat == 0 && ly > 0)
ly--;
else if (m->statusat > 0 && ly >= (u_int)m->statusat)
ly = m->statusat - 1;
found = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
if (!window_pane_visible(wp))
for (i = 0; i < nitems(cells); i++) {
lc = layout_search_by_border(w->layout_root, lx + offsets[i][0],
ly + offsets[i][1]);
if (lc == NULL)
continue;
if (wp->xoff + wp->sx == m->lx &&
wp->yoff <= 1 + ly &&
wp->yoff + wp->sy >= ly) {
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, m->x - m->lx, 0);
found = 1;
for (j = 0; j < ncells; j++) {
if (cells[j] == lc) {
lc = NULL;
break;
}
}
if (wp->yoff + wp->sy == ly &&
wp->xoff <= 1 + m->lx &&
wp->xoff + wp->sx >= m->lx) {
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, y - ly, 0);
found = 1;
if (lc == NULL)
continue;
cells[ncells] = lc;
ncells++;
}
if (ncells == 0)
return;
for (i = 0; i < ncells; i++) {
type = cells[i]->parent->type;
if (y != ly && type == LAYOUT_TOPBOTTOM) {
layout_resize_layout(w, cells[i], type, y - ly, 0);
resizes++;
} else if (x != lx && type == LAYOUT_LEFTRIGHT) {
layout_resize_layout(w, cells[i], type, x - lx, 0);
resizes++;
}
}
if (found)
server_redraw_window(wl->window);
else
c->tty.mouse_drag_update = NULL;
if (resizes != 0)
server_redraw_window(w);
}

109
cmd-resize-window.c Normal file
View File

@@ -0,0 +1,109 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2018 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Increase or decrease window size.
*/
static enum cmd_retval cmd_resize_window_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_resize_window_entry = {
.name = "resize-window",
.alias = "resizew",
.args = { "aADLRt:Ux:y:", 0, 1 },
.usage = "[-aADLRU] [-x width] [-y height] " CMD_TARGET_WINDOW_USAGE " "
"[adjustment]",
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_resize_window_exec
};
static enum cmd_retval
cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct session *s = item->target.s;
const char *errstr;
char *cause;
u_int adjust, sx, sy;
if (args->argc == 0)
adjust = 1;
else {
adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "adjustment %s", errstr);
return (CMD_RETURN_ERROR);
}
}
sx = w->sx;
sy = w->sy;
if (args_has(args, 'x')) {
sx = args_strtonum(args, 'x', WINDOW_MINIMUM, WINDOW_MAXIMUM,
&cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
if (args_has(args, 'y')) {
sy = args_strtonum(args, 'y', WINDOW_MINIMUM, WINDOW_MAXIMUM,
&cause);
if (cause != NULL) {
cmdq_error(item, "height %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
if (args_has(args, 'L')) {
if (sx >= adjust)
sx -= adjust;
} else if (args_has(args, 'R'))
sx += adjust;
else if (args_has(args, 'U')) {
if (sy >= adjust)
sy -= adjust;
} else if (args_has(args, 'D'))
sy += adjust;
if (args_has(args, 'A'))
default_window_size(s, w, &sx, &sy, WINDOW_SIZE_LARGEST);
else if (args_has(args, 'a'))
default_window_size(s, w, &sx, &sy, WINDOW_SIZE_SMALLEST);
options_set_number(w->options, "window-size", WINDOW_SIZE_MANUAL);
resize_window(w, sx, sy);
return (CMD_RETURN_NORMAL);
}

View File

@@ -20,7 +20,7 @@
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "tmux.h"
@@ -34,10 +34,11 @@ const struct cmd_entry cmd_respawn_pane_entry = {
.name = "respawn-pane",
.alias = "respawnp",
.args = { "kt:", 0, -1 },
.usage = "[-k] " CMD_TARGET_PANE_USAGE " [command]",
.args = { "c:e:kt:", 0, -1 },
.usage = "[-k] [-c start-directory] [-e environment] "
CMD_TARGET_PANE_USAGE " [command]",
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_respawn_pane_exec
@@ -47,48 +48,49 @@ static enum cmd_retval
cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl;
struct window *w = wl->window;
struct window_pane *wp = item->state.tflag.wp;
struct session *s = item->state.tflag.s;
struct environ *env;
const char *path;
char *cause;
u_int idx;
struct environ_entry *envent;
struct spawn_context sc;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
char *cause = NULL;
const char *add;
struct args_value *value;
if (!args_has(self->args, 'k') && wp->fd != -1) {
if (window_pane_index(wp, &idx) != 0)
fatalx("index not found");
cmdq_error(item, "pane still active: %s:%d.%u",
s->name, wl->idx, idx);
return (CMD_RETURN_ERROR);
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
sc.wl = wl;
sc.wp0 = wp;
sc.lc = NULL;
sc.name = NULL;
sc.argc = args->argc;
sc.argv = args->argv;
sc.environ = environ_create();
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
add = args_next_value(&value);
}
window_pane_reset_mode(wp);
screen_reinit(&wp->base);
input_init(wp);
sc.idx = -1;
sc.cwd = args_get(args, 'c');
path = NULL;
if (item->client != NULL && item->client->session == NULL)
envent = environ_find(item->client->environ, "PATH");
else
envent = environ_find(s->environ, "PATH");
if (envent != NULL)
path = envent->value;
sc.flags = SPAWN_RESPAWN;
if (args_has(args, 'k'))
sc.flags |= SPAWN_KILL;
env = environ_for_session(s);
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env,
s->tio, &cause) != 0) {
if (spawn_pane(&sc, &cause) == NULL) {
cmdq_error(item, "respawn pane failed: %s", cause);
free(cause);
environ_free(env);
return (CMD_RETURN_ERROR);
}
environ_free(env);
wp->flags |= PANE_REDRAW;
server_status_window(w);
server_status_window(wp->window);
environ_free(sc.environ);
return (CMD_RETURN_NORMAL);
}

View File

@@ -19,7 +19,7 @@
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "tmux.h"
@@ -34,10 +34,11 @@ const struct cmd_entry cmd_respawn_window_entry = {
.name = "respawn-window",
.alias = "respawnw",
.args = { "kt:", 0, -1 },
.usage = "[-k] " CMD_TARGET_WINDOW_USAGE " [command]",
.args = { "c:e:kt:", 0, -1 },
.usage = "[-k] [-c start-directory] [-e environment] "
CMD_TARGET_WINDOW_USAGE " [command]",
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_respawn_window_exec
@@ -47,58 +48,44 @@ static enum cmd_retval
cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct window *w = wl->window;
struct window_pane *wp;
struct environ *env;
const char *path;
char *cause;
struct environ_entry *envent;
struct spawn_context sc;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
char *cause = NULL;
const char *add;
struct args_value *value;
if (!args_has(self->args, 'k')) {
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd == -1)
continue;
cmdq_error(item, "window still active: %s:%d", s->name,
wl->idx);
return (CMD_RETURN_ERROR);
}
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
sc.wl = wl;
sc.name = NULL;
sc.argc = args->argc;
sc.argv = args->argv;
sc.environ = environ_create();
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
add = args_next_value(&value);
}
wp = TAILQ_FIRST(&w->panes);
TAILQ_REMOVE(&w->panes, wp, entry);
layout_free(w);
window_destroy_panes(w);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
window_pane_resize(wp, w->sx, w->sy);
sc.idx = -1;
sc.cwd = args_get(args, 'c');
path = NULL;
if (item->client != NULL && item->client->session == NULL)
envent = environ_find(item->client->environ, "PATH");
else
envent = environ_find(s->environ, "PATH");
if (envent != NULL)
path = envent->value;
sc.flags = SPAWN_RESPAWN;
if (args_has(args, 'k'))
sc.flags |= SPAWN_KILL;
env = environ_for_session(s);
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env,
s->tio, &cause) != 0) {
if (spawn_window(&sc, &cause) == NULL) {
cmdq_error(item, "respawn window failed: %s", cause);
free(cause);
environ_free(env);
server_destroy_pane(wp, 0);
return (CMD_RETURN_ERROR);
}
environ_free(env);
layout_init(w, wp);
window_pane_reset_mode(wp);
screen_reinit(&wp->base);
input_init(wp);
window_set_active_pane(w, wp);
recalculate_sizes();
server_redraw_window(w);
server_redraw_window(wl->window);
environ_free(sc.environ);
return (CMD_RETURN_NORMAL);
}

View File

@@ -34,7 +34,7 @@ const struct cmd_entry cmd_rotate_window_entry = {
.args = { "Dt:U", 0, 0 },
.usage = "[-DU] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_rotate_window_exec
@@ -43,7 +43,8 @@ const struct cmd_entry cmd_rotate_window_entry = {
static enum cmd_retval
cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct winlink *wl = item->state.tflag.wl;
struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct window_pane *wp, *wp2;
struct layout_cell *lc;
@@ -76,7 +77,8 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL)
wp = TAILQ_LAST(&w->panes, window_panes);
window_set_active_pane(w, wp);
window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
} else {
wp = TAILQ_FIRST(&w->panes);
@@ -103,7 +105,8 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_NEXT(w->active, entry)) == NULL)
wp = TAILQ_FIRST(&w->panes);
window_set_active_pane(w, wp);
window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
}

View File

@@ -42,7 +42,7 @@ const struct cmd_entry cmd_run_shell_entry = {
.args = { "bt:", 1, 1 },
.usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
.tflag = CMD_PANE_CANFAIL,
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = 0,
.exec = cmd_run_shell_exec
@@ -57,9 +57,10 @@ struct cmd_run_shell_data {
static void
cmd_run_shell_print(struct job *job, const char *msg)
{
struct cmd_run_shell_data *cdata = job->data;
struct cmd_run_shell_data *cdata = job_get_data(job);
struct window_pane *wp = NULL;
struct cmd_find_state fs;
struct window_mode_entry *wme;
if (cdata->wp_id != -1)
wp = window_pane_find_by_id(cdata->wp_id);
@@ -68,17 +69,17 @@ cmd_run_shell_print(struct job *job, const char *msg)
cmdq_print(cdata->item, "%s", msg);
return;
}
if (cmd_find_current (&fs, NULL, CMD_FIND_QUIET) != 0)
if (cmd_find_from_nothing(&fs, 0) != 0)
return;
wp = fs.wp;
if (wp == NULL)
return;
}
if (window_pane_set_mode(wp, &window_copy_mode) == 0)
window_copy_init_for_output(wp);
if (wp->mode == &window_copy_mode)
window_copy_add(wp, "%s", msg);
wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
window_copy_add(wp, "%s", msg);
}
static enum cmd_retval
@@ -86,18 +87,10 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_run_shell_data *cdata;
struct client *c = item->state.c;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct window_pane *wp = item->state.tflag.wp;
const char *cwd;
if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
else if (s != NULL)
cwd = s->cwd;
else
cwd = NULL;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
cdata = xcalloc(1, sizeof *cdata);
cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp);
@@ -110,8 +103,12 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 'b'))
cdata->item = item;
job_run(cdata->cmd, s, cwd, cmd_run_shell_callback, cmd_run_shell_free,
cdata);
if (job_run(cdata->cmd, s, server_client_get_cwd(item->client, s), NULL,
cmd_run_shell_callback, cmd_run_shell_free, cdata, 0) == NULL) {
cmdq_error(item, "failed to run command: %s", cdata->cmd);
free(cdata);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
@@ -121,22 +118,23 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
static void
cmd_run_shell_callback(struct job *job)
{
struct cmd_run_shell_data *cdata = job->data;
char *cmd = cdata->cmd, *msg, *line;
struct cmd_run_shell_data *cdata = job_get_data(job);
struct bufferevent *event = job_get_event(job);
char *cmd = cdata->cmd, *msg = NULL, *line;
size_t size;
int retcode;
int retcode, status;
do {
if ((line = evbuffer_readline(job->event->input)) != NULL) {
if ((line = evbuffer_readline(event->input)) != NULL) {
cmd_run_shell_print(job, line);
free(line);
}
} while (line != NULL);
size = EVBUFFER_LENGTH(job->event->input);
size = EVBUFFER_LENGTH(event->input);
if (size != 0) {
line = xmalloc(size + 1);
memcpy(line, EVBUFFER_DATA(job->event->input), size);
memcpy(line, EVBUFFER_DATA(event->input), size);
line[size] = '\0';
cmd_run_shell_print(job, line);
@@ -144,12 +142,12 @@ cmd_run_shell_callback(struct job *job)
free(line);
}
msg = NULL;
if (WIFEXITED(job->status)) {
if ((retcode = WEXITSTATUS(job->status)) != 0)
status = job_get_status(job);
if (WIFEXITED(status)) {
if ((retcode = WEXITSTATUS(status)) != 0)
xasprintf(&msg, "'%s' returned %d", cmd, retcode);
} else if (WIFSIGNALED(job->status)) {
retcode = WTERMSIG(job->status);
} else if (WIFSIGNALED(status)) {
retcode = WTERMSIG(status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
}
if (msg != NULL)

View File

@@ -59,11 +59,13 @@ static enum cmd_retval
cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->client;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
struct paste_buffer *pb;
const char *path, *bufname, *bufdata, *start, *end;
const char *flags;
char *msg, *file;
const char *bufname, *bufdata, *start, *end, *flags;
char *msg, *path, *file;
size_t size, used, msglen, bufsize;
FILE *f;
@@ -83,10 +85,12 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
bufdata = paste_buffer_data(pb, &bufsize);
if (self->entry == &cmd_show_buffer_entry)
path = "-";
path = xstrdup("-");
else
path = args->argv[0];
path = format_single(item, args->argv[0], c, s, wl, wp);
if (strcmp(path, "-") == 0) {
free(path);
c = item->client;
if (c == NULL) {
cmdq_error(item, "can't write to stdout");
return (CMD_RETURN_ERROR);
@@ -100,7 +104,9 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(self->args, 'a'))
flags = "ab";
file = server_client_get_path(c, path);
file = server_client_get_path(item->client, path);
free(path);
f = fopen(file, flags);
if (f == NULL) {
cmdq_error(item, "%s: %s", file, strerror(errno));
@@ -111,6 +117,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
if (fwrite(bufdata, 1, bufsize, f) != bufsize) {
cmdq_error(item, "%s: write error", file);
fclose(f);
free(file);
return (CMD_RETURN_ERROR);
}

View File

@@ -33,10 +33,10 @@ const struct cmd_entry cmd_select_layout_entry = {
.name = "select-layout",
.alias = "selectl",
.args = { "nopt:", 0, 1 },
.usage = "[-nop] " CMD_TARGET_WINDOW_USAGE " [layout-name]",
.args = { "Enopt:", 0, 1 },
.usage = "[-Enop] " CMD_TARGET_PANE_USAGE " [layout-name]",
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec
@@ -49,7 +49,7 @@ const struct cmd_entry cmd_next_layout_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec
@@ -62,7 +62,7 @@ const struct cmd_entry cmd_previous_layout_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec
@@ -71,14 +71,14 @@ const struct cmd_entry cmd_previous_layout_entry = {
static enum cmd_retval
cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl;
struct window *w;
const char *layoutname;
char *oldlayout;
int next, previous, layout;
struct args *args = self->args;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct window_pane *wp = item->target.wp;
const char *layoutname;
char *oldlayout;
int next, previous, layout;
w = wl->window;
server_unzoom_window(w);
next = self->entry == &cmd_next_layout_entry;
@@ -99,6 +99,11 @@ cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
goto changed;
}
if (args_has(args, 'E')) {
layout_spread_out(wp);
goto changed;
}
if (!args_has(args, 'o')) {
if (args->argc == 0)
layout = w->lastlayout;
@@ -130,7 +135,9 @@ cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
changed:
free(oldlayout);
recalculate_sizes();
server_redraw_window(w);
notify_window("window-layout-changed", w);
return (CMD_RETURN_NORMAL);
error:

View File

@@ -18,6 +18,9 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
@@ -30,10 +33,10 @@ const struct cmd_entry cmd_select_pane_entry = {
.name = "select-pane",
.alias = "selectp",
.args = { "DdegLlMmP:Rt:U", 0, 0 },
.usage = "[-DdegLlMmRU] [-P style] " CMD_TARGET_PANE_USAGE,
.args = { "DdegLlMmP:RT:t:U", 0, 0 },
.usage = "[-DdegLlMmRU] [-P style] [-T title] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_select_pane_exec
@@ -46,41 +49,74 @@ const struct cmd_entry cmd_last_pane_entry = {
.args = { "det:", 0, 0 },
.usage = "[-de] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_select_pane_exec
};
static void
cmd_select_pane_redraw(struct window *w)
{
struct client *c;
/*
* Redraw entire window if it is bigger than the client (the
* offset may change), otherwise just draw borders.
*/
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == NULL || (c->flags & CLIENT_CONTROL))
continue;
if (c->session->curw->window == w && tty_window_bigger(&c->tty))
server_redraw_client(c);
else {
if (c->session->curw->window == w)
c->flags |= CLIENT_REDRAWBORDERS;
if (session_has(c->session, w))
c->flags |= CLIENT_REDRAWSTATUS;
}
}
}
static enum cmd_retval
cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl;
struct cmd_find_state *current = &item->shared->current;
struct client *c = cmd_find_client(item, NULL, 1);
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct session *s = item->state.tflag.s;
struct window_pane *wp = item->state.tflag.wp, *lastwp, *markedwp;
struct session *s = item->target.s;
struct window_pane *wp = item->target.wp, *lastwp, *markedwp;
struct style *sy = &wp->style;
char *pane_title;
const char *style;
if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
if (wl->window->last == NULL) {
lastwp = w->last;
if (lastwp == NULL && window_count_panes(w) == 2) {
lastwp = TAILQ_PREV(w->active, window_panes, entry);
if (lastwp == NULL)
lastwp = TAILQ_NEXT(w->active, entry);
}
if (lastwp == NULL) {
cmdq_error(item, "no last pane");
return (CMD_RETURN_ERROR);
}
if (args_has(self->args, 'e'))
w->last->flags &= ~PANE_INPUTOFF;
lastwp->flags &= ~PANE_INPUTOFF;
else if (args_has(self->args, 'd'))
w->last->flags |= PANE_INPUTOFF;
lastwp->flags |= PANE_INPUTOFF;
else {
server_unzoom_window(w);
window_redraw_active_switch(w, w->last);
if (window_set_active_pane(w, w->last)) {
server_status_window(w);
server_redraw_window_borders(w);
window_redraw_active_switch(w, lastwp);
if (window_set_active_pane(w, lastwp, 1)) {
cmd_find_from_winlink(current, wl, 0);
cmd_select_pane_redraw(w);
}
}
return (CMD_RETURN_NORMAL);
}
@@ -107,17 +143,16 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
}
if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
if (args_has(args, 'P')) {
style = args_get(args, 'P');
if (style_parse(&grid_default_cell, &wp->colgc,
style) == -1) {
if ((style = args_get(args, 'P')) != NULL) {
style_set(sy, &grid_default_cell);
if (style_parse(sy, &grid_default_cell, style) == -1) {
cmdq_error(item, "bad style: %s", style);
return (CMD_RETURN_ERROR);
}
wp->flags |= PANE_REDRAW;
}
if (args_has(self->args, 'g'))
cmdq_print(item, "%s", style_tostring(&wp->colgc));
cmdq_print(item, "%s", style_tostring(sy));
return (CMD_RETURN_NORMAL);
}
@@ -146,17 +181,23 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
if (args_has(self->args, 'T')) {
pane_title = format_single(item, args_get(self->args, 'T'),
c, s, wl, wp);
screen_set_title(&wp->base, pane_title);
server_status_window(wp->window);
free(pane_title);
return (CMD_RETURN_NORMAL);
}
if (wp == w->active)
return (CMD_RETURN_NORMAL);
server_unzoom_window(wp->window);
if (!window_pane_visible(wp)) {
cmdq_error(item, "pane not visible");
return (CMD_RETURN_ERROR);
}
window_redraw_active_switch(w, wp);
if (window_set_active_pane(w, wp)) {
server_status_window(w);
server_redraw_window_borders(w);
if (window_set_active_pane(w, wp, 1)) {
cmd_find_from_winlink_pane(current, wl, wp, 0);
cmdq_insert_hook(s, item, current, "after-select-pane");
cmd_select_pane_redraw(w);
}
return (CMD_RETURN_NORMAL);

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_select_window_entry = {
.args = { "lnpTt:", 0, 0 },
.usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_select_window_exec
@@ -49,7 +49,7 @@ const struct cmd_entry cmd_next_window_entry = {
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0,
.exec = cmd_select_window_exec
@@ -62,7 +62,7 @@ const struct cmd_entry cmd_previous_window_entry = {
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0,
.exec = cmd_select_window_exec
@@ -75,7 +75,7 @@ const struct cmd_entry cmd_last_window_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0,
.exec = cmd_select_window_exec
@@ -84,9 +84,10 @@ const struct cmd_entry cmd_last_window_entry = {
static enum cmd_retval
cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct winlink *wl = item->state.tflag.wl;
struct session *s = item->state.tflag.s;
int next, previous, last, activity;
struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->target.wl;
struct session *s = item->target.s;
int next, previous, last, activity;
next = self->entry == &cmd_next_window_entry;
if (args_has(self->args, 'n'))
@@ -116,8 +117,9 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
}
cmd_find_from_session(current, s, 0);
server_redraw_session(s);
cmdq_insert_hook(s, item, current, "after-select-window");
} else {
/*
* If -T and select-window is invoked on same window as
@@ -128,9 +130,14 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no last window");
return (-1);
}
if (current->s == s)
cmd_find_from_session(current, s, 0);
server_redraw_session(s);
} else if (session_select(s, wl->idx) == 0)
} else if (session_select(s, wl->idx) == 0) {
cmd_find_from_session(current, s, 0);
server_redraw_session(s);
}
cmdq_insert_hook(s, item, current, "after-select-window");
}
recalculate_sizes();

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_send_keys_entry = {
.args = { "lXRMN:t:", 0, -1 },
.usage = "[-lXRM] [-N repeat-count] " CMD_TARGET_PANE_USAGE " key ...",
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_send_keys_exec
@@ -49,26 +49,55 @@ const struct cmd_entry cmd_send_prefix_entry = {
.args = { "2t:", 0, 0 },
.usage = "[-2] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_send_keys_exec
};
static struct cmdq_item *
cmd_send_keys_inject(struct client *c, struct cmd_find_state *fs,
struct cmdq_item *item, key_code key)
{
struct window_mode_entry *wme;
struct key_table *table;
struct key_binding *bd;
wme = TAILQ_FIRST(&fs->wp->modes);
if (wme == NULL || wme->mode->key_table == NULL) {
if (options_get_number(fs->wp->window->options, "xterm-keys"))
key |= KEYC_XTERM;
window_pane_key(fs->wp, item->client, fs->s, fs->wl, key, NULL);
return (item);
}
table = key_bindings_get_table(wme->mode->key_table(wme), 1);
bd = key_bindings_get(table, key & ~KEYC_XTERM);
if (bd != NULL) {
table->references++;
item = key_bindings_dispatch(bd, item, c, NULL, &item->target);
key_bindings_unref_table(table);
}
return (item);
}
static enum cmd_retval
cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct window_pane *wp = item->state.tflag.wp;
struct session *s = item->state.tflag.s;
struct mouse_event *m = &item->mouse;
struct utf8_data *ud, *uc;
wchar_t wc;
int i, literal;
key_code key;
u_int np = 1;
char *cause = NULL;
struct args *args = self->args;
struct client *c = cmd_find_client(item, NULL, 1);
struct window_pane *wp = item->target.wp;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct mouse_event *m = &item->shared->mouse;
struct cmd_find_state *fs = &item->target;
struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
struct utf8_data *ud, *uc;
wchar_t wc;
int i, literal;
key_code key;
u_int np = 1;
char *cause = NULL;
if (args_has(args, 'N')) {
np = args_strtonum(args, 'N', 1, UINT_MAX, &cause);
@@ -77,19 +106,23 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
free(cause);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'X') || args->argc == 0)
wp->modeprefix = np;
if (wme != NULL && (args_has(args, 'X') || args->argc == 0)) {
if (wme == NULL || wme->mode->command == NULL) {
cmdq_error(item, "not in a mode");
return (CMD_RETURN_ERROR);
}
wme->prefix = np;
}
}
if (args_has(args, 'X')) {
if (wp->mode == NULL || wp->mode->command == NULL) {
if (wme == NULL || wme->mode->command == NULL) {
cmdq_error(item, "not in a mode");
return (CMD_RETURN_ERROR);
}
if (!m->valid)
wp->mode->command(wp, c, s, args, NULL);
else
wp->mode->command(wp, c, s, args, m);
m = NULL;
wme->mode->command(wme, c, s, wl, args, m);
return (CMD_RETURN_NORMAL);
}
@@ -99,7 +132,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no mouse target");
return (CMD_RETURN_ERROR);
}
window_pane_key(wp, NULL, s, m->key, m);
window_pane_key(wp, item->client, s, wl, m->key, m);
return (CMD_RETURN_NORMAL);
}
@@ -108,7 +141,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
key = options_get_number(s->options, "prefix2");
else
key = options_get_number(s->options, "prefix");
window_pane_key(wp, NULL, s, key, NULL);
cmd_send_keys_inject(c, fs, item, key);
return (CMD_RETURN_NORMAL);
}
@@ -122,9 +155,10 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
literal = args_has(args, 'l');
if (!literal) {
key = key_string_lookup_string(args->argv[i]);
if (key != KEYC_NONE && key != KEYC_UNKNOWN)
window_pane_key(wp, NULL, s, key, NULL);
else
if (key != KEYC_NONE && key != KEYC_UNKNOWN) {
item = cmd_send_keys_inject(c, fs, item,
key);
} else
literal = 1;
}
if (literal) {
@@ -132,7 +166,8 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
for (uc = ud; uc->size != 0; uc++) {
if (utf8_combine(uc, &wc) != UTF8_DONE)
continue;
window_pane_key(wp, NULL, s, wc, NULL);
item = cmd_send_keys_inject(c, fs, item,
wc);
}
free(ud);
}

View File

@@ -37,7 +37,7 @@ const struct cmd_entry cmd_set_environment_entry = {
.args = { "grt:u", 1, 2 },
.usage = "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
.tflag = CMD_SESSION_CANFAIL,
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_set_environment_exec
@@ -68,7 +68,7 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(self->args, 'g'))
env = global_environ;
else {
if (item->state.tflag.s == NULL) {
if (item->target.s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(item, "no such session: %s", target);
@@ -76,7 +76,7 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
}
env = item->state.tflag.s->environ;
env = item->target.s->environ;
}
if (args_has(self->args, 'u')) {

View File

@@ -1,130 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Set or show global or session hooks.
*/
static enum cmd_retval cmd_set_hook_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_set_hook_entry = {
.name = "set-hook",
.alias = NULL,
.args = { "gt:u", 1, 2 },
.usage = "[-gu] " CMD_TARGET_SESSION_USAGE " hook-name [command]",
.tflag = CMD_SESSION_CANFAIL,
.flags = CMD_AFTERHOOK,
.exec = cmd_set_hook_exec
};
const struct cmd_entry cmd_show_hooks_entry = {
.name = "show-hooks",
.alias = NULL,
.args = { "gt:", 0, 1 },
.usage = "[-g] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.flags = CMD_AFTERHOOK,
.exec = cmd_set_hook_exec
};
static enum cmd_retval
cmd_set_hook_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_list *cmdlist;
struct hooks *hooks;
struct hook *hook;
char *cause, *tmp;
const char *name, *cmd, *target;
if (args_has(args, 'g'))
hooks = global_hooks;
else {
if (item->state.tflag.s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(item, "no such session: %s", target);
else
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
}
hooks = item->state.tflag.s->hooks;
}
if (self->entry == &cmd_show_hooks_entry) {
hook = hooks_first(hooks);
while (hook != NULL) {
tmp = cmd_list_print(hook->cmdlist);
cmdq_print(item, "%s -> %s", hook->name, tmp);
free(tmp);
hook = hooks_next(hook);
}
return (CMD_RETURN_NORMAL);
}
name = args->argv[0];
if (*name == '\0') {
cmdq_error(item, "invalid hook name");
return (CMD_RETURN_ERROR);
}
if (args->argc < 2)
cmd = NULL;
else
cmd = args->argv[1];
if (args_has(args, 'u')) {
if (cmd != NULL) {
cmdq_error(item, "command passed to unset hook: %s",
name);
return (CMD_RETURN_ERROR);
}
hooks_remove(hooks, name);
return (CMD_RETURN_NORMAL);
}
if (cmd == NULL) {
cmdq_error(item, "no command to set hook: %s", name);
return (CMD_RETURN_ERROR);
}
cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);
if (cmdlist == NULL) {
if (cause != NULL) {
cmdq_error(item, "%s", cause);
free(cause);
}
return (CMD_RETURN_ERROR);
}
hooks_add(hooks, name, cmdlist);
cmd_list_free(cmdlist);
return (CMD_RETURN_NORMAL);
}

View File

@@ -18,6 +18,7 @@
#include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h>
#include <string.h>
@@ -42,10 +43,10 @@ const struct cmd_entry cmd_set_option_entry = {
.name = "set-option",
.alias = "set",
.args = { "agoqst:uw", 1, 2 },
.usage = "[-agosquw] [-t target-window] option [value]",
.args = { "aFgoqst:uw", 1, 2 },
.usage = "[-aFgosquw] [-t target-window] option [value]",
.tflag = CMD_WINDOW_CANFAIL,
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec
@@ -55,10 +56,23 @@ const struct cmd_entry cmd_set_window_option_entry = {
.name = "set-window-option",
.alias = "setw",
.args = { "agoqt:u", 1, 2 },
.usage = "[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
.args = { "aFgoqt:u", 1, 2 },
.usage = "[-aFgoqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
.tflag = CMD_WINDOW_CANFAIL,
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec
};
const struct cmd_entry cmd_set_hook_entry = {
.name = "set-hook",
.alias = NULL,
.args = { "agRt:u", 1, 2 },
.usage = "[-agRu] " CMD_TARGET_SESSION_USAGE " hook [command]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec
@@ -69,33 +83,45 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
int append = args_has(args, 'a');
struct cmd_find_state *fs = &item->state.tflag;
struct cmd_find_state *fs = &item->target;
struct client *c, *loop;
struct session *s = fs->s;
struct winlink *wl = fs->wl;
struct window *w;
struct client *c;
enum options_table_scope scope;
struct options *oo;
struct options_entry *parent, *o;
const char *name, *value, *target;
char *name, *argument, *value = NULL, *cause;
const char *target;
int window, idx, already, error, ambiguous;
char *cause;
struct style *sy;
/* Expand argument. */
c = cmd_find_client(item, NULL, 1);
argument = format_single(item, args->argv[0], c, s, wl, NULL);
if (self->entry == &cmd_set_hook_entry && args_has(args, 'R')) {
notify_hook(item, argument);
return (CMD_RETURN_NORMAL);
}
/* Parse option name and index. */
name = options_match(args->argv[0], &idx, &ambiguous);
name = options_match(argument, &idx, &ambiguous);
if (name == NULL) {
if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL);
goto out;
if (ambiguous)
cmdq_error(item, "ambiguous option: %s", args->argv[0]);
cmdq_error(item, "ambiguous option: %s", argument);
else
cmdq_error(item, "invalid option: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
cmdq_error(item, "invalid option: %s", argument);
goto fail;
}
if (args->argc < 2)
value = NULL;
else if (args_has(args, 'F'))
value = format_single(item, args->argv[1], c, s, wl, NULL);
else
value = args->argv[1];
value = xstrdup(args->argv[1]);
/*
* Figure out the scope: for user options it comes from the arguments,
@@ -113,15 +139,15 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
scope = OPTIONS_TABLE_WINDOW;
else {
scope = OPTIONS_TABLE_NONE;
xasprintf(&cause, "unknown option: %s", args->argv[0]);
xasprintf(&cause, "unknown option: %s", argument);
}
}
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL);
goto out;
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
goto fail;
}
/* Which table should this option go into? */
@@ -136,7 +162,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no such session: %s", target);
else
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
goto fail;
} else
oo = s->options;
} else if (scope == OPTIONS_TABLE_WINDOW) {
@@ -148,7 +174,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no such window: %s", target);
else
cmdq_error(item, "no current window");
return (CMD_RETURN_ERROR);
goto fail;
} else
oo = wl->window->options;
}
@@ -156,11 +182,9 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
parent = options_get(oo, name);
/* Check that array options and indexes match up. */
if (idx != -1) {
if (*name == '@' || options_array_size(parent, NULL) == -1) {
cmdq_error(item, "not an array: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
if (idx != -1 && (*name == '@' || !options_isarray(parent))) {
cmdq_error(item, "not an array: %s", argument);
goto fail;
}
/* With -o, check this option is not already set. */
@@ -175,49 +199,60 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
}
if (already) {
if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL);
cmdq_error(item, "already set: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
goto out;
cmdq_error(item, "already set: %s", argument);
goto fail;
}
}
/* Change the option. */
if (args_has(args, 'u')) {
if (o == NULL)
return (CMD_RETURN_NORMAL);
goto out;
if (idx == -1) {
if (oo == global_options ||
if (*name == '@')
options_remove(o);
else if (oo == global_options ||
oo == global_s_options ||
oo == global_w_options)
options_default(oo, options_table_entry(o));
else
options_remove(o);
} else
options_array_set(o, idx, NULL, 0);
} else if (options_array_set(o, idx, NULL, 0, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
goto fail;
}
} else if (*name == '@') {
if (value == NULL) {
cmdq_error(item, "empty value");
return (CMD_RETURN_ERROR);
goto fail;
}
options_set_string(oo, name, append, "%s", value);
} else if (idx == -1 && options_array_size(parent, NULL) == -1) {
} else if (idx == -1 && !options_isarray(parent)) {
error = cmd_set_option_set(self, item, oo, parent, value);
if (error != 0)
return (CMD_RETURN_ERROR);
goto fail;
} else {
if (value == NULL) {
cmdq_error(item, "empty value");
return (CMD_RETURN_ERROR);
goto fail;
}
if (o == NULL)
o = options_empty(oo, options_table_entry(parent));
if (idx == -1) {
if (!append)
options_array_clear(o);
options_array_assign(o, value);
} else if (options_array_set(o, idx, value, append) != 0) {
cmdq_error(item, "invalid index: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
if (options_array_assign(o, value, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
goto fail;
}
} else if (options_array_set(o, idx, value, append,
&cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
goto fail;
}
}
@@ -231,8 +266,24 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
}
}
if (strcmp(name, "key-table") == 0) {
TAILQ_FOREACH(c, &clients, entry)
server_client_set_key_table(c, NULL);
TAILQ_FOREACH(loop, &clients, entry)
server_client_set_key_table(loop, NULL);
}
if (strcmp(name, "user-keys") == 0) {
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->tty.flags & TTY_OPENED)
tty_keys_build(&loop->tty);
}
}
if (strcmp(name, "status-fg") == 0 || strcmp(name, "status-bg") == 0) {
sy = options_get_style(oo, "status-style");
sy->gc.fg = options_get_number(oo, "status-fg");
sy->gc.bg = options_get_number(oo, "status-bg");
}
if (strcmp(name, "status-style") == 0) {
sy = options_get_style(oo, "status-style");
options_set_number(oo, "status-fg", sy->gc.fg);
options_set_number(oo, "status-bg", sy->gc.bg);
}
if (strcmp(name, "status") == 0 ||
strcmp(name, "status-interval") == 0)
@@ -246,22 +297,32 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
}
if (strcmp(name, "pane-border-status") == 0) {
RB_FOREACH(w, windows, &windows)
layout_fix_panes(w, w->sx, w->sy);
layout_fix_panes(w);
}
RB_FOREACH (s, sessions, &sessions)
status_update_saved(s);
RB_FOREACH(s, sessions, &sessions)
status_update_cache(s);
/*
* Update sizes and redraw. May not always be necessary but do it
* anyway.
*/
recalculate_sizes();
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != NULL)
server_redraw_client(c);
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->session != NULL)
server_redraw_client(loop);
}
out:
free(argument);
free(value);
free(name);
return (CMD_RETURN_NORMAL);
fail:
free(argument);
free(value);
free(name);
return (CMD_RETURN_ERROR);
}
static int
@@ -273,7 +334,8 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
int append = args_has(args, 'a');
struct options_entry *o;
long long number;
const char *errstr;
const char *errstr, *new;
char *old;
key_code key;
oe = options_table_entry(parent);
@@ -286,7 +348,16 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
switch (oe->type) {
case OPTIONS_TABLE_STRING:
old = xstrdup(options_get_string(oo, oe->name));
options_set_string(oo, oe->name, append, "%s", value);
new = options_get_string(oo, oe->name);
if (oe->pattern != NULL && fnmatch(oe->pattern, new, 0) != 0) {
options_set_string(oo, oe->name, 0, "%s", old);
free(old);
cmdq_error(item, "value is invalid: %s", value);
return (-1);
}
free(old);
return (0);
case OPTIONS_TABLE_NUMBER:
number = strtonum(value, oe->minimum, oe->maximum, &errstr);
@@ -309,16 +380,7 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
cmdq_error(item, "bad colour: %s", value);
return (-1);
}
o = options_set_number(oo, oe->name, number);
options_style_update_new(oo, o);
return (0);
case OPTIONS_TABLE_ATTRIBUTES:
if ((number = attributes_fromstring(value)) == -1) {
cmdq_error(item, "bad attributes: %s", value);
return (-1);
}
o = options_set_number(oo, oe->name, number);
options_style_update_new(oo, o);
options_set_number(oo, oe->name, number);
return (0);
case OPTIONS_TABLE_FLAG:
return (cmd_set_option_flag(item, oe, oo, value));
@@ -330,9 +392,8 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
cmdq_error(item, "bad style: %s", value);
return (-1);
}
options_style_update_old(oo, o);
return (0);
case OPTIONS_TABLE_ARRAY:
case OPTIONS_TABLE_COMMAND:
break;
}
return (-1);

View File

@@ -41,7 +41,7 @@ const struct cmd_entry cmd_show_environment_entry = {
.args = { "gst:", 0, 1 },
.usage = "[-gs] " CMD_TARGET_SESSION_USAGE " [name]",
.tflag = CMD_SESSION_CANFAIL,
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_show_environment_exec
@@ -97,7 +97,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
const char *target;
if ((target = args_get(args, 't')) != NULL) {
if (item->state.tflag.s == NULL) {
if (item->target.s == NULL) {
cmdq_error(item, "no such session: %s", target);
return (CMD_RETURN_ERROR);
}
@@ -106,7 +106,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(self->args, 'g'))
env = global_environ;
else {
if (item->state.tflag.s == NULL) {
if (item->target.s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(item, "no such session: %s", target);
@@ -114,7 +114,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
}
env = item->state.tflag.s->environ;
env = item->target.s->environ;
}
if (args->argc != 0) {

View File

@@ -38,14 +38,11 @@ const struct cmd_entry cmd_show_messages_entry = {
.args = { "JTt:", 0, 0 },
.usage = "[-JT] " CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = CMD_AFTERHOOK,
.exec = cmd_show_messages_exec
};
static int cmd_show_messages_terminals(struct cmdq_item *, int);
static int cmd_show_messages_jobs(struct cmdq_item *, int);
static int
cmd_show_messages_terminals(struct cmdq_item *item, int blank)
@@ -68,41 +65,25 @@ cmd_show_messages_terminals(struct cmdq_item *item, int blank)
return (n != 0);
}
static int
cmd_show_messages_jobs(struct cmdq_item *item, int blank)
{
struct job *job;
u_int n;
n = 0;
LIST_FOREACH(job, &all_jobs, lentry) {
if (blank) {
cmdq_print(item, "%s", "");
blank = 0;
}
cmdq_print(item, "Job %u: %s [fd=%d, pid=%ld, status=%d]",
n, job->cmd, job->fd, (long)job->pid, job->status);
n++;
}
return (n != 0);
}
static enum cmd_retval
cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct client *c;
struct message_entry *msg;
char *tim;
int done, blank;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
done = blank = 0;
if (args_has(args, 'T')) {
blank = cmd_show_messages_terminals(item, blank);
done = 1;
}
if (args_has(args, 'J')) {
cmd_show_messages_jobs(item, blank);
job_print_summary(item, blank);
done = 1;
}
if (done)

View File

@@ -29,8 +29,8 @@
static enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmdq_item *);
static enum cmd_retval cmd_show_options_one(struct cmd *, struct cmdq_item *,
struct options *);
static void cmd_show_options_print(struct cmd *, struct cmdq_item *,
struct options_entry *, int);
static enum cmd_retval cmd_show_options_all(struct cmd *, struct cmdq_item *,
struct options *);
@@ -38,10 +38,10 @@ const struct cmd_entry cmd_show_options_entry = {
.name = "show-options",
.alias = "show",
.args = { "gqst:vw", 0, 1 },
.usage = "[-gqsvw] [-t target-session|target-window] [option]",
.args = { "gHqst:vw", 0, 1 },
.usage = "[-gHqsvw] [-t target-session|target-window] [option]",
.tflag = CMD_WINDOW_CANFAIL,
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec
@@ -54,7 +54,20 @@ const struct cmd_entry cmd_show_window_options_entry = {
.args = { "gvt:", 0, 1 },
.usage = "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]",
.tflag = CMD_WINDOW_CANFAIL,
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec
};
const struct cmd_entry cmd_show_hooks_entry = {
.name = "show-hooks",
.alias = NULL,
.args = { "gt:", 0, 1 },
.usage = "[-g] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec
@@ -64,113 +77,179 @@ static enum cmd_retval
cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_find_state *fs = &item->state.tflag;
struct cmd_find_state *fs = &item->target;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct options *oo;
enum options_table_scope scope;
char *cause;
int window;
char *argument, *name = NULL, *cause;
const char *target;
int window, idx, ambiguous;
struct options_entry *o;
window = (self->entry == &cmd_show_window_options_entry);
scope = options_scope_from_flags(args, window, fs, &oo, &cause);
if (args->argc == 0) {
scope = options_scope_from_flags(args, window, fs, &oo, &cause);
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL);
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
return (cmd_show_options_all(self, item, oo));
}
argument = format_single(item, args->argv[0], c, s, wl, NULL);
name = options_match(argument, &idx, &ambiguous);
if (name == NULL) {
if (args_has(args, 'q'))
goto fail;
if (ambiguous)
cmdq_error(item, "ambiguous option: %s", argument);
else
cmdq_error(item, "invalid option: %s", argument);
goto fail;
}
if (*name == '@')
scope = options_scope_from_flags(args, window, fs, &oo, &cause);
else {
if (options_get_only(global_options, name) != NULL)
scope = OPTIONS_TABLE_SERVER;
else if (options_get_only(global_s_options, name) != NULL)
scope = OPTIONS_TABLE_SESSION;
else if (options_get_only(global_w_options, name) != NULL)
scope = OPTIONS_TABLE_WINDOW;
else {
scope = OPTIONS_TABLE_NONE;
xasprintf(&cause, "unknown option: %s", argument);
}
if (scope == OPTIONS_TABLE_SERVER)
oo = global_options;
else if (scope == OPTIONS_TABLE_SESSION) {
if (args_has(self->args, 'g'))
oo = global_s_options;
else if (s == NULL) {
target = args_get(args, 't');
if (target != NULL) {
cmdq_error(item, "no such session: %s",
target);
} else
cmdq_error(item, "no current session");
goto fail;
} else
oo = s->options;
} else if (scope == OPTIONS_TABLE_WINDOW) {
if (args_has(self->args, 'g'))
oo = global_w_options;
else if (wl == NULL) {
target = args_get(args, 't');
if (target != NULL) {
cmdq_error(item, "no such window: %s",
target);
} else
cmdq_error(item, "no current window");
goto fail;
} else
oo = wl->window->options;
}
}
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
goto fail;
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
goto fail;
}
o = options_get_only(oo, name);
if (o != NULL)
cmd_show_options_print(self, item, o, idx);
if (args->argc == 0)
return (cmd_show_options_all(self, item, oo));
else
return (cmd_show_options_one(self, item, oo));
free(name);
free(argument);
return (CMD_RETURN_NORMAL);
fail:
free(name);
free(argument);
return (CMD_RETURN_ERROR);
}
static void
cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
struct options_entry *o, int idx)
{
const char *name;
const char *value;
char *tmp, *escaped;
u_int size, i;
struct options_array_item *a;
const char *name = options_name(o);
char *value, *tmp = NULL, *escaped;
if (idx != -1) {
xasprintf(&tmp, "%s[%d]", options_name(o), idx);
xasprintf(&tmp, "%s[%d]", name, idx);
name = tmp;
} else {
if (options_array_size(o, &size) != -1) {
for (i = 0; i < size; i++) {
if (options_array_get(o, i) == NULL)
continue;
cmd_show_options_print(self, item, o, i);
if (options_isarray(o)) {
a = options_array_first(o);
if (a == NULL) {
if (!args_has(self->args, 'v'))
cmdq_print(item, "%s", name);
return;
}
while (a != NULL) {
idx = options_array_item_index(a);
cmd_show_options_print(self, item, o, idx);
a = options_array_next(a);
}
return;
}
tmp = NULL;
name = options_name(o);
}
value = options_tostring(o, idx, 0);
if (args_has(self->args, 'v'))
cmdq_print(item, "%s", value);
else if (options_isstring(o)) {
utf8_stravis(&escaped, value, VIS_OCTAL|VIS_TAB|VIS_NL|VIS_DQ);
cmdq_print(item, "%s \"%s\"", name, escaped);
escaped = args_escape(value);
cmdq_print(item, "%s %s", name, escaped);
free(escaped);
} else
cmdq_print(item, "%s %s", name, value);
free(value);
free(tmp);
}
static enum cmd_retval
cmd_show_options_one(struct cmd *self, struct cmdq_item *item,
struct options *oo)
{
struct args *args = self->args;
struct options_entry *o;
int idx, ambiguous;
const char *name = args->argv[0];
o = options_match_get(oo, name, &idx, 1, &ambiguous);
if (o == NULL) {
if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL);
if (ambiguous) {
cmdq_error(item, "ambiguous option: %s", name);
return (CMD_RETURN_ERROR);
}
if (*name != '@' &&
options_match_get(oo, name, &idx, 0, &ambiguous) != NULL)
return (CMD_RETURN_NORMAL);
cmdq_error(item, "unknown option: %s", name);
return (CMD_RETURN_ERROR);
}
cmd_show_options_print(self, item, o, idx);
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_show_options_all(struct cmd *self, struct cmdq_item *item,
struct options *oo)
{
struct options_entry *o;
struct options_entry *o;
struct options_array_item *a;
u_int idx;
const struct options_table_entry *oe;
u_int size, idx;
o = options_first(oo);
while (o != NULL) {
oe = options_table_entry(o);
if (oe != NULL && oe->style != NULL) {
if ((self->entry != &cmd_show_hooks_entry &&
!args_has(self->args, 'H') &&
oe != NULL &&
(oe->flags & OPTIONS_TABLE_IS_HOOK)) ||
(self->entry == &cmd_show_hooks_entry &&
(oe == NULL ||
(~oe->flags & OPTIONS_TABLE_IS_HOOK)))) {
o = options_next(o);
continue;
}
if (options_array_size(o, &size) == -1)
if (!options_isarray(o))
cmd_show_options_print(self, item, o, -1);
else {
for (idx = 0; idx < size; idx++) {
if (options_array_get(o, idx) == NULL)
continue;
else if ((a = options_array_first(o)) == NULL) {
if (!args_has(self->args, 'v'))
cmdq_print(item, "%s", options_name(o));
} else {
while (a != NULL) {
idx = options_array_item_index(a);
cmd_show_options_print(self, item, o, idx);
a = options_array_next(a);
}
}
o = options_next(o);

View File

@@ -37,8 +37,8 @@ const struct cmd_entry cmd_source_file_entry = {
.name = "source-file",
.alias = "source",
.args = { "q", 1, 1 },
.usage = "[-q] path",
.args = { "nq", 1, -1 },
.usage = "[-nq] path ...",
.flags = 0,
.exec = cmd_source_file_exec
@@ -48,45 +48,60 @@ static enum cmd_retval
cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
int quiet = args_has(args, 'q');
int flags = 0;
struct client *c = item->client;
struct cmdq_item *new_item;
struct cmdq_item *new_item, *after;
enum cmd_retval retval;
char *pattern, *tmp;
const char *path = args->argv[0];
char *pattern, *cwd;
const char *path, *error;
glob_t g;
u_int i;
int i;
u_int j;
if (*path == '/')
pattern = xstrdup(path);
else {
utf8_stravis(&tmp, server_client_get_cwd(c), VIS_GLOB);
xasprintf(&pattern, "%s/%s", tmp, path);
free(tmp);
}
log_debug("%s: %s", __func__, pattern);
if (args_has(args, 'q'))
flags |= CMD_PARSE_QUIET;
if (args_has(args, 'n'))
flags |= CMD_PARSE_PARSEONLY;
utf8_stravis(&cwd, server_client_get_cwd(c, NULL), VIS_GLOB);
retval = CMD_RETURN_NORMAL;
if (glob(pattern, 0, NULL, &g) != 0) {
if (!quiet || errno != ENOENT) {
cmdq_error(item, "%s: %s", path, strerror(errno));
retval = CMD_RETURN_ERROR;
for (i = 0; i < args->argc; i++) {
path = args->argv[i];
if (*path == '/')
pattern = xstrdup(path);
else
xasprintf(&pattern, "%s/%s", cwd, path);
log_debug("%s: %s", __func__, pattern);
if (glob(pattern, 0, NULL, &g) != 0) {
error = strerror(errno);
if (errno != ENOENT || (~flags & CMD_PARSE_QUIET)) {
cmdq_error(item, "%s: %s", path, error);
retval = CMD_RETURN_ERROR;
}
free(pattern);
continue;
}
free(pattern);
return (retval);
}
free(pattern);
for (i = 0; i < (u_int)g.gl_pathc; i++) {
if (load_cfg(g.gl_pathv[i], c, item, quiet) < 0)
retval = CMD_RETURN_ERROR;
after = item;
for (j = 0; j < g.gl_pathc; j++) {
path = g.gl_pathv[j];
if (load_cfg(path, c, after, flags, &new_item) < 0)
retval = CMD_RETURN_ERROR;
else if (new_item != NULL)
after = new_item;
}
globfree(&g);
}
if (cfg_finished) {
if (retval == CMD_RETURN_ERROR && c->session == NULL)
c->retval = 1;
new_item = cmdq_get_callback(cmd_source_file_done, NULL);
cmdq_insert_after(item, new_item);
}
globfree(&g);
free(cwd);
return (retval);
}

View File

@@ -39,11 +39,12 @@ const struct cmd_entry cmd_split_window_entry = {
.name = "split-window",
.alias = "splitw",
.args = { "bc:dfF:l:hp:Pt:v", 0, -1 },
.usage = "[-bdfhvP] [-c start-directory] [-F format] "
"[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]",
.args = { "bc:de:fF:hIl:p:Pt:v", 0, -1 },
.usage = "[-bdefhIPv] [-c start-directory] [-e environment] "
"[-F format] [-p percentage|-l size] " CMD_TARGET_PANE_USAGE
" [command]",
.tflag = CMD_PANE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_split_window_exec
@@ -53,111 +54,105 @@ static enum cmd_retval
cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct window *w = wl->window;
struct window_pane *wp = item->state.tflag.wp, *new_wp = NULL;
struct environ *env;
const char *cmd, *path, *shell, *template, *cwd, *to_free;
char **argv, *cause, *new_cause, *cp;
u_int hlimit;
int argc, size, percentage;
struct cmd_find_state *current = &item->shared->current;
struct spawn_context sc;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp, *new_wp;
enum layout_type type;
struct layout_cell *lc;
struct environ_entry *envent;
struct cmd_find_state fs;
struct cmd_find_state fs;
int size, percentage, flags, input;
const char *template, *add;
char *cause, *cp;
struct args_value *value;
server_unzoom_window(w);
if (args->argc == 0) {
cmd = options_get_string(s->options, "default-command");
if (cmd != NULL && *cmd != '\0') {
argc = 1;
argv = (char **)&cmd;
} else {
argc = 0;
argv = NULL;
}
} else {
argc = args->argc;
argv = args->argv;
}
to_free = NULL;
if (args_has(args, 'c')) {
cwd = args_get(args, 'c');
to_free = cwd = format_single(item, cwd, c, s, NULL, NULL);
} else if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
else
cwd = s->cwd;
type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT;
size = -1;
else
type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
xasprintf(&new_cause, "size %s", cause);
cmdq_error(item, "create pane failed: -l %s", cause);
free(cause);
cause = new_cause;
goto error;
return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause);
if (cause != NULL) {
xasprintf(&new_cause, "percentage %s", cause);
cmdq_error(item, "create pane failed: -p %s", cause);
free(cause);
cause = new_cause;
goto error;
return (CMD_RETURN_ERROR);
}
if (type == LAYOUT_TOPBOTTOM)
size = (wp->sy * percentage) / 100;
else
size = (wp->sx * percentage) / 100;
}
hlimit = options_get_number(s->options, "history-limit");
shell = options_get_string(s->options, "default-shell");
if (*shell == '\0' || areshell(shell))
shell = _PATH_BSHELL;
lc = layout_split_pane(wp, type, size, args_has(args, 'b'),
args_has(args, 'f'));
if (lc == NULL) {
cause = xstrdup("pane too small");
goto error;
}
new_wp = window_add_pane(w, wp, args_has(args, 'b'), hlimit);
layout_assign_pane(lc, new_wp);
path = NULL;
if (item->client != NULL && item->client->session == NULL)
envent = environ_find(item->client->environ, "PATH");
else
envent = environ_find(s->environ, "PATH");
if (envent != NULL)
path = envent->value;
env = environ_for_session(s);
if (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, env,
s->tio, &cause) != 0) {
environ_free(env);
goto error;
}
environ_free(env);
server_redraw_window(w);
if (!args_has(args, 'd')) {
window_set_active_pane(w, new_wp);
session_select(s, wl->idx);
server_redraw_session(s);
} else
server_status_session(s);
size = -1;
server_unzoom_window(wp->window);
input = (args_has(args, 'I') && args->argc == 0);
flags = 0;
if (args_has(args, 'b'))
flags |= SPAWN_BEFORE;
if (args_has(args, 'f'))
flags |= SPAWN_FULLSIZE;
if (input || (args->argc == 1 && *args->argv[0] == '\0'))
flags |= SPAWN_EMPTY;
lc = layout_split_pane(wp, type, size, flags);
if (lc == NULL) {
cmdq_error(item, "no space for new pane");
return (CMD_RETURN_ERROR);
}
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
sc.wl = wl;
sc.wp0 = wp;
sc.lc = lc;
sc.name = NULL;
sc.argc = args->argc;
sc.argv = args->argv;
sc.environ = environ_create();
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
add = args_next_value(&value);
}
sc.idx = -1;
sc.cwd = args_get(args, 'c');
sc.flags = flags;
if (args_has(args, 'd'))
sc.flags |= SPAWN_DETACHED;
if ((new_wp = spawn_pane(&sc, &cause)) == NULL) {
layout_close_pane(new_wp);
cmdq_error(item, "create pane failed: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (input && window_pane_start_input(new_wp, item, &cause) != 0) {
layout_close_pane(new_wp);
window_remove_pane(wp->window, new_wp);
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (!args_has(args, 'd'))
cmd_find_from_winlink_pane(current, wl, new_wp, 0);
server_redraw_window(wp->window);
server_status_session(s);
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
@@ -166,30 +161,12 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
cmdq_print(item, "%s", cp);
free(cp);
}
notify_window("window-layout-changed", w);
if (to_free != NULL)
free((void *)to_free);
cmd_find_clear_state(&fs, NULL, 0);
fs.s = s;
fs.wl = wl;
fs.w = w;
fs.wp = new_wp;
cmd_find_log_state(__func__, &fs);
hooks_insert(s->hooks, item, &fs, "after-split-window");
cmd_find_from_winlink_pane(&fs, wl, new_wp, 0);
cmdq_insert_hook(s, item, &fs, "after-split-window");
environ_free(sc.environ);
if (input)
return (CMD_RETURN_WAIT);
return (CMD_RETURN_NORMAL);
error:
if (new_wp != NULL) {
layout_close_pane(new_wp);
window_remove_pane(w, new_wp);
}
cmdq_error(item, "create pane failed: %s", cause);
free(cause);
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_ERROR);
}

View File

@@ -1,365 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "tmux.h"
/*
* Parse a command from a string.
*/
static int cmd_string_getc(const char *, size_t *);
static void cmd_string_ungetc(size_t *);
static void cmd_string_copy(char **, char *, size_t *);
static char *cmd_string_string(const char *, size_t *, char, int);
static char *cmd_string_variable(const char *, size_t *);
static char *cmd_string_expand_tilde(const char *, size_t *);
static int
cmd_string_getc(const char *s, size_t *p)
{
const u_char *ucs = s;
if (ucs[*p] == '\0')
return (EOF);
return (ucs[(*p)++]);
}
static void
cmd_string_ungetc(size_t *p)
{
(*p)--;
}
int
cmd_string_split(const char *s, int *rargc, char ***rargv)
{
size_t p = 0;
int ch, argc = 0, append = 0;
char **argv = NULL, *buf = NULL, *t;
const char *whitespace, *equals;
size_t len = 0;
for (;;) {
ch = cmd_string_getc(s, &p);
switch (ch) {
case '\'':
if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL)
goto error;
cmd_string_copy(&buf, t, &len);
break;
case '"':
if ((t = cmd_string_string(s, &p, '"', 1)) == NULL)
goto error;
cmd_string_copy(&buf, t, &len);
break;
case '$':
if ((t = cmd_string_variable(s, &p)) == NULL)
goto error;
cmd_string_copy(&buf, t, &len);
break;
case '#':
/* Comment: discard rest of line. */
while ((ch = cmd_string_getc(s, &p)) != EOF)
;
/* FALLTHROUGH */
case EOF:
case ' ':
case '\t':
if (buf != NULL) {
buf = xrealloc(buf, len + 1);
buf[len] = '\0';
argv = xreallocarray(argv, argc + 1,
sizeof *argv);
argv[argc++] = buf;
buf = NULL;
len = 0;
}
if (ch != EOF)
break;
while (argc != 0) {
equals = strchr(argv[0], '=');
whitespace = argv[0] + strcspn(argv[0], " \t");
if (equals == NULL || equals > whitespace)
break;
environ_put(global_environ, argv[0]);
argc--;
memmove(argv, argv + 1, argc * (sizeof *argv));
}
goto done;
case '~':
if (buf != NULL) {
append = 1;
break;
}
t = cmd_string_expand_tilde(s, &p);
if (t == NULL)
goto error;
cmd_string_copy(&buf, t, &len);
break;
default:
append = 1;
break;
}
if (append) {
if (len >= SIZE_MAX - 2)
goto error;
buf = xrealloc(buf, len + 1);
buf[len++] = ch;
}
append = 0;
}
done:
*rargc = argc;
*rargv = argv;
free(buf);
return (0);
error:
if (argv != NULL)
cmd_free_argv(argc, argv);
free(buf);
return (-1);
}
struct cmd_list *
cmd_string_parse(const char *s, const char *file, u_int line, char **cause)
{
struct cmd_list *cmdlist = NULL;
int argc;
char **argv;
*cause = NULL;
if (cmd_string_split(s, &argc, &argv) != 0)
goto error;
if (argc != 0) {
cmdlist = cmd_list_parse(argc, argv, file, line, cause);
if (cmdlist == NULL) {
cmd_free_argv(argc, argv);
goto error;
}
}
cmd_free_argv(argc, argv);
return (cmdlist);
error:
xasprintf(cause, "invalid or unknown command: %s", s);
return (NULL);
}
static void
cmd_string_copy(char **dst, char *src, size_t *len)
{
size_t srclen;
srclen = strlen(src);
*dst = xrealloc(*dst, *len + srclen + 1);
strlcpy(*dst + *len, src, srclen + 1);
*len += srclen;
free(src);
}
static char *
cmd_string_string(const char *s, size_t *p, char endch, int esc)
{
int ch;
char *buf, *t;
size_t len;
buf = NULL;
len = 0;
while ((ch = cmd_string_getc(s, p)) != endch) {
switch (ch) {
case EOF:
goto error;
case '\\':
if (!esc)
break;
switch (ch = cmd_string_getc(s, p)) {
case EOF:
goto error;
case 'e':
ch = '\033';
break;
case 'r':
ch = '\r';
break;
case 'n':
ch = '\n';
break;
case 't':
ch = '\t';
break;
}
break;
case '$':
if (!esc)
break;
if ((t = cmd_string_variable(s, p)) == NULL)
goto error;
cmd_string_copy(&buf, t, &len);
continue;
}
if (len >= SIZE_MAX - 2)
goto error;
buf = xrealloc(buf, len + 1);
buf[len++] = ch;
}
buf = xrealloc(buf, len + 1);
buf[len] = '\0';
return (buf);
error:
free(buf);
return (NULL);
}
static char *
cmd_string_variable(const char *s, size_t *p)
{
int ch, fch;
char *buf, *t;
size_t len;
struct environ_entry *envent;
#define cmd_string_first(ch) ((ch) == '_' || \
((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
#define cmd_string_other(ch) ((ch) == '_' || \
((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \
((ch) >= '0' && (ch) <= '9'))
buf = NULL;
len = 0;
fch = EOF;
switch (ch = cmd_string_getc(s, p)) {
case EOF:
goto error;
case '{':
fch = '{';
ch = cmd_string_getc(s, p);
if (!cmd_string_first(ch))
goto error;
/* FALLTHROUGH */
default:
if (!cmd_string_first(ch)) {
xasprintf(&t, "$%c", ch);
return (t);
}
buf = xrealloc(buf, len + 1);
buf[len++] = ch;
for (;;) {
ch = cmd_string_getc(s, p);
if (ch == EOF || !cmd_string_other(ch))
break;
else {
if (len >= SIZE_MAX - 3)
goto error;
buf = xrealloc(buf, len + 1);
buf[len++] = ch;
}
}
}
if (fch == '{' && ch != '}')
goto error;
if (ch != EOF && fch != '{')
cmd_string_ungetc(p); /* ch */
buf = xrealloc(buf, len + 1);
buf[len] = '\0';
envent = environ_find(global_environ, buf);
free(buf);
if (envent == NULL)
return (xstrdup(""));
return (xstrdup(envent->value));
error:
free(buf);
return (NULL);
}
static char *
cmd_string_expand_tilde(const char *s, size_t *p)
{
struct passwd *pw;
struct environ_entry *envent;
char *home, *path, *user, *cp;
int last;
home = NULL;
last = cmd_string_getc(s, p);
if (last == EOF || last == '/' || last == ' '|| last == '\t') {
envent = environ_find(global_environ, "HOME");
if (envent != NULL && *envent->value != '\0')
home = envent->value;
else if ((pw = getpwuid(getuid())) != NULL)
home = pw->pw_dir;
} else {
cmd_string_ungetc(p);
cp = user = xmalloc(strlen(s));
for (;;) {
last = cmd_string_getc(s, p);
if (last == EOF ||
last == '/' ||
last == ' '||
last == '\t')
break;
*cp++ = last;
}
*cp = '\0';
if ((pw = getpwnam(user)) != NULL)
home = pw->pw_dir;
free(user);
}
if (home == NULL)
return (NULL);
if (last != EOF)
xasprintf(&path, "%s%c", home, last);
else
xasprintf(&path, "%s", home);
return (path);
}

View File

@@ -35,8 +35,8 @@ const struct cmd_entry cmd_swap_pane_entry = {
.args = { "dDs:t:U", 0, 0 },
.usage = "[-dDU] " CMD_SRCDST_PANE_USAGE,
.sflag = CMD_PANE_MARKED,
.tflag = CMD_PANE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_swap_pane_exec
@@ -50,10 +50,10 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
struct layout_cell *src_lc, *dst_lc;
u_int sx, sy, xoff, yoff;
dst_w = item->state.tflag.wl->window;
dst_wp = item->state.tflag.wp;
src_w = item->state.sflag.wl->window;
src_wp = item->state.sflag.wp;
dst_w = item->target.wl->window;
dst_wp = item->target.wp;
src_w = item->source.wl->window;
src_wp = item->source.wp;
server_unzoom_window(dst_w);
if (args_has(self->args, 'D')) {
@@ -101,19 +101,17 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(self->args, 'd')) {
if (src_w != dst_w) {
window_set_active_pane(src_w, dst_wp);
window_set_active_pane(dst_w, src_wp);
window_set_active_pane(src_w, dst_wp, 1);
window_set_active_pane(dst_w, src_wp, 1);
} else {
tmp_wp = dst_wp;
if (!window_pane_visible(tmp_wp))
tmp_wp = src_wp;
window_set_active_pane(src_w, tmp_wp);
window_set_active_pane(src_w, tmp_wp, 1);
}
} else {
if (src_w->active == src_wp)
window_set_active_pane(src_w, dst_wp);
window_set_active_pane(src_w, dst_wp, 1);
if (dst_w->active == dst_wp)
window_set_active_pane(dst_w, src_wp);
window_set_active_pane(dst_w, src_wp, 1);
}
if (src_w != dst_w) {
if (src_w->last == src_wp)

View File

@@ -35,8 +35,8 @@ const struct cmd_entry cmd_swap_window_entry = {
.args = { "ds:t:", 0, 0 },
.usage = "[-d] " CMD_SRCDST_WINDOW_USAGE,
.sflag = CMD_WINDOW_MARKED,
.tflag = CMD_WINDOW,
.source = { 's', CMD_FIND_WINDOW, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_swap_window_exec
@@ -50,12 +50,12 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
struct winlink *wl_src, *wl_dst;
struct window *w_src, *w_dst;
wl_src = item->state.sflag.wl;
src = item->state.sflag.s;
wl_src = item->source.wl;
src = item->source.s;
sg_src = session_group_contains(src);
wl_dst = item->state.tflag.wl;
dst = item->state.tflag.s;
wl_dst = item->target.wl;
dst = item->target.s;
sg_dst = session_group_contains(dst);
if (src != dst && sg_src != NULL && sg_dst != NULL &&
@@ -78,9 +78,9 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
TAILQ_INSERT_TAIL(&w_dst->winlinks, wl_src, wentry);
if (!args_has(self->args, 'd')) {
session_select(dst, wl_dst->idx);
session_select(src, wl_src->idx);
if (src != dst)
session_select(src, wl_src->idx);
session_select(dst, wl_dst->idx);
}
session_group_synchronize_from(src);
server_redraw_session_group(src);

View File

@@ -38,8 +38,7 @@ const struct cmd_entry cmd_switch_client_entry = {
.usage = "[-Elnpr] [-c target-client] [-t target-session] "
"[-T key-table]",
.cflag = CMD_CLIENT,
.tflag = CMD_SESSION_WITHPANE,
/* -t is special */
.flags = CMD_READONLY,
.exec = cmd_switch_client_exec
@@ -49,13 +48,32 @@ static enum cmd_retval
cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_state *state = &item->state;
struct client *c = state->c;
struct session *s = item->state.tflag.s;
const char *tflag = args_get(args, 't');
enum cmd_find_type type;
int flags;
struct client *c;
struct session *s;
struct winlink *wl;
struct window_pane *wp;
const char *tablename;
struct key_table *table;
if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (tflag != NULL && tflag[strcspn(tflag, ":.%")] != '\0') {
type = CMD_FIND_PANE;
flags = 0;
} else {
type = CMD_FIND_SESSION;
flags = CMD_FIND_PREFER_UNATTACHED;
}
if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
return (CMD_RETURN_ERROR);
s = item->target.s;
wl = item->target.wl;
wp = item->target.wp;
if (args_has(args, 'r'))
c->flags ^= CLIENT_READONLY;
@@ -94,11 +112,14 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
} else {
if (item->client == NULL)
return (CMD_RETURN_NORMAL);
if (state->tflag.wl != NULL) {
wp = state->tflag.wp;
if (wp != NULL)
window_set_active_pane(wp->window, wp);
session_set_current(s, state->tflag.wl);
if (wl != NULL) {
server_unzoom_window(wl->window);
if (wp != NULL) {
window_redraw_active_switch(wp->window, wp);
window_set_active_pane(wp->window, wp, 1);
}
session_set_current(s, wl);
cmd_find_from_session(&item->shared->current, s, 0);
}
}
@@ -108,9 +129,11 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
if (c->session != NULL && c->session != s)
c->last_session = c->session;
c->session = s;
if (!item->repeat)
if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);

View File

@@ -170,7 +170,7 @@ cmd_wait_for_wait(struct cmdq_item *item, const char *name,
struct client *c = item->client;
struct wait_item *wi;
if (c == NULL || c->session != NULL) {
if (c == NULL) {
cmdq_error(item, "not able to wait");
return (CMD_RETURN_ERROR);
}
@@ -198,7 +198,7 @@ cmd_wait_for_lock(struct cmdq_item *item, const char *name,
{
struct wait_item *wi;
if (item->client == NULL || item->client->session != NULL) {
if (item->client == NULL) {
cmdq_error(item, "not able to lock");
return (CMD_RETURN_ERROR);
}

431
cmd.c
View File

@@ -33,9 +33,7 @@ extern const struct cmd_entry cmd_break_pane_entry;
extern const struct cmd_entry cmd_capture_pane_entry;
extern const struct cmd_entry cmd_choose_buffer_entry;
extern const struct cmd_entry cmd_choose_client_entry;
extern const struct cmd_entry cmd_choose_session_entry;
extern const struct cmd_entry cmd_choose_tree_entry;
extern const struct cmd_entry cmd_choose_window_entry;
extern const struct cmd_entry cmd_clear_history_entry;
extern const struct cmd_entry cmd_clock_mode_entry;
extern const struct cmd_entry cmd_command_prompt_entry;
@@ -43,6 +41,7 @@ extern const struct cmd_entry cmd_confirm_before_entry;
extern const struct cmd_entry cmd_copy_mode_entry;
extern const struct cmd_entry cmd_delete_buffer_entry;
extern const struct cmd_entry cmd_detach_client_entry;
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_panes_entry;
extern const struct cmd_entry cmd_down_pane_entry;
@@ -82,6 +81,7 @@ extern const struct cmd_entry cmd_refresh_client_entry;
extern const struct cmd_entry cmd_rename_session_entry;
extern const struct cmd_entry cmd_rename_window_entry;
extern const struct cmd_entry cmd_resize_pane_entry;
extern const struct cmd_entry cmd_resize_window_entry;
extern const struct cmd_entry cmd_respawn_pane_entry;
extern const struct cmd_entry cmd_respawn_window_entry;
extern const struct cmd_entry cmd_rotate_window_entry;
@@ -122,9 +122,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_capture_pane_entry,
&cmd_choose_buffer_entry,
&cmd_choose_client_entry,
&cmd_choose_session_entry,
&cmd_choose_tree_entry,
&cmd_choose_window_entry,
&cmd_clear_history_entry,
&cmd_clock_mode_entry,
&cmd_command_prompt_entry,
@@ -132,6 +130,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_copy_mode_entry,
&cmd_delete_buffer_entry,
&cmd_detach_client_entry,
&cmd_display_menu_entry,
&cmd_display_message_entry,
&cmd_display_panes_entry,
&cmd_find_window_entry,
@@ -170,6 +169,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_rename_session_entry,
&cmd_rename_window_entry,
&cmd_resize_pane_entry,
&cmd_resize_window_entry,
&cmd_respawn_pane_entry,
&cmd_respawn_window_entry,
&cmd_rotate_window_entry,
@@ -204,6 +204,45 @@ const struct cmd_entry *cmd_table[] = {
NULL
};
void printflike(3, 4)
cmd_log_argv(int argc, char **argv, const char *fmt, ...)
{
char *prefix;
va_list ap;
int i;
va_start(ap, fmt);
xvasprintf(&prefix, fmt, ap);
va_end(ap);
for (i = 0; i < argc; i++)
log_debug("%s: argv[%d]=%s", prefix, i, argv[i]);
free(prefix);
}
void
cmd_prepend_argv(int *argc, char ***argv, char *arg)
{
char **new_argv;
int i;
new_argv = xreallocarray(NULL, (*argc) + 1, sizeof *new_argv);
new_argv[0] = xstrdup(arg);
for (i = 0; i < *argc; i++)
new_argv[1 + i] = (*argv)[i];
free(*argv);
*argv = new_argv;
(*argc)++;
}
void
cmd_append_argv(int *argc, char ***argv, char *arg)
{
*argv = xreallocarray(*argv, (*argc) + 1, sizeof **argv);
(*argv)[(*argc)++] = xstrdup(arg);
}
int
cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
{
@@ -212,6 +251,7 @@ cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
if (argc == 0)
return (0);
cmd_log_argv(argc, argv, "%s", __func__);
*buf = '\0';
for (i = 0; i < argc; i++) {
@@ -244,9 +284,11 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
arglen = strlen(buf) + 1;
(*argv)[i] = xstrdup(buf);
buf += arglen;
len -= arglen;
}
cmd_log_argv(argc, *argv, "%s", __func__);
return (0);
}
@@ -305,106 +347,103 @@ cmd_stringify_argv(int argc, char **argv)
return (buf);
}
static int
cmd_try_alias(int *argc, char ***argv)
char *
cmd_get_alias(const char *name)
{
struct options_entry *o;
int old_argc = *argc, new_argc;
char **old_argv = *argv, **new_argv;
u_int size, idx;
int i;
size_t wanted;
const char *s, *cp = NULL;
struct options_entry *o;
struct options_array_item *a;
union options_value *ov;
size_t wanted, n;
const char *equals;
o = options_get_only(global_options, "command-alias");
if (o == NULL || options_array_size(o, &size) == -1 || size == 0)
return (-1);
if (o == NULL)
return (NULL);
wanted = strlen(name);
wanted = strlen(old_argv[0]);
for (idx = 0; idx < size; idx++) {
s = options_array_get(o, idx);
if (s == NULL)
continue;
a = options_array_first(o);
while (a != NULL) {
ov = options_array_item_value(a);
cp = strchr(s, '=');
if (cp == NULL || (size_t)(cp - s) != wanted)
equals = strchr(ov->string, '=');
if (equals != NULL) {
n = equals - ov->string;
if (n == wanted && strncmp(name, ov->string, n) == 0)
return (xstrdup(equals + 1));
}
a = options_array_next(a);
}
return (NULL);
}
static const struct cmd_entry *
cmd_find(const char *name, char **cause)
{
const struct cmd_entry **loop, *entry, *found = NULL;
int ambiguous;
char s[BUFSIZ];
ambiguous = 0;
for (loop = cmd_table; *loop != NULL; loop++) {
entry = *loop;
if (entry->alias != NULL && strcmp(entry->alias, name) == 0) {
ambiguous = 0;
found = entry;
break;
}
if (strncmp(entry->name, name, strlen(name)) != 0)
continue;
if (strncmp(old_argv[0], s, wanted) == 0)
if (found != NULL)
ambiguous = 1;
found = entry;
if (strcmp(entry->name, name) == 0)
break;
}
if (idx == size)
return (-1);
if (ambiguous)
goto ambiguous;
if (found == NULL) {
xasprintf(cause, "unknown command: %s", name);
return (NULL);
}
return (found);
if (cmd_string_split(cp + 1, &new_argc, &new_argv) != 0)
return (-1);
*argc = new_argc + old_argc - 1;
*argv = xcalloc((*argc) + 1, sizeof **argv);
for (i = 0; i < new_argc; i++)
(*argv)[i] = xstrdup(new_argv[i]);
for (i = 1; i < old_argc; i++)
(*argv)[new_argc + i - 1] = xstrdup(old_argv[i]);
log_debug("alias: %s=%s", old_argv[0], cp + 1);
for (i = 0; i < *argc; i++)
log_debug("alias: argv[%d] = %s", i, (*argv)[i]);
cmd_free_argv(new_argc, new_argv);
return (0);
ambiguous:
*s = '\0';
for (loop = cmd_table; *loop != NULL; loop++) {
entry = *loop;
if (strncmp(entry->name, name, strlen(name)) != 0)
continue;
if (strlcat(s, entry->name, sizeof s) >= sizeof s)
break;
if (strlcat(s, ", ", sizeof s) >= sizeof s)
break;
}
s[strlen(s) - 2] = '\0';
xasprintf(cause, "ambiguous command: %s, could be: %s", name, s);
return (NULL);
}
struct cmd *
cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause)
{
const struct cmd_entry *entry;
const char *name;
const struct cmd_entry **entryp, *entry;
struct cmd *cmd;
struct args *args;
char s[BUFSIZ];
int ambiguous, allocated = 0;
*cause = NULL;
if (argc == 0) {
xasprintf(cause, "no command");
return (NULL);
}
name = argv[0];
retry:
ambiguous = 0;
entry = NULL;
for (entryp = cmd_table; *entryp != NULL; entryp++) {
if ((*entryp)->alias != NULL &&
strcmp((*entryp)->alias, argv[0]) == 0) {
ambiguous = 0;
entry = *entryp;
break;
}
if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0)
continue;
if (entry != NULL)
ambiguous = 1;
entry = *entryp;
/* Bail now if an exact match. */
if (strcmp(entry->name, argv[0]) == 0)
break;
}
if ((ambiguous || entry == NULL) &&
server_proc != NULL &&
!allocated &&
cmd_try_alias(&argc, &argv) == 0) {
allocated = 1;
goto retry;
}
if (ambiguous)
goto ambiguous;
if (entry == NULL) {
xasprintf(cause, "unknown command: %s", name);
entry = cmd_find(name, cause);
if (entry == NULL)
return (NULL);
}
cmd_log_argv(argc, argv, "%s: %s", __func__, entry->name);
args = args_parse(entry->args.template, argc, argv);
if (args == NULL)
@@ -422,23 +461,11 @@ retry:
cmd->file = xstrdup(file);
cmd->line = line;
if (allocated)
cmd_free_argv(argc, argv);
return (cmd);
cmd->alias = NULL;
cmd->argc = argc;
cmd->argv = cmd_copy_argv(argc, argv);
ambiguous:
*s = '\0';
for (entryp = cmd_table; *entryp != NULL; entryp++) {
if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0)
continue;
if (strlcat(s, (*entryp)->name, sizeof s) >= sizeof s)
break;
if (strlcat(s, ", ", sizeof s) >= sizeof s)
break;
}
s[strlen(s) - 2] = '\0';
xasprintf(cause, "ambiguous command: %s, could be: %s", name, s);
return (NULL);
return (cmd);
usage:
if (args != NULL)
@@ -447,188 +474,16 @@ usage:
return (NULL);
}
static int
cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
struct cmdq_item *item)
void
cmd_free(struct cmd *cmd)
{
int targetflags, error;
struct cmd_find_state *fs = NULL;
struct cmd_find_state current;
free(cmd->alias);
cmd_free_argv(cmd->argc, cmd->argv);
if (flag == CMD_NONE ||
flag == CMD_CLIENT ||
flag == CMD_CLIENT_CANFAIL)
return (0);
free(cmd->file);
if (c == 't')
fs = &item->state.tflag;
else if (c == 's')
fs = &item->state.sflag;
if (flag == CMD_SESSION_WITHPANE) {
if (target != NULL && target[strcspn(target, ":.")] != '\0')
flag = CMD_PANE;
else
flag = CMD_SESSION_PREFERUNATTACHED;
}
targetflags = 0;
switch (flag) {
case CMD_SESSION:
case CMD_SESSION_CANFAIL:
case CMD_SESSION_PREFERUNATTACHED:
case CMD_SESSION_WITHPANE:
if (flag == CMD_SESSION_CANFAIL)
targetflags |= CMD_FIND_QUIET;
if (flag == CMD_SESSION_PREFERUNATTACHED)
targetflags |= CMD_FIND_PREFER_UNATTACHED;
break;
case CMD_MOVEW_R:
flag = CMD_WINDOW_INDEX;
/* FALLTHROUGH */
case CMD_WINDOW:
case CMD_WINDOW_CANFAIL:
case CMD_WINDOW_MARKED:
case CMD_WINDOW_INDEX:
if (flag == CMD_WINDOW_CANFAIL)
targetflags |= CMD_FIND_QUIET;
if (flag == CMD_WINDOW_MARKED)
targetflags |= CMD_FIND_DEFAULT_MARKED;
if (flag == CMD_WINDOW_INDEX)
targetflags |= CMD_FIND_WINDOW_INDEX;
break;
case CMD_PANE:
case CMD_PANE_CANFAIL:
case CMD_PANE_MARKED:
if (flag == CMD_PANE_CANFAIL)
targetflags |= CMD_FIND_QUIET;
if (flag == CMD_PANE_MARKED)
targetflags |= CMD_FIND_DEFAULT_MARKED;
break;
default:
fatalx("unknown %cflag %d", c, flag);
}
log_debug("%s: flag %c %d %#x", __func__, c, flag, targetflags);
error = cmd_find_current(&current, item, targetflags);
if (error != 0) {
if (~targetflags & CMD_FIND_QUIET)
return (-1);
cmd_find_clear_state(&current, NULL, 0);
}
if (!cmd_find_empty_state(&current) && !cmd_find_valid_state(&current))
fatalx("invalid current state");
switch (flag) {
case CMD_NONE:
case CMD_CLIENT:
case CMD_CLIENT_CANFAIL:
return (0);
case CMD_SESSION:
case CMD_SESSION_CANFAIL:
case CMD_SESSION_PREFERUNATTACHED:
case CMD_SESSION_WITHPANE:
error = cmd_find_target(fs, &current, item, target,
CMD_FIND_SESSION, targetflags);
if (error != 0)
goto error;
break;
case CMD_MOVEW_R:
error = cmd_find_target(fs, &current, item, target,
CMD_FIND_SESSION, CMD_FIND_QUIET);
if (error == 0)
break;
/* FALLTHROUGH */
case CMD_WINDOW:
case CMD_WINDOW_CANFAIL:
case CMD_WINDOW_MARKED:
case CMD_WINDOW_INDEX:
error = cmd_find_target(fs, &current, item, target,
CMD_FIND_WINDOW, targetflags);
if (error != 0)
goto error;
break;
case CMD_PANE:
case CMD_PANE_CANFAIL:
case CMD_PANE_MARKED:
error = cmd_find_target(fs, &current, item, target,
CMD_FIND_PANE, targetflags);
if (error != 0)
goto error;
break;
default:
fatalx("unknown %cflag %d", c, flag);
}
return (0);
error:
if (~targetflags & CMD_FIND_QUIET)
return (-1);
cmd_find_clear_state(fs, NULL, 0);
return (0);
}
int
cmd_prepare_state(struct cmd *cmd, struct cmdq_item *item)
{
const struct cmd_entry *entry = cmd->entry;
struct cmd_state *state = &item->state;
char *tmp;
enum cmd_entry_flag flag;
const char *s;
int error;
tmp = cmd_print(cmd);
log_debug("preparing state for %s (client %p)", tmp, item->client);
free(tmp);
state->c = NULL;
cmd_find_clear_state(&state->tflag, NULL, 0);
cmd_find_clear_state(&state->sflag, NULL, 0);
flag = cmd->entry->cflag;
if (flag == CMD_NONE) {
flag = cmd->entry->tflag;
if (flag == CMD_CLIENT || flag == CMD_CLIENT_CANFAIL)
s = args_get(cmd->args, 't');
else
s = NULL;
} else
s = args_get(cmd->args, 'c');
switch (flag) {
case CMD_CLIENT:
state->c = cmd_find_client(item, s, 0);
if (state->c == NULL)
return (-1);
break;
default:
state->c = cmd_find_client(item, s, 1);
break;
}
log_debug("using client %p", state->c);
s = args_get(cmd->args, 't');
log_debug("preparing -t state: target %s", s == NULL ? "none" : s);
error = cmd_prepare_state_flag('t', s, entry->tflag, item);
if (error != 0)
return (error);
s = args_get(cmd->args, 's');
log_debug("preparing -s state: target %s", s == NULL ? "none" : s);
error = cmd_prepare_state_flag('s', s, entry->sflag, item);
if (error != 0)
return (error);
if (!cmd_find_empty_state(&state->tflag) &&
!cmd_find_valid_state(&state->tflag))
fatalx("invalid -t state");
if (!cmd_find_empty_state(&state->sflag) &&
!cmd_find_valid_state(&state->sflag))
fatalx("invalid -s state");
return (0);
args_free(cmd->args);
free(cmd);
}
char *
@@ -654,17 +509,16 @@ cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
u_int x, y;
if (last) {
x = m->lx;
y = m->ly;
x = m->lx + m->ox;
y = m->ly + m->oy;
} else {
x = m->x;
y = m->y;
x = m->x + m->ox;
y = m->y + m->oy;
}
log_debug("%s: x=%u, y=%u%s", __func__, x, y, last ? " (last)" : "");
if (m->statusat == 0 && y > 0)
y--;
else if (m->statusat > 0 && y >= (u_int)m->statusat)
y = m->statusat - 1;
if (x < wp->xoff || x >= wp->xoff + wp->sx)
return (-1);
@@ -684,17 +538,22 @@ cmd_mouse_window(struct mouse_event *m, struct session **sp)
{
struct session *s;
struct window *w;
struct winlink *wl;
if (!m->valid || m->s == -1 || m->w == -1)
if (!m->valid)
return (NULL);
if ((s = session_find_by_id(m->s)) == NULL)
if (m->s == -1 || (s = session_find_by_id(m->s)) == NULL)
return (NULL);
if ((w = window_find_by_id(m->w)) == NULL)
return (NULL);
if (m->w == -1)
wl = s->curw;
else {
if ((w = window_find_by_id(m->w)) == NULL)
return (NULL);
wl = winlink_find_by_window(&s->windows, w);
}
if (sp != NULL)
*sp = s;
return (winlink_find_by_window(&s->windows, w));
return (wl);
}
/* Get current mouse pane if any. */

View File

@@ -141,6 +141,8 @@ colour_tostring(int c)
return ("white");
case 8:
return ("default");
case 9:
return ("terminal");
case 90:
return ("brightblack");
case 91:
@@ -158,7 +160,7 @@ colour_tostring(int c)
case 97:
return ("brightwhite");
}
return (NULL);
return ("invalid");
}
/* Convert colour from string. */
@@ -188,6 +190,11 @@ colour_fromstring(const char *s)
return (n | COLOUR_FLAG_256);
}
if (strcasecmp(s, "default") == 0)
return (8);
if (strcasecmp(s, "terminal") == 0)
return (9);
if (strcasecmp(s, "black") == 0 || strcmp(s, "0") == 0)
return (0);
if (strcasecmp(s, "red") == 0 || strcmp(s, "1") == 0)
@@ -204,8 +211,6 @@ colour_fromstring(const char *s)
return (6);
if (strcasecmp(s, "white") == 0 || strcmp(s, "7") == 0)
return (7);
if (strcasecmp(s, "default") == 0 || strcmp(s, "8") == 0)
return (8);
if (strcasecmp(s, "brightblack") == 0 || strcmp(s, "90") == 0)
return (90);
if (strcasecmp(s, "brightred") == 0 || strcmp(s, "91") == 0)

View File

@@ -18,6 +18,7 @@
#define COMPAT_H
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <limits.h>
@@ -66,6 +67,7 @@ void warnx(const char *, ...);
#define _PATH_DEVNULL "/dev/null"
#define _PATH_TTY "/dev/tty"
#define _PATH_DEV "/dev/"
#define _PATH_DEFPATH "/usr/bin:/bin"
#endif
#ifndef __OpenBSD__
@@ -100,17 +102,17 @@ void warnx(const char *, ...);
#include <paths.h>
#endif
#ifdef HAVE_FORKPTY
#ifdef HAVE_LIBUTIL_H
#include <libutil.h>
#endif
#ifdef HAVE_PTY_H
#include <pty.h>
#endif
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
#endif
#ifdef HAVE_VIS
#include <vis.h>
@@ -260,6 +262,11 @@ size_t strnlen(const char *, size_t);
char *strndup(const char *, size_t);
#endif
#ifndef HAVE_MEMMEM
/* memmem.c */
void *memmem(const void *, size_t, const void *, size_t);
#endif
#ifndef HAVE_DAEMON
/* daemon.c */
int daemon(int, int);
@@ -283,9 +290,15 @@ int b64_ntop(const char *, size_t, char *, size_t);
int b64_pton(const char *, u_char *, size_t);
#endif
#ifndef HAVE_FDFORKPTY
/* fdforkpty.c */
int getptmfd(void);
pid_t fdforkpty(int, int *, char *, struct termios *,
struct winsize *);
#endif
#ifndef HAVE_FORKPTY
/* forkpty.c */
#include <sys/ioctl.h>
pid_t forkpty(int *, char *, struct termios *, struct winsize *);
#endif
@@ -300,10 +313,6 @@ int vasprintf(char **, const char *, va_list);
char *fgetln(FILE *, size_t *);
#endif
#ifndef HAVE_FPARSELN
char *fparseln(FILE *, size_t *, size_t *, const char *, int);
#endif
#ifndef HAVE_SETENV
/* setenv.c */
int setenv(const char *, const char *, int);
@@ -337,9 +346,7 @@ int utf8proc_mbtowc(wchar_t *, const char *, size_t);
int utf8proc_wctomb(char *, wchar_t);
#endif
#ifdef HAVE_GETOPT
#include <getopt.h>
#else
#ifndef HAVE_GETOPT
/* getopt.c */
extern int BSDopterr;
extern int BSDoptind;

85
compat/daemon-darwin.c Normal file
View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Copyright (c) 2011-2013, Chris Johnsen <chris_johnsen@pobox.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <mach/mach.h>
#include <Availability.h>
#include <unistd.h>
void daemon_darwin(void);
#ifdef __MAC_10_10
extern kern_return_t bootstrap_look_up_per_user(mach_port_t, const char *,
uid_t, mach_port_t *);
extern kern_return_t bootstrap_get_root(mach_port_t, mach_port_t *);
void
daemon_darwin(void)
{
mach_port_t root = MACH_PORT_NULL;
mach_port_t s = MACH_PORT_NULL;
uid_t uid;
uid = getuid();
if (bootstrap_get_root(bootstrap_port, &root) == KERN_SUCCESS &&
bootstrap_look_up_per_user(root, NULL, uid, &s) == KERN_SUCCESS &&
task_set_bootstrap_port(mach_task_self(), s) == KERN_SUCCESS &&
mach_port_deallocate(mach_task_self(), bootstrap_port) == KERN_SUCCESS)
bootstrap_port = s;
}
#else
void
daemon_darwin(void)
{
}
#endif

View File

@@ -28,12 +28,18 @@
* SUCH DAMAGE.
*/
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include "compat.h"
#ifdef __APPLE__
extern void daemon_darwin(void);
#endif
int
daemon(int nochdir, int noclose)
{
@@ -61,5 +67,9 @@ daemon(int nochdir, int noclose)
if (fd > 2)
(void)close (fd);
}
#ifdef __APPLE__
daemon_darwin();
#endif
return (0);
}

34
compat/fdforkpty.c Normal file
View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <limits.h>
#include "compat.h"
int
getptmfd(void)
{
return (INT_MAX);
}
pid_t
fdforkpty(__unused int ptmfd, int *master, char *name, struct termios *tio,
struct winsize *ws)
{
return (forkpty(master, name, tio, ws));
}

View File

@@ -29,7 +29,8 @@ void fatal(const char *, ...);
void fatalx(const char *, ...);
pid_t
forkpty(int *master, unused char *name, struct termios *tio, struct winsize *ws)
forkpty(int *master, __unused char *name, struct termios *tio,
struct winsize *ws)
{
int slave = -1, fd, pipe_fd[2];
char *path, dummy;

View File

@@ -1,221 +0,0 @@
/* $OpenBSD: fparseln.c,v 1.6 2005/08/02 21:46:23 espie Exp $ */
/* $NetBSD: fparseln.c,v 1.7 1999/07/02 15:49:12 simonb Exp $ */
/*
* Copyright (c) 1997 Christos Zoulas. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Christos Zoulas.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* OPENBSD ORIGINAL: lib/libutil/fparseln.c */
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "compat.h"
/*
* fparseln() specific operation flags.
*/
#define FPARSELN_UNESCESC 0x01
#define FPARSELN_UNESCCONT 0x02
#define FPARSELN_UNESCCOMM 0x04
#define FPARSELN_UNESCREST 0x08
#define FPARSELN_UNESCALL 0x0f
static int isescaped(const char *, const char *, int);
/* isescaped():
* Return true if the character in *p that belongs to a string
* that starts in *sp, is escaped by the escape character esc.
*/
static int
isescaped(const char *sp, const char *p, int esc)
{
const char *cp;
size_t ne;
/* No escape character */
if (esc == '\0')
return 1;
/* Count the number of escape characters that precede ours */
for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++)
continue;
/* Return true if odd number of escape characters */
return (ne & 1) != 0;
}
/* fparseln():
* Read a line from a file parsing continuations ending in \
* and eliminating trailing newlines, or comments starting with
* the comment char.
*/
char *
fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3],
int flags)
{
static const char dstr[3] = { '\\', '\\', '#' };
char *buf = NULL, *ptr, *cp, esc, con, nl, com;
size_t s, len = 0;
int cnt = 1;
if (str == NULL)
str = dstr;
esc = str[0];
con = str[1];
com = str[2];
/*
* XXX: it would be cool to be able to specify the newline character,
* but unfortunately, fgetln does not let us
*/
nl = '\n';
while (cnt) {
cnt = 0;
if (lineno)
(*lineno)++;
if ((ptr = fgetln(fp, &s)) == NULL)
break;
if (s && com) { /* Check and eliminate comments */
for (cp = ptr; cp < ptr + s; cp++)
if (*cp == com && !isescaped(ptr, cp, esc)) {
s = cp - ptr;
cnt = s == 0 && buf == NULL;
break;
}
}
if (s && nl) { /* Check and eliminate newlines */
cp = &ptr[s - 1];
if (*cp == nl)
s--; /* forget newline */
}
if (s && con) { /* Check and eliminate continuations */
cp = &ptr[s - 1];
if (*cp == con && !isescaped(ptr, cp, esc)) {
s--; /* forget escape */
cnt = 1;
}
}
if (s == 0 && buf != NULL)
continue;
if ((cp = realloc(buf, len + s + 1)) == NULL) {
free(buf);
return NULL;
}
buf = cp;
(void) memcpy(buf + len, ptr, s);
len += s;
buf[len] = '\0';
}
if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL &&
strchr(buf, esc) != NULL) {
ptr = cp = buf;
while (cp[0] != '\0') {
int skipesc;
while (cp[0] != '\0' && cp[0] != esc)
*ptr++ = *cp++;
if (cp[0] == '\0' || cp[1] == '\0')
break;
skipesc = 0;
if (cp[1] == com)
skipesc += (flags & FPARSELN_UNESCCOMM);
if (cp[1] == con)
skipesc += (flags & FPARSELN_UNESCCONT);
if (cp[1] == esc)
skipesc += (flags & FPARSELN_UNESCESC);
if (cp[1] != com && cp[1] != con && cp[1] != esc)
skipesc = (flags & FPARSELN_UNESCREST);
if (skipesc)
cp++;
else
*ptr++ = *cp++;
*ptr++ = *cp++;
}
*ptr = '\0';
len = strlen(buf);
}
if (size)
*size = len;
return buf;
}
#ifdef TEST
int main(int, char **);
int
main(argc, argv)
int argc;
char **argv;
{
char *ptr;
size_t size, line;
line = 0;
while ((ptr = fparseln(stdin, &size, &line, NULL,
FPARSELN_UNESCALL)) != NULL)
printf("line %d (%d) |%s|\n", line, size, ptr);
return 0;
}
/*
# This is a test
line 1
line 2 \
line 3 # Comment
line 4 \# Not comment \\\\
# And a comment \
line 5 \\\
line 6
*/
#endif /* TEST */

View File

@@ -30,19 +30,12 @@ getdtablecount(void)
{
char path[PATH_MAX];
glob_t g;
int n;
int n = 0;
if (snprintf(path, sizeof path, "/proc/%ld/fd/*", (long)getpid()) < 0)
fatal("snprintf overflow");
switch (glob(path, 0, NULL, &g)) {
case GLOB_NOMATCH:
return (0);
case 0:
break;
default:
fatal("glob(\"%s\") failed", path);
}
n = g.gl_pathc;
if (glob(path, 0, NULL, &g) == 0)
n = g.gl_pathc;
globfree(&g);
return (n);
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: imsg-buffer.c,v 1.10 2017/04/11 09:57:19 reyk Exp $ */
/* $OpenBSD: imsg-buffer.c,v 1.11 2017/12/14 09:27:44 kettenis Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -29,9 +29,9 @@
#include "compat.h"
#include "imsg.h"
int ibuf_realloc(struct ibuf *, size_t);
void ibuf_enqueue(struct msgbuf *, struct ibuf *);
void ibuf_dequeue(struct msgbuf *, struct ibuf *);
static int ibuf_realloc(struct ibuf *, size_t);
static void ibuf_enqueue(struct msgbuf *, struct ibuf *);
static void ibuf_dequeue(struct msgbuf *, struct ibuf *);
struct ibuf *
ibuf_open(size_t len)
@@ -67,7 +67,7 @@ ibuf_dynamic(size_t len, size_t max)
return (buf);
}
int
static int
ibuf_realloc(struct ibuf *buf, size_t len)
{
u_char *b;
@@ -289,14 +289,14 @@ again:
return (1);
}
void
static void
ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
{
TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
msgbuf->queued++;
}
void
static void
ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
{
TAILQ_REMOVE(&msgbuf->bufs, buf, entry);

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: imsg.c,v 1.15 2017/04/11 09:57:19 reyk Exp $ */
/* $OpenBSD: imsg.c,v 1.16 2017/12/14 09:27:44 kettenis Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -30,7 +30,7 @@
int imsg_fd_overhead = 0;
int imsg_get_fd(struct imsgbuf *);
static int imsg_get_fd(struct imsgbuf *);
void
imsg_init(struct imsgbuf *ibuf, int fd)
@@ -266,7 +266,7 @@ imsg_free(struct imsg *imsg)
freezero(imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE);
}
int
static int
imsg_get_fd(struct imsgbuf *ibuf)
{
int fd;

65
compat/memmem.c Normal file
View File

@@ -0,0 +1,65 @@
/* $OpenBSD: memmem.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */
/*-
* Copyright (c) 2005 Pascal Gloor <pascal.gloor@spale.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <string.h>
#include "compat.h"
/*
* Find the first occurrence of the byte string s in byte string l.
*/
void *
memmem(const void *l, size_t l_len, const void *s, size_t s_len)
{
const char *cur, *last;
const char *cl = l;
const char *cs = s;
/* a zero length needle should just return the haystack */
if (s_len == 0)
return (void *)cl;
/* "s" must be smaller or equal to "l" */
if (l_len < s_len)
return NULL;
/* special case where s_len == 1 */
if (s_len == 1)
return memchr(l, *cs, l_len);
/* the last position where its possible to find "s" in "l" */
last = cl + l_len - s_len;
for (cur = cl; cur <= last; cur++)
if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
return (void *)cur;
return NULL;
}

View File

@@ -15,13 +15,15 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "compat.h"
int
setenv(const char *name, const char *value, unused int overwrite)
setenv(const char *name, const char *value, __unused int overwrite)
{
char *newval;

View File

@@ -1,6 +1,6 @@
# configure.ac
AC_INIT(tmux, 2.4)
AC_INIT([tmux], 3.0-rc3)
AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc)
@@ -28,6 +28,7 @@ AC_PROG_CC_C99
AC_PROG_CPP
AC_PROG_EGREP
AC_PROG_INSTALL
AC_PROG_YACC
PKG_PROG_PKG_CONFIG
AC_USE_SYSTEM_EXTENSIONS
@@ -35,6 +36,7 @@ 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,
AC_HELP_STRING(--enable-debug, enable debug build flags),
@@ -103,10 +105,10 @@ AC_REPLACE_FUNCS([ \
closefrom \
explicit_bzero \
fgetln \
fparseln \
freezero \
getdtablecount \
getprogname \
memmem \
recallocarray \
reallocarray \
setenv \
@@ -175,7 +177,8 @@ if test "x$found_ncurses" = xno; then
)
fi
if test "x$found_ncurses" = xyes; then
CPPFLAGS="$LIBNCURSES_CFLAGS $LIBTINFO_CFLAGS $CPPFLAGS"
AM_CFLAGS="$LIBNCURSES_CFLAGS $LIBTINFO_CFLAGS $AM_CFLAGS"
CFLAGS="$LIBNCURSES_CFLAGS $LIBTINFO_CFLAGS $CFLAGS"
LIBS="$LIBNCURSES_LIBS $LIBTINFO_LIBS $LIBS"
else
# pkg-config didn't work, try ncurses.
@@ -283,6 +286,7 @@ if test "x$found_b64_ntop" = xno; then
AC_MSG_RESULT(no)
AC_MSG_CHECKING(for b64_ntop with -lresolv)
OLD_LIBS="$LIBS"
LIBS="$LIBS -lresolv"
AC_TRY_LINK(
[
@@ -295,6 +299,7 @@ if test "x$found_b64_ntop" = xno; then
found_b64_ntop=no
)
if test "x$found_b64_ntop" = xno; then
LIBS="$OLD_LIBS"
AC_MSG_RESULT(no)
fi
fi
@@ -453,13 +458,22 @@ else
AC_LIBOBJ(getopt)
fi
# Look for forkpty in libutil. compat/forkpty-*.c is linked if not found.
# Look for fdforkpty and forkpty in libutil.
AC_SEARCH_LIBS(fdforkpty, util, found_fdforkpty=yes, found_fdforkpty=no)
if test "x$found_fdforkpty" = xyes; then
AC_DEFINE(HAVE_FDFORKPTY)
else
AC_LIBOBJ(fdforkpty)
fi
AC_SEARCH_LIBS(forkpty, util, found_forkpty=yes, found_forkpty=no)
if test "x$found_forkpty" = xyes; then
AC_DEFINE(HAVE_FORKPTY)
fi
AM_CONDITIONAL(NEED_FORKPTY, test "x$found_forkpty" = xno)
# Look for kinfo_getfile in libutil.
AC_SEARCH_LIBS(kinfo_getfile, [util util-freebsd])
# Look for a suitable queue.h.
AC_CHECK_DECL(
TAILQ_CONCAT,
@@ -555,8 +569,15 @@ case "$host_os" in
;;
*darwin*)
AC_MSG_RESULT(darwin)
AC_DEFINE(BROKEN_CMSG_FIRSTHDR)
PLATFORM=darwin
#
# OS X CMSG_FIRSTHDR is broken, so redefine it with a working
# one. daemon works but has some stupid side effects, so use
# our internal version which has a workaround.
#
AC_DEFINE(BROKEN_CMSG_FIRSTHDR)
AC_LIBOBJ(daemon)
AC_LIBOBJ(daemon-darwin)
;;
*dragonfly*)
AC_MSG_RESULT(dragonfly)
@@ -585,13 +606,22 @@ case "$host_os" in
*solaris*)
AC_MSG_RESULT(sunos)
PLATFORM=sunos
MANFORMAT=man
case `/usr/bin/nroff --version 2>&1` in
*GNU*)
# Solaris 11.4 and later use GNU groff.
MANFORMAT=mdoc
;;
*)
# Solaris 2.0 to 11.3 use AT&T nroff.
MANFORMAT=man
;;
esac
;;
*hpux*)
AC_MSG_RESULT(hpux)
PLATFORM=hpux
;;
*cygwin*)
*cygwin*|*msys*)
AC_MSG_RESULT(cygwin)
PLATFORM=cygwin
;;

View File

@@ -28,25 +28,22 @@
void
control_notify_input(struct client *c, struct window_pane *wp,
struct evbuffer *input)
const u_char *buf, size_t len)
{
u_char *buf;
size_t len;
struct evbuffer *message;
u_int i;
if (c->session == NULL)
return;
buf = EVBUFFER_DATA(input);
len = EVBUFFER_LENGTH(input);
/*
* Only write input if the window pane is linked to a window belonging
* to the client's session.
*/
if (winlink_find_by_window(&c->session->windows, wp->window) != NULL) {
message = evbuffer_new();
if (message == NULL)
fatalx("out of memory");
evbuffer_add_printf(message, "%%output %%%u ", wp->id);
for (i = 0; i < len; i++) {
if (buf[i] < ' ' || buf[i] == '\\')
@@ -59,14 +56,27 @@ control_notify_input(struct client *c, struct window_pane *wp,
}
}
void
control_notify_pane_mode_changed(int pane)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue;
control_write(c, "%%pane-mode-changed %%%u", pane);
}
}
void
control_notify_window_layout_changed(struct window *w)
{
struct client *c;
struct session *s;
struct winlink *wl;
const char *template;
char *cp;
struct client *c;
struct session *s;
struct winlink *wl;
const char *template;
char *cp;
template = "%layout-change #{window_id} #{window_layout} "
"#{window_visible_layout} #{window_flags}";
@@ -96,6 +106,20 @@ control_notify_window_layout_changed(struct window *w)
}
}
void
control_notify_window_pane_changed(struct window *w)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue;
control_write(c, "%%window-pane-changed @%u %%%u", w->id,
w->active->id);
}
}
void
control_notify_window_unlinked(__unused struct session *s, struct window *w)
{
@@ -154,15 +178,27 @@ control_notify_window_renamed(struct window *w)
}
void
control_notify_client_session_changed(struct client *c)
control_notify_client_session_changed(struct client *cc)
{
struct client *c;
struct session *s;
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
if (cc->session == NULL)
return;
s = c->session;
s = cc->session;
control_write(c, "%%session-changed $%u %s", s->id, s->name);
TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
continue;
if (cc == c) {
control_write(c, "%%session-changed $%u %s", s->id,
s->name);
} else {
control_write(c, "%%client-session-changed %s $%u %s",
cc->name, s->id, s->name);
}
}
}
void
@@ -203,3 +239,17 @@ control_notify_session_closed(__unused struct session *s)
control_write(c, "%%sessions-changed");
}
}
void
control_notify_session_window_changed(struct session *s)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue;
control_write(c, "%%session-window-changed $%u @%u", s->id,
s->curw->window->id);
}
}

View File

@@ -68,10 +68,9 @@ control_error(struct cmdq_item *item, void *data)
void
control_callback(struct client *c, int closed, __unused void *data)
{
char *line, *cause;
struct cmd_list *cmdlist;
struct cmd *cmd;
char *line;
struct cmdq_item *item;
struct cmd_parse_result *pr;
if (closed)
c->flags |= CLIENT_EXIT;
@@ -85,16 +84,20 @@ control_callback(struct client *c, int closed, __unused void *data)
break;
}
cmdlist = cmd_string_parse(line, NULL, 0, &cause);
if (cmdlist == NULL) {
item = cmdq_get_callback(control_error, cause);
pr = cmd_parse_from_string(line, NULL);
switch (pr->status) {
case CMD_PARSE_EMPTY:
break;
case CMD_PARSE_ERROR:
item = cmdq_get_callback(control_error, pr->error);
cmdq_append(c, item);
} else {
TAILQ_FOREACH(cmd, &cmdlist->list, qentry)
cmd->flags |= CMD_CONTROL;
item = cmdq_get_command(cmdlist, NULL, NULL, 0);
break;
case CMD_PARSE_SUCCESS:
item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
item->shared->flags |= CMDQ_SHARED_CONTROL;
cmdq_append(c, item);
cmd_list_free(cmdlist);
cmd_list_free(pr->cmdlist);
break;
}
free(line);

Some files were not shown because too many files have changed in this diff Show More