1578 Commits
3.0 ... 3.2a

Author SHA1 Message Date
Nicholas Marriott
3b929f332a Update CHANGES. 2021-06-10 09:24:57 +01:00
Nicholas Marriott
c827f5092d Do not clear region based on current cursor position, this is not necessary
anymore and causes problems, GitHub issue 2735.
2021-06-10 09:23:54 +01:00
Nicholas Marriott
d8feffd2bf Feature for the mouse since FreeBSD termcap does not have kmous. 2021-06-10 09:23:48 +01:00
Nicholas Marriott
f48c46a76a Fix rectangle selection, from Anindya Mukherjee, GitHub issue 2709. 2021-06-10 09:23:43 +01:00
Nicholas Marriott
f06ee2b87b Bump FORMAT_LOOOP_LIMIT and add a log message when hit, GitHub issue 2715. 2021-06-10 09:23:34 +01:00
Nicholas Marriott
9b4c05b6b9 Er, fix it properly. 2021-06-10 09:23:30 +01:00
Nicholas Marriott
3b9b823df5 Fix <= operator. 2021-06-10 09:23:25 +01:00
Nicholas Marriott
8aa34f616f Do not use NULL client when source-file finishes, GitHub issue 2707. 2021-06-10 09:23:15 +01:00
Nicholas Marriott
5ea6ccbb7f Do not expand the file given with -f so it can contain :s. 2021-06-10 09:23:07 +01:00
Nicholas Marriott
434ac8734a Looks like evports on SunOS are broken also, disable them. GitHub issue 2702. 2021-06-10 09:23:03 +01:00
Nicholas Marriott
47af583a50 Remove old shift function keys which interfere with xterm keys now. GitHub
issue 2696.
2021-06-10 09:22:51 +01:00
Nicholas Marriott
aaf87abfb4 Fire check callback after cleaning up event so it does not get stuck, from
Jeongho Jang in GitHub issue 2695.
2021-06-10 09:22:47 +01:00
Nicholas Marriott
bacb4d1b4d Fix warnings, from Jan Tache in GitHub issue 2692. 2021-06-10 09:22:39 +01:00
Nicholas Marriott
ad2f7642f2 Ctrl keys are < 0x7f, not Unicode. 2021-06-10 09:22:13 +01:00
Nicholas Marriott
059580e0f7 Move "special" keys into the Unicode PUA rather than making them high a top bit
set, some compilers cannot handle enums that are larger than int. GitHub issue
2673.
2021-06-10 09:22:07 +01:00
Nicholas Marriott
cb2943faab Change resize timers and flags into one timer and a queue to fix problems with
vim when resized multiple times. GitHub issue 2677.
2021-06-10 09:21:55 +01:00
Nicholas Marriott
7c28597e0f Mention S- for Shift, GitHub issue 2683. 2021-06-10 09:21:42 +01:00
Nicholas Marriott
fb52921a86 Do not count client if no window. 2021-06-10 09:21:34 +01:00
Nicholas Marriott
ddc67152a5 Three changes to fix problems with xterm in VT340 mode, reported by Thomas
Sattler.

1) Do not include the DECSLRM or DECFRA features for xterm; they will be added
   instead if secondary DA responds as VT420 (this happens already).

2) Set or reset the individual flags after terminal-overrides is applied, so
   the user can properly disable them.

3) Add a capability for DECFRA ("Rect").
2021-06-10 09:21:26 +01:00
Nicholas Marriott
4cf595a402 Include current client in size calcultion for new sessions, GitHub issue 2662. 2021-06-10 09:21:16 +01:00
Nicholas Marriott
5107e84897 Add an "always" value to the extended-keys option to always forward these keys
to applications inside tmux.
2021-06-10 09:21:09 +01:00
Nicholas Marriott
736a276cc9 Minor CHANGES and tmux.1 fixed, from Daniel Hahler, GitHub issue 2664. 2021-06-10 09:21:05 +01:00
Nicholas Marriott
825feac9f8 Add another couple of keys needed for extended keys, GitHub issue 2658. 2021-06-10 09:20:56 +01:00
Nicholas Marriott
d8c0069254 Use = not ==, from Leonardo Taccari. 2021-06-10 09:20:51 +01:00
Nicholas Marriott
33d4f854c0 back-to-indentation fixes, from Anindya Mukherjee. 2021-06-10 09:20:42 +01:00
Nicholas Marriott
9865ad27a5 Fix display-menu -xR, from Alexis Hildebrandt. 2021-06-10 09:20:33 +01:00
Nicholas Marriott
16b497e12b Apple have broken strtonum so check it works, from Teubel Gyorgy. 2021-06-10 09:20:28 +01:00
Nicholas Marriott
a25af7d0f3 Adjust latest client when a client detaches, GitHub issue 2657. 2021-06-10 09:20:22 +01:00
Nicholas Marriott
a11aa870b3 Handle modifier 9 as Meta, GitHub issue 2647. 2021-06-10 09:20:15 +01:00
Nicholas Marriott
0431d4d639 Add crosscompiling fallbacks, from Hasso Tepper. 2021-06-10 09:20:07 +01:00
nicm
d863978464 %begin now has three arguments, not two. GitHubs issue 2646. 2021-06-10 09:20:02 +01:00
nicm
57d5f67552 Include modifiers when looking up an individual key. 2021-06-10 09:19:56 +01:00
nicm
bab7a9a085 Change how extended ctrl keys are processed to fix C-S-Tab and C-;. 2021-06-10 09:19:49 +01:00
Nicholas Marriott
2ab53d30d0 3.2a version. 2021-06-10 09:17:46 +01:00
nicm
bc4681c83d Move mode set/reset after sync so cursor doesn't flicker, from Avi
Halachmi.
2021-04-13 08:37:57 +01:00
nicm
f29d3c7f74 Handle C-Tab correctly with extended keys, GitHub issue 2642. 2021-04-13 08:37:57 +01:00
Nicholas Marriott
30cf20d615 Update CHANGES. 2021-04-13 06:28:16 +01:00
Nicholas Marriott
c2048c5c65 Merge branch 'master' into 3.2-rc 2021-04-13 06:25:59 +01:00
Thomas Adam
bedf2bd437 Merge branch 'obsd-master' into master 2021-04-12 12:01:32 +01:00
nicm
e6abe55134 Add a flag to disable keys to close a message, GitHub issue 2625. 2021-04-12 09:36:12 +00:00
Thomas Adam
83cd593b9c Merge branch 'obsd-master' into master 2021-04-12 10:01:27 +01:00
nicm
cd208c9d72 Permit shortcut keys in buffer, client, tree modes to be configured with
a format; the default remains the line number. GitHub issue 2636.
2021-04-12 06:50:25 +00:00
Thomas Adam
7579097db6 Merge branch 'obsd-master' into master 2021-04-09 10:01:19 +01:00
nicm
73cbe46f8d Change a type to fix a warning with some compilers. 2021-04-09 07:02:00 +00:00
Thomas Adam
caf7aeb3a9 Merge branch 'obsd-master' into master 2021-04-08 16:01:17 +01:00
nicm
30fb628388 Log the key written to the terminal as well as tmux's idea of what it
is.
2021-04-08 14:16:12 +00:00
Thomas Adam
a57c2bf97e Merge branch 'obsd-master' into master 2021-04-07 18:01:20 +01:00
nicm
efb5e58c38 Restore previous behaviour so that C-X remains the same as C-x. Instead,
translate incoming extended keys so that they are consistent.
2021-04-07 15:46:12 +00:00
Thomas Adam
3cd63cc9e0 Merge branch 'obsd-master' into master 2021-04-07 16:01:21 +01:00
nicm
71fc9f3ee8 Add a current_file format for the config file being parsed. Originally
suggested by kn@, also GitHub issue 2638.
2021-04-07 12:50:12 +00:00
nicm
1ac47400d2 When display-message used in config file, show the message after the
config file finishes. GitHub issue 2637.
2021-04-07 12:49:33 +00:00
Thomas Adam
998a6b0aea Merge branch 'obsd-master' into master 2021-04-07 10:01:19 +01:00
nicm
ba99996676 Fixes for extended keys: 1) allow C-x and C-X to be bound separately
since some terminals report them differently 2) use the "backspace"
option to translate backspace 3) map ctrl which are have the ctrl
implied (such as C-x) properly when the terminal reports both the key
and the modifier.

Note that any key bindings for C-X where C-x is meant must now be
changed.
2021-04-07 07:30:02 +00:00
Thomas Adam
db97bef60b Merge branch 'obsd-master' into master 2021-04-05 16:01:23 +01:00
nicm
10470cea67 Move client-detached into server_client_lost so it is fired even if a
client is closed unexpectedly.
2021-04-05 14:11:05 +00:00
Thomas Adam
22ccae1c9d Merge branch 'obsd-master' into master 2021-04-05 10:01:19 +01:00
nicm
5900b164a4 Fix a couple of edge cases with the jump-back-xxx commands, and also
update back-to-indentation to use grid_reader, thereby fixing line
wrapping issues. From Anindya Mukherjee, GitHub issue 2633.
2021-04-05 08:43:48 +00:00
Thomas Adam
b307fc8cd5 Merge branch 'obsd-master' into master 2021-04-01 12:01:25 +01:00
nicm
28cd956729 Change search-again with vi keys to work like actual vi(1), also some
other fixes. From Aaron Jensen with help from Anindya Mukherjee.
2021-04-01 06:46:12 +00:00
nicm
6c98f222e9 Missing commas, from Vipul Kumar. 2021-04-01 06:37:46 +00:00
Thomas Adam
8f5ff4bf66 Merge branch 'obsd-master' into master 2021-03-31 10:01:16 +01:00
nicm
a4b9b5a1e5 Do not exit if cannot write to normal log file, GitHub issue 2630. 2021-03-31 08:37:48 +00:00
Nicholas Marriott
4208641de7 Remove queue.h, from Simon Holesch. 2021-03-28 10:16:17 +01:00
Thomas Adam
be568ea3b2 Merge branch 'obsd-master' into master 2021-03-16 10:01:20 +00:00
nicm
8b800b41c9 Add client-detached notification in control mode, from Mohsin Kaleem. 2021-03-16 09:14:58 +00:00
Thomas Adam
60bb8fa86d Merge branch 'obsd-master' into master 2021-03-15 14:01:17 +00:00
nicm
9017af2355 Do not crash if there is no item to show command error, from Anindya
Mukherjee.
2021-03-15 13:06:33 +00:00
Thomas Adam
7019937b52 Merge branch 'obsd-master' into master 2021-03-12 10:01:18 +00:00
nicm
e8224fb0d1 Fix so tmux correctly sends the cvvis (cursor very visible) capability
rather than sending it and then immediately undoing it with cnorm. Also
turn it off when the cursor shape is changed like xterm.
2021-03-12 08:39:17 +00:00
Nicholas Marriott
46cbbe3d45 Merge branch 'master' into 3.2-rc 2021-03-11 08:41:19 +00:00
Nicholas Marriott
ef9700816f malloc_trim is itself very poor and gets slower and slower as the heap becomes
more fragmented. Run it only once an hour. GitHub issue 2551.
2021-03-11 08:39:41 +00:00
Thomas Adam
12cfd0d22b Merge branch 'obsd-master' into master 2021-03-11 08:01:29 +00:00
nicm
ee0df1b8f8 Tidy old jobs every hour instead of every 30 seconds. 2021-03-11 07:08:18 +00:00
nicm
3eb91efba1 Add an "absolute-centre" alignment to use the centre of the total space
instead of only the available space. From Magnus Gross in GitHub issue 2578.
2021-03-11 06:41:04 +00:00
nicm
d98f9f7fe5 Add split-window -Z to start the pane zoomed, GitHub issue 2591. 2021-03-11 06:31:05 +00:00
Thomas Adam
541872bc57 Merge branch 'obsd-master' into master 2021-03-09 14:01:24 +00:00
nicm
7f87280cd5 Allow cursor to be just after match if copying, GitHub issue 2602. 2021-03-09 13:07:50 +00:00
Thomas Adam
ff77658f27 Merge branch 'obsd-master' into master 2021-03-09 10:01:19 +00:00
nicm
81e5736510 Copy mode improvements from Anindya Mukherjee:
- Fix word and word-end for wrapped lines.
- Fix copying of selection end on wrapped lines.
- Fix wrapped word selection edge case.
- Update select-line to respect wrapped lines.
- Update window_copy_..._pos() functions to use grid_reader.

GitHub issue 2605.
2021-03-09 08:24:09 +00:00
Nicholas Marriott
7bef887fd1 Update version. 2021-03-08 08:59:58 +00:00
Nicholas Marriott
8995d571d8 Merge branch 'master' into 3.2-rc 2021-03-08 08:59:40 +00:00
Nicholas Marriott
0792b65863 Remove compat.h again. 2021-03-08 08:59:13 +00:00
Nicholas Marriott
de4ac37baa 3.3. 2021-03-02 12:37:52 +00:00
Nicholas Marriott
b243f1b2ee No sys/queue.h. 2021-03-02 12:37:23 +00:00
Nicholas Marriott
d06c7197d4 Merge branch 'master' into 3.2-rc 2021-03-02 12:10:14 +00:00
Nicholas Marriott
fb039d5b82 paths.h is compat. 2021-03-02 12:09:59 +00:00
Nicholas Marriott
c01251d023 Merge branch 'master' into 3.2-rc 2021-03-02 12:08:34 +00:00
Nicholas Marriott
1466b570ee Update CHANGES. 2021-03-02 12:05:41 +00:00
Thomas Adam
2301bee87d Merge branch 'obsd-master' into master 2021-03-02 12:01:25 +00:00
nicm
81f9a23d25 Do not use NULL active window; also do not leak window name. GitHub
issue 2590 from Chester Liu.
2021-03-02 11:00:38 +00:00
nicm
c44750792a Drop support for popups where the content is provided directly to tmux
(which does not have many practical uses) and only support running a
program in the popup. display-popup is now simpler and can accept
multiple arguments to avoid escaping problems (like the other commands).
2021-03-02 10:56:45 +00:00
Thomas Adam
48131c6d02 Merge branch 'obsd-master' into master 2021-03-01 20:01:20 +00:00
Thomas Adam
9d99dad9e8 Merge branch 'obsd-master' into master 2021-03-01 17:54:47 +00:00
jmc
de3a898e8a escape quotes and remove some unneccessary Pp; ok nicm 2021-03-01 17:49:08 +00:00
Nicholas Marriott
9cd45ddad3 Reinstate del_curterm ifdef bits. 2021-03-01 10:51:24 +00:00
nicm
8a4a2153fd There is no need to call del_curterm in the server anymore. 2021-03-01 10:50:14 +00:00
nicm
b6dfb9996a Add some text with examples of ; as a separator, GitHub issues 2522 and
2580.
2021-03-01 10:44:38 +00:00
Thomas Adam
ba9f89c44e Merge branch 'obsd-master' into master 2021-02-27 08:01:20 +00:00
nicm
40ad11b2b5 Handle NULL term_type. 2021-02-27 06:28:16 +00:00
Thomas Adam
a7d4703bfe Merge branch 'obsd-master' into master 2021-02-27 00:01:19 +00:00
nicm
583aaebc0a Check session, window, pane in the right order when working out format type. 2021-02-26 21:53:41 +00:00
Thomas Adam
9c6502fcc9 Merge branch 'obsd-master' into master 2021-02-26 10:01:22 +00:00
nicm
dd7006c850 Add a couple of format variables for active and last window index. 2021-02-26 07:53:26 +00:00
Thomas Adam
9710ec5244 Merge branch 'obsd-master' into master 2021-02-24 10:01:19 +00:00
nicm
6aaef3e705 Correct client_prefix so it returns 1 if in prefix, not 0. 2021-02-24 09:22:15 +00:00
Thomas Adam
0982a1a975 Merge branch 'obsd-master' into master 2021-02-22 12:01:18 +00:00
nicm
6d8efe9319 expand_paths needs the global environment to be set up, do that first. 2021-02-22 11:42:50 +00:00
Thomas Adam
0cd5ed9e9b Merge branch 'obsd-master' into master 2021-02-22 10:01:22 +00:00
nicm
5f425ee318 Fix regex searching with wrapped lines, from Anindya Mukherjee; GitHub
issue 2570.
2021-02-22 08:31:19 +00:00
nicm
6876381276 Move config file path expansion much earlier, keep the list of paths
around rather than freeing later, and add a config_files format variable
containing it. Suggested by kn@ a while back.
2021-02-22 08:18:13 +00:00
Thomas Adam
cb7e6698f3 Merge branch 'obsd-master' into master 2021-02-22 08:01:22 +00:00
nicm
e858270006 There are many format variables now so allocating all the default ones
each time a tree is created is too expensive. Instead, convert them all
into callbacks and put them in a static table so they only allocate on
demand. The tree remains for the moment for extra (non-default)
variables added by for example copy mode or popups. Also reduce
expensive calls to localtime_r/strftime. GitHub issue 2253.
2021-02-22 07:09:06 +00:00
nicm
8986c8dfcd Move jump commands to grid reader, make them UTF-8 aware, and tidy up,
from Anindya Mukherjee.
2021-02-22 06:53:04 +00:00
Thomas Adam
742e670805 Merge branch 'obsd-master' into master 2021-02-19 10:01:19 +00:00
nicm
b04f8acb70 Check return value of chdir() to stop a silly warning with some
compilers, GitHub issue 2573.
2021-02-19 09:09:16 +00:00
Thomas Adam
11e404ca3c Merge branch 'obsd-master' into master 2021-02-18 16:01:18 +00:00
nicm
fb42ae3071 Reduce len when moving past spaces in OSC 11 parameter. 2021-02-18 13:30:24 +00:00
Thomas Adam
3a76a56824 Merge branch 'obsd-master' into master 2021-02-17 09:58:51 +00:00
Thomas Adam
ce5de76592 Merge branch 'obsd-master' into master 2021-02-17 09:58:12 +00:00
nicm
af3ffa9c41 Move the call to setupterm() into the client and have it pass the
results to the server over imsg, means the server does not need to enter
ncurses or read terminfo db. Old clients will not work with a new
server.
2021-02-17 07:18:36 +00:00
nicm
5c275c2a1a Log missing keys when extended keys is on rather than fatal(). 2021-02-16 09:41:55 +00:00
nicm
5df9b3650a In the end UTF-8 did not become a terminal feature, should not be listed
in man page.
2021-02-16 09:40:00 +00:00
nicm
d768fc2553 Make SGR 6 (rapid blink) the same as SGR 5 (blink) and make SGR 21 to
the same as SGR 4:2, it is an old alternative. GitHub issue 2567.
2021-02-15 14:22:35 +00:00
Nicholas Marriott
0526d074d0 OSC 11 test. 2021-02-15 09:40:50 +00:00
nicm
6642706f7b Support X11 colour names and some other variations for OSC 10/11, also
add OSC 110 and 111. GitHub issue 2567.
2021-02-15 09:39:37 +00:00
nicm
632636dba5 Do not care about the server socket closing if exiting anyway. 2021-02-12 06:52:48 +00:00
nicm
2b58c226db Add a couple of helper functions, and flush imsgs on exit. 2021-02-11 09:39:29 +00:00
nicm
79e1984962 O_TRUNC is needed in case file exists. 2021-02-11 09:03:38 +00:00
nicm
e40831a002 Move file handling protocol stuff all into file.c so it can be reused
more easily.
2021-02-11 08:28:45 +00:00
Nicholas Marriott
679b2288e8 Restore utf8proc bits that went missing, GitHub issue 2564. 2021-02-10 17:18:37 +00:00
Thomas Adam
5b6d4c4fd1 Merge branch 'obsd-master' into master 2021-02-10 08:01:20 +00:00
nicm
32186950f5 Use ~/.tmux.conf as an example rather than /etc/passwd, suggested by
deraadt@.
2021-02-10 07:17:07 +00:00
Thomas Adam
c6215b55e0 Merge branch 'obsd-master' into master 2021-02-09 16:01:18 +00:00
nicm
1492ae11a5 Do not expand times and #() inside #(). 2021-02-09 14:25:40 +00:00
Thomas Adam
8d7f341a85 Merge branch 'obsd-master' into master 2021-02-08 16:01:21 +00:00
nicm
e3005e5ec4 Add "pipe" variants of the "copy-pipe" commands which do not copy, from
Christian Zangl.
2021-02-08 14:46:53 +00:00
Thomas Adam
fe3ab51b78 Merge branch 'obsd-master' into master 2021-02-08 10:01:20 +00:00
nicm
c579be1f2a Include "focused" in client flags, from Dan Aloni in GitHub issue 2558. 2021-02-08 08:33:54 +00:00
Thomas Adam
03430887be Merge branch 'obsd-master' into master 2021-02-06 14:01:20 +00:00
nicm
1e29ebd412 In the end UTF-8 did not become a terminal feature, should not be listed
in man page.
2021-02-06 13:02:52 +00:00
Thomas Adam
39904f7fc6 Merge branch 'obsd-master' into master 2021-02-05 14:01:23 +00:00
nicm
3dddc11603 Send Unicode directional isolate characters around horizontal pane
borders if the terminal support UTF-8 and an extension terminfo(5)
capability "Bidi" is present. On terminals with BiDi support (ie, VTE)
this seems to be enough to display right-to-left text acceptably enough
to be usable (with some caveats about the mouse position). Requested by
and with help from Mahmoud Elagdar in GitHub issue 2425.
2021-02-05 12:29:18 +00:00
nicm
be471c328e Add a -S flag to new-window to make it select the existing window if one
with the given name already exists rather than failing with an error.
Also add a format to check if a window or session name exists which
allows the same with other commands. Requested by and discussed with
kn@.
2021-02-05 12:23:49 +00:00
Nicholas Marriott
e3d71d9bdf Add compat clock_gettime for older macOS. GitHub issue 2555. 2021-02-05 11:01:21 +00:00
Thomas Adam
3dd2e85075 Merge branch 'obsd-master' into master 2021-02-04 16:01:18 +00:00
nicm
c13f2e1135 Redraw status line and borders on pane enable/disable, GitHub issue 2554. 2021-02-04 14:02:24 +00:00
Thomas Adam
86955dbfe1 Merge branch 'obsd-master' into master 2021-02-02 14:01:19 +00:00
nicm
f0546b0ff8 Fix popup mouse position. 2021-02-02 13:03:03 +00:00
Thomas Adam
a5d69ab4b0 Merge branch 'obsd-master' into master 2021-02-02 08:01:19 +00:00
jmc
5c48086e5c article fixes; from eddie youseph 2021-02-02 07:33:29 +00:00
Thomas Adam
0242513ce7 Merge branch 'obsd-master' into master 2021-02-01 10:01:20 +00:00
nicm
509221520c Add a no-detached choice to detach-on-destroy which detaches only if
there are no other detached sessions to switch to, from Sencer Selcuk in
GitHub issue 2553.
2021-02-01 08:01:14 +00:00
Thomas Adam
545a610c6b Merge branch 'obsd-master' into master 2021-01-29 12:01:21 +00:00
nicm
255802d8d7 Trim output overwritten by later text or clears completely rather than
only in a few cases. This means we can better track when a line should
wrap. GitHub issue 2537.
2021-01-29 09:48:43 +00:00
Thomas Adam
ffc159a456 Merge branch 'obsd-master' into master 2021-01-27 12:01:21 +00:00
nicm
8156d9ba41 Flush pending output before entering or exiting alternate screen rather
than leaking it, oss-fuzz issue 29959.
2021-01-27 10:42:52 +00:00
Thomas Adam
70a6af6287 Merge branch 'obsd-master' into master 2021-01-26 10:01:18 +00:00
nicm
d6542c333d Always resize the original screen before copying when exiting the
alternate screen, GitHub issue 2536.
2021-01-26 09:32:52 +00:00
Thomas Adam
3b51abcf22 Merge branch 'obsd-master' into master 2021-01-22 14:01:18 +00:00
Thomas Adam
0898a868c6 Merge branch 'obsd-master' into master 2021-01-22 12:01:21 +00:00
nicm
9fcf413d87 Revert clear changes to writing as they don't work properly, better
change to come.
2021-01-22 11:28:33 +00:00
nicm
bba71f696f Add rectangle-on and rectangle-off copy mode commands, GitHub isse 2546
from author at will dot party.
2021-01-22 10:24:52 +00:00
nicm
8d185395e4 Fix some cursor movement commands, from Anindya Mukherjee. 2021-01-22 10:21:24 +00:00
Thomas Adam
9ff017e908 Merge branch 'obsd-master' into master 2021-01-20 08:01:22 +00:00
nicm
fb774b77d0 Change so that window_flags escapes # automatically which means configs
will not have to change. A new format window_raw_flags contains the old
unescaped version.
2021-01-20 07:16:54 +00:00
Thomas Adam
82423975df Merge branch 'obsd-master' into master 2021-01-18 14:01:21 +00:00
Thomas Adam
66da51b631 Merge branch 'obsd-master' into master 2021-01-18 12:01:22 +00:00
Nicholas Marriott
3c86fa2ad0 Add -Wno-format-y2k. 2021-01-18 11:14:37 +00:00
nicm
0730dce5ab Hide some warnings on newer GCC versions, GitHUb issue 2525. 2021-01-18 11:14:23 +00:00
Nicholas Marriott
63f4a3c4e5 Extra result message. 2021-01-18 10:48:49 +00:00
nicm
91d112bf12 There is no need to clear every line entirely before drawing to it, this
means moving the cursor and messes up wrapping. Better to just clear the
sections that aren't written over. GitHub issue 2537.
2021-01-18 10:27:54 +00:00
Nicholas Marriott
4148417a2a PKG_CHECK_MODULES needs to be separate. 2021-01-17 19:03:18 +00:00
Nicholas Marriott
607594f6e5 Show config.log on failure. 2021-01-17 18:47:14 +00:00
Nicholas Marriott
b18834be8a Revert "Set CFLAGS also."
This reverts commit 032723c874.
2021-01-17 18:24:52 +00:00
Nicholas Marriott
032723c874 Set CFLAGS also. 2021-01-17 18:21:54 +00:00
Nicholas Marriott
c6bcf3dba5 Fix yes/no for b64_ntop check. 2021-01-17 18:20:15 +00:00
Thomas Adam
24c15eda79 Merge branch 'obsd-master' into master 2021-01-17 18:01:21 +00:00
Nicholas Marriott
d4866d5fe6 Fix SEARCH_LIBS. 2021-01-17 17:55:14 +00:00
Nicholas Marriott
603280cb28 +compat.h 2021-01-17 17:52:10 +00:00
Nicholas Marriott
a3011be0d2 Look for libevent2 differently from libevent for platforms with both. 2021-01-17 17:21:51 +00:00
nicm
71c590a37f Add -N flag to never start server even if command would normally do so,
GitHub issue 2523.
2021-01-17 16:17:41 +00:00
Thomas Adam
dc1e1125a5 Merge branch 'obsd-master' into master 2021-01-08 12:01:21 +00:00
nicm
a75aca4d6a Missed from last commit. 2021-01-08 10:09:44 +00:00
Thomas Adam
9df33bc536 Merge branch 'obsd-master' into master 2021-01-08 10:01:20 +00:00
nicm
b96c5e3687 With incremental search, start empty and only repeat the previous search
if the user tries to search again with an empty prompt. This matches
emacs behaviour more closely.
2021-01-08 08:22:10 +00:00
Thomas Adam
fc28e2065a Merge branch 'obsd-master' into master 2021-01-06 10:01:22 +00:00
nicm
199689954b Insert joined pane before the target pane with -b, like for split. From
Takeshi Banse.
2021-01-06 07:32:23 +00:00
nicm
ccb8b9eb2a Remove unused variable, from Ben Boeckel. 2021-01-06 07:29:49 +00:00
Thomas Adam
5a2db4c7e8 Merge branch 'obsd-master' into master 2021-01-04 10:01:20 +00:00
nicm
bd0fb22f0a Add a variant of remain-on-exit that only keeps the pane if the program
failed, GitHub issue 2513.
2021-01-04 08:43:16 +00:00
Thomas Adam
f04cc39976 Merge branch 'obsd-master' into master 2021-01-01 10:01:21 +00:00
nicm
606bd5f8c6 Add a -C flag to run-shell to use a tmux command rather than a shell command. 2021-01-01 08:36:51 +00:00
Thomas Adam
f72deb092a Merge branch 'obsd-master' into master 2020-12-30 22:01:23 +00:00
nicm
f97305af31 Use right format for session loop, GitHub issue 2519. 2020-12-30 18:29:40 +00:00
Thomas Adam
3cbe186efb Merge branch 'obsd-master' into master 2020-12-28 12:01:21 +00:00
nicm
a98ee00dd9 Do not list user options with show-hooks. 2020-12-28 09:40:27 +00:00
nicm
c68baaad98 Remove current match indicator which can't work anymore since we only
search the visible region. From Anindya Mukherjee, GitHub issue 2508.
2020-12-28 09:36:26 +00:00
Thomas Adam
d936fde7ef Makefile.am: add grid-reader.c
Add grid-reader.c to Makefile.am so it's included for compilation.
2020-12-24 22:22:10 +00:00
Thomas Adam
70a0eb3a22 Merge branch 'obsd-master' into master 2020-12-24 22:21:21 +00:00
nicm
c43f2dce1b Break cursor movement in grid into a common set of functions that can
handle line wrapping and so on in one place and use them for the obvious
copy mode commands. From Anindya Mukherjee.
2020-12-22 09:22:14 +00:00
Thomas Adam
950e982001 Merge branch 'obsd-master' into master 2020-12-15 10:01:22 +00:00
nicm
8bd29a30bf Make synchronize-panes a pane option and add -U flag to set-option to
unset an option on all panes. GitHub issue 2491 from Rostislav Nesin.
2020-12-15 08:31:50 +00:00
Nicholas Marriott
681c0d2bfb Include compat.h after system headers, GitHub issue 2492. 2020-12-07 12:13:20 +00:00
Thomas Adam
caf096394b Merge branch 'obsd-master' into master 2020-12-07 10:01:20 +00:00
nicm
f6095cad99 Do not include the status line size when working out the character for
the pane status line. GitHub issue 2493.
2020-12-07 09:46:58 +00:00
nicm
ed786309cc Do not clear the wrapped flag on linefeeds if it is already set - this
does not appear to be what applications want. GitHub issue 2478 and 2414.
2020-12-07 09:23:57 +00:00
Thomas Adam
e288ea153c Merge branch 'obsd-master' into master 2020-12-03 08:01:22 +00:00
nicm
fd451aa796 Redraw any visible modes when status line changes so that formats like
the pane title are updated. GitHub issue 2487. Also a man page fix from
jmc.
2020-12-03 07:12:11 +00:00
Thomas Adam
4724702d4e Merge branch 'obsd-master' into master 2020-12-01 12:01:20 +00:00
nicm
f0c1233d4f Leave newlines inside multiline quotes. 2020-12-01 10:48:03 +00:00
Thomas Adam
27634645e9 Merge branch 'obsd-master' into master 2020-12-01 10:01:22 +00:00
nicm
9a74bba007 Make replacement of ##s consistent when drawing formats, whether
followed by [ or not. Add a flag (e) to the q: format modifier to double
up #s and use it for the window_flags format variable so it doesn't end
up escaping any following text. GitHub issue 2485.
2020-12-01 08:12:58 +00:00
Thomas Adam
70a5207bd1 Merge branch 'obsd-master' into master 2020-11-30 16:01:22 +00:00
nicm
33046ecee2 Ignore running command when checking for no-hooks flag if it is blocked.
GitHub issue 2483.
2020-11-30 13:37:45 +00:00
Thomas Adam
bf8aa9804b Merge branch 'obsd-master' into master 2020-11-26 14:01:19 +00:00
nicm
fd5c3e6122 Fix check for vertical centre. 2020-11-26 13:06:21 +00:00
Thomas Adam
82fbff4e08 Merge branch 'obsd-master' into master 2020-11-26 10:01:21 +00:00
nicm
76cfb5f471 Add -N flag to display-panes to ignore keys, GitHub issue 2473. 2020-11-26 09:19:10 +00:00
Nicholas Marriott
2f1578ef83 Update closefrom from OpenSSH for macOS code which is now needed. 2020-11-20 09:05:32 +00:00
Nicholas Marriott
bfdc4373d7 Update closefrom from OpenSSH for macOS code which is now needed. 2020-11-17 17:57:21 +00:00
Thomas Adam
3ee1addbb9 Merge branch 'obsd-master' into master 2020-11-17 10:01:22 +00:00
nicm
0d28ee9274 Log missing keys when extended keys is on rather than fatal(). 2020-11-17 08:13:35 +00:00
Thomas Adam
e94bd5ccff Merge branch 'obsd-master' 2020-11-10 10:01:22 +00:00
nicm
bbab5b7a30 Allow previous-word to scroll onto the first line, noticed by Anindya
Mukherjee.
2020-11-10 08:16:52 +00:00
Nicholas Marriott
3eb1519bd7 Scaffold for oss-fuzz, from Sergey Nizovtsev. 2020-11-09 16:44:39 +00:00
Thomas Adam
0dcb6e5eb4 Merge branch 'obsd-master' 2020-11-09 12:01:21 +00:00
nicm
f1193b4891 If mouse bits change, clear them all and set again to avoid problems
with some bits implying others. GitHub issue 2458.
2020-11-09 10:54:28 +00:00
Thomas Adam
5ddbf0c918 Merge branch 'obsd-master' 2020-11-09 10:01:27 +00:00
nicm
61e55fa50d Change how escaping is processed for formats so that ## and # can be
used in styles. Also add a 'w' format modifier for the width. From Chas
J Owens IV in GitHub issue 2389.
2020-11-09 09:10:10 +00:00
Nicholas Marriott
72c46aa15e Add support for Haiku, from David Carlier. GitHub issue 2453. 2020-11-09 09:00:41 +00:00
nicm
1326529f99 Remove some old debug logging. 2020-11-09 08:42:43 +00:00
Thomas Adam
dac285c92a Merge branch 'obsd-master' 2020-11-03 10:01:21 +00:00
Nicholas Marriott
572a6b21b5 Back to 3.3. 2020-11-03 08:41:24 +00:00
Nicholas Marriott
5306bb0db7 Update to 3.2-rc3, bring in all the changes from master. 2020-11-03 08:37:08 +00:00
Nicholas Marriott
ba9962b568 Merge branch 'master' into 3.2-rc 2020-11-03 08:35:52 +00:00
nicm
9d83c5e948 Expand menu and popup -x and -y as a format, from teo_paul1 at yahoo dot
com in GitHub issue 2442.
2020-11-03 08:09:35 +00:00
Thomas Adam
ff53eed402 Merge branch 'obsd-master' 2020-11-02 10:01:20 +00:00
nicm
ac5045a00f Add numeric comparisons for formats, from teo_paul1 at yahoo dot com in
GitHub issue 2442.
2020-11-02 08:21:30 +00:00
Thomas Adam
ffe39edf2f Merge branch 'obsd-master' 2020-10-30 20:01:20 +00:00
nicm
95841ba16a With csh, a tmux client gets SIGTERM before SIGCONT when killed with
"kill %%", so when the client tells the server it got SIGCONT, don't use
bits that may already have been freed when it got SIGTERM. Also don't
print anything on exit if we get SIGTERM while suspended. Reported by
Theo.
2020-10-30 18:54:23 +00:00
Thomas Adam
d064060904 Merge branch 'obsd-master' 2020-10-30 14:01:20 +00:00
Nicholas Marriott
0b8ae4de5c Update CHANGES. 2020-10-30 12:29:40 +00:00
nicm
9726c4454e Do not allow disabled items to be selected. 2020-10-30 12:00:01 +00:00
nicm
8e1d28453d Limit range of repeat to avoid silly high numbers causing delays, from
Sergey Nizovtsev.
2020-10-30 11:34:13 +00:00
nicm
02197f20d0 Do not leak path when freeing screen, from Sergey Nizovtsev. 2020-10-30 11:33:41 +00:00
Thomas Adam
970e8f734c Merge branch 'obsd-master' 2020-10-30 10:01:22 +00:00
Nicholas Marriott
ce2b6ff40e Style trim test (currently failing). 2020-10-30 09:25:41 +00:00
nicm
910457f68d There is no reason not to fire focus events when a pane is in a mode,
GitHub issue 2372.
2020-10-30 09:00:07 +00:00
nicm
649e5970e9 Add a -O flag to display-menu to change the mouse behaviour and not
close the menu when the mouse is released, from teo_paul1 at yahoo dot
com.
2020-10-30 08:55:56 +00:00
nicm
733abfcfc5 Do not write after the end of the array and overwrite the stack when
colon-separated SGR sequences contain empty arguments. Reported by Sergey
Nizovtsev.
2020-10-30 08:17:38 +00:00
Thomas Adam
7f321a4cc6 Merge branch 'obsd-master' 2020-10-29 18:01:21 +00:00
nicm
a868bacb46 Do not write after the end of the array and overwrite the stack when
colon-separated SGR sequences contain empty arguments. Reported by Sergey
Nizovtsev.
2020-10-29 16:33:01 +00:00
nicm
7a4aa14618 Do not require that there be no other clients before loading the config,
being the first client is enough. GitHub issue 2438.
2020-10-29 14:10:24 +00:00
Thomas Adam
d5fac75667 Merge branch 'obsd-master' 2020-10-29 14:05:21 +00:00
nicm
977cf3cf69 Set RGB flag if capabilities are present, GitHub issue 2418. 2020-10-29 13:48:03 +00:00
nicm
07ffed8b6f Fix note for "previous-window" default key binding, from Sebastian
Falbesoner.
2020-10-29 13:47:50 +00:00
nicm
7ffb414299 Client could be NULL in select-window (for example in .tmux.conf), do
not set latest session if so. GitHub issue 2429 from Han Boetes.
2020-10-29 13:47:40 +00:00
nicm
3c298b98ce SIGQUIT handler needs to be cleared before fork like the others,
reported by Simon Andersson.
2020-10-29 13:47:24 +00:00
nicm
b33a302235 Do not require that there be no other clients before loading the config,
being the first client is enough. GitHub issue 2438.
2020-10-28 10:09:10 +00:00
Thomas Adam
20e89605c9 Merge branch 'obsd-master' 2020-10-26 20:01:18 +00:00
nicm
31ed29e551 SIGQUIT handler needs to be cleared before fork like the others,
reported by Simon Andersson.
2020-10-26 19:00:37 +00:00
Thomas Adam
9a5b2c93a7 Merge branch 'obsd-master' 2020-10-19 10:01:18 +01:00
nicm
d8cda9286f Client could be NULL in select-window (for example in .tmux.conf), do
not set latest session if so. GitHub issue 2429 from Han Boetes.
2020-10-19 06:39:28 +00:00
Thomas Adam
6125800876 Merge branch 'obsd-master' 2020-10-13 12:01:20 +01:00
nicm
4c8706d399 Fix note for "previous-window" default key binding, from Sebastian
Falbesoner.
2020-10-13 10:15:23 +00:00
Thomas Adam
9ab81e1879 Merge branch 'obsd-master' 2020-10-13 10:01:19 +01:00
nicm
d603dbdef0 Set RGB flag if capabilities are present, GitHub issue 2418. 2020-10-13 07:29:24 +00:00
Thomas Adam
30601d11a8 Merge branch 'obsd-master' 2020-10-09 22:01:22 +01:00
tim
4dc76e084b Escape ! in Ql
OK jmc@ nicm@, agreement from schwarze@
2020-10-09 19:12:36 +00:00
Thomas Adam
7ca0b9ddfa Merge branch 'obsd-master' 2020-10-07 10:01:19 +01:00
Nicholas Marriott
991d5a9c74 Add compat for getdtablesize, GitHub issue 2406. 2020-10-07 09:39:43 +01:00
nicm
3afcc6faac Allow fnmatch(3) wildcards in update-environment, GitHub issue 2397. 2020-10-07 08:23:55 +00:00
Thomas Adam
57168f3f59 Merge branch 'obsd-master' 2020-10-06 10:01:20 +01:00
nicm
7e319756d2 Fix a last minute change in previous. 2020-10-06 07:36:42 +00:00
nicm
e369f64669 Add a state struct to store working state during format expansion
instead of modiyfing the format tree.

Use this to disable nested job expansion so that the result of #() is
not expanded again. Reported by Chas J Owens IV, GitHub issue 2390.
2020-10-06 07:36:05 +00:00
Nicholas Marriott
680e7a382f glibc's malloc is very bad about returning memory from the kernel, add a call
to its malloc_trim to prompt it to do so. Reported by Sarunas Valaskevicius.
2020-10-06 08:18:42 +01:00
Thomas Adam
847a061e31 Merge branch 'obsd-master' 2020-10-05 14:01:19 +01:00
nicm
8d9ea1b97c Trim "s from process names; also fix a default format in man page. 2020-10-05 11:04:40 +00:00
Thomas Adam
f5b7ebc540 Merge branch 'obsd-master' 2020-10-05 12:01:23 +01:00
nicm
1479e32e1a Tidy the resize code, merge some common bits and add some comments. From
"Mike" in GitHub issue 2392.
2020-10-05 10:00:51 +00:00
nicm
c8f3736b07 Use the setal capability as well as (tmux's) Setulc. 2020-10-05 09:53:01 +00:00
Nicholas Marriott
92a2e7411f Link to install wiki page. 2020-10-01 09:01:42 +01:00
Nicholas Marriott
9ec68db74f Correct break-pane default format, from Gregory Pakosz. 2020-09-30 14:17:27 +01:00
Nicholas Marriott
f43e3e5b4f Next version. 2020-09-30 13:36:58 +01:00
Nicholas Marriott
86433c6fb5 Merge tag '3.2-rc' into master
3.2-rc
2020-09-30 13:36:26 +01:00
Nicholas Marriott
cf8ef63c4a Fix some warnings, GitHub issue 2382. 2020-09-30 13:35:51 +01:00
nicm
ec9e03d09a Old Terminal.app versions do not respond correctly to secondary DA,
instead responding with the primary DA response. Ignore it. Reported by
Dave Vandervies.
2020-09-30 13:33:02 +01:00
Nicholas Marriott
3bece648bd Trim "s from process names, from Gregory Pakosz. 2020-09-30 13:27:50 +01:00
nicm
68c2d5c48d Escape+Up and the other arrow keys should be kept as Escape+Up and not
converted to M-Up. Do not give them the implied meta flag so they don't
match the M-Up entry in the output key tree. Fixes problem with vi
reported by jsing@.
2020-09-30 13:27:43 +01:00
Nicholas Marriott
f70eda3817 Check if UNIX 03 is needed for CMSG_DATA, for newer Solaris. From Eric N Vander
Weele.
2020-09-30 13:27:35 +01:00
Nicholas Marriott
a880237141 Also pkg-config. 2020-09-30 13:27:25 +01:00
Nicholas Marriott
9d597390ca Mention build dependencies, based on a change from Mateusz Urbanek. 2020-09-30 13:27:21 +01:00
Nicholas Marriott
5f50e7d942 Trim "s from process names, from Gregory Pakosz. 2020-09-30 13:26:31 +01:00
Nicholas Marriott
4f638c0e31 Check if UNIX 03 is needed for CMSG_DATA, for newer Solaris. From Eric N Vander
Weele.
2020-09-25 10:04:52 +01:00
Nicholas Marriott
e2e5169f84 Also pkg-config. 2020-09-25 09:43:35 +01:00
Nicholas Marriott
ebf27f6900 Mention build dependencies, based on a change from Mateusz Urbanek. 2020-09-25 09:41:41 +01:00
Thomas Adam
476c185997 Merge branch 'obsd-master' 2020-09-23 18:01:17 +01:00
nicm
f2dfc2759e Escape+Up and the other arrow keys should be kept as Escape+Up and not
converted to M-Up. Do not give them the implied meta flag so they don't
match the M-Up entry in the output key tree. Fixes problem with vi
reported by jsing@.
2020-09-23 14:57:33 +00:00
Thomas Adam
dc0c3aa391 Merge branch 'obsd-master' 2020-09-22 18:01:18 +01:00
nicm
d6680b9474 Move a sentence to the right command. 2020-09-22 15:45:20 +00:00
Thomas Adam
859a4c3460 Merge branch 'obsd-master' 2020-09-22 10:01:17 +01:00
nicm
b9392d5cb1 Do not wrap at end of text when positioning at end of match because the
length may include trailing spaces.
2020-09-22 08:41:27 +00:00
Thomas Adam
a34ceb1074 Merge branch 'obsd-master' 2020-09-22 08:01:18 +01:00
nicm
51909a107f Resize screen to the correct size (borders need to be taken off). 2020-09-22 06:44:52 +00:00
nicm
86d6ac2f06 Fix warnings on some platforms with %llx and add a new message to handle
64-bit client flags.
2020-09-22 05:23:34 +00:00
Thomas Adam
ca5afb34bf Merge branch 'obsd-master' 2020-09-18 14:01:19 +01:00
nicm
88b66e9e28 Free buffer earlier to avoid confusing some compilers, GitHub issue
2382.
2020-09-18 11:23:29 +00:00
nicm
ed946dccc7 Some other warnings, GitHub issue 2382. 2020-09-18 11:20:59 +00:00
Thomas Adam
eea85fb4c7 Merge branch 'obsd-master' 2020-09-16 22:01:18 +01:00
nicm
3206869ea5 Add -q flag to unbind-key to hide errors, GitHub issue 2381. 2020-09-16 19:12:59 +00:00
Thomas Adam
c3e1b841f9 Merge branch 'obsd-master' 2020-09-16 20:01:19 +01:00
nicm
869c0e860f Fix some warnings, GitHub issue 2382. 2020-09-16 18:37:55 +00:00
Thomas Adam
3c1f34c208 Merge branch 'obsd-master' 2020-09-08 12:01:17 +01:00
nicm
1fed7e84a3 Allow -N without a command to change or add a note to an existing key. 2020-09-08 10:19:19 +00:00
Thomas Adam
634a2bb647 Merge branch 'obsd-master' 2020-09-04 14:01:18 +01:00
nicm
9b45ba82fd calloc cb data so the client is NULL. 2020-09-04 12:24:25 +00:00
Nicholas Marriott
233d14f4da Hide warnings due to Apple's stupidity with __dead, reported by Kurtis Rader. 2020-09-04 08:37:11 +01:00
Thomas Adam
2e931d4994 Merge branch 'obsd-master' 2020-09-03 14:01:18 +01:00
nicm
eadf18b9fa Do not free old session working directory until after expanding the new
one because it may be needed.
2020-09-03 12:47:33 +00:00
Thomas Adam
cbbf5febff Merge branch 'obsd-master' 2020-09-02 20:01:17 +01:00
nicm
e538bef757 Check started flag before looking for capability. 2020-09-02 17:19:58 +00:00
Thomas Adam
fc9ecdc665 Merge branch 'obsd-master' 2020-09-02 16:01:20 +01:00
nicm
37b1600d9c Add a -w flag to set- and load-buffer to send to clipboard using OSC 52.
GitHub issue 2363.
2020-09-02 13:46:35 +00:00
Thomas Adam
a0fee328bf Merge branch 'obsd-master' 2020-09-01 12:01:20 +01:00
nicm
60860aced8 Add -F to set-environment and source-file; GitHub issue 2359. 2020-09-01 09:19:01 +00:00
nicm
b2a262e353 Only print below number when there is enough space. 2020-09-01 08:50:14 +00:00
Thomas Adam
b895ffbf37 Merge branch 'obsd-master' 2020-08-27 10:01:20 +01:00
nicm
2ab289980a Add pane_last format, GitHub issue 2353. 2020-08-27 06:55:54 +00:00
Thomas Adam
655134f77c Merge branch 'obsd-master' 2020-08-25 14:01:19 +01:00
nicm
20fcdcfea1 Allow colour to be spelt as color, from Boris Verkhovsky. GitHub issue
2317.
2020-08-25 11:35:32 +00:00
Thomas Adam
aa084bb49e Merge branch 'obsd-master' 2020-08-24 08:01:17 +01:00
nicm
e4a4fcfc90 Old Terminal.app versions do not respond correctly to secondary DA,
instead responding with the primary DA response. Ignore it. Reported by
Dave Vandervies.
2020-08-24 05:23:30 +00:00
nicm
43e3e53908 Do not run off end of string when stripping delays, reported by Dave
Vandervies.
2020-08-24 05:22:28 +00:00
Thomas Adam
769ae10658 Merge branch 'obsd-master' 2020-08-20 20:01:19 +01:00
nicm
d0957529ed Add n: modifier to get length of a format, also automatically expand
variable name arguments again if they contain a #{.
2020-08-20 16:57:40 +00:00
Thomas Adam
5a55d1390a Merge branch 'obsd-master' 2020-08-19 10:01:19 +01:00
nicm
d8b6560cbf Set alert flag for the current window if the session is unattached.
GitHub issues 1182 and 2299. From Eric Garver.
2020-08-19 07:15:42 +00:00
nicm
f08bfa7cd1 Respond to colour requests if a colour is available, from Michal Goral. 2020-08-19 06:37:23 +00:00
Thomas Adam
93eb2c8c53 Merge branch 'obsd-master' 2020-08-07 10:01:19 +01:00
nicm
212c0c1f72 Do not force line width to grid width because it may need to be larger
to accomodate a wide character. GitHub issue 2336.
2020-08-07 07:02:57 +00:00
Thomas Adam
9f0973b711 Merge branch 'obsd-master' 2020-08-05 12:01:21 +01:00
nicm
df7fbcd7a5 Change searching to behave more like emacs and so that regex searching
doesn't overlap when searching forwards.
2020-08-05 09:11:09 +00:00
Thomas Adam
8d7e127b17 Merge branch 'obsd-master' 2020-08-04 12:01:18 +01:00
nicm
82c65e3f37 Also ignore SIGQUIT so it can't be used to kill the client when locked. 2020-08-04 08:50:01 +00:00
Thomas Adam
98aa835079 Merge branch 'obsd-master' 2020-07-30 10:01:18 +01:00
nicm
944177eec3 Trim newline from ctime, from Thomas Adam. 2020-07-30 07:32:52 +00:00
Thomas Adam
2fdd5fa507 Merge branch 'obsd-master' 2020-07-27 10:01:21 +01:00
nicm
40e65c5115 Add a -d option to display-message to set delay, from theonekeyg at
gmail dot com in GitHub issue 2322.
2020-07-27 08:03:10 +00:00
Thomas Adam
90158b5977 Merge branch 'obsd-master' 2020-07-24 10:01:19 +01:00
Nicholas Marriott
31bc4c4346 3.2-rc version. 2020-07-24 08:38:34 +01:00
nicm
d329b035ce Add a hook when the pane title changed. 2020-07-24 07:05:37 +00:00
Thomas Adam
1f19355fb0 Merge branch 'obsd-master' 2020-07-23 16:01:17 +01:00
nicm
112b0f417c Check all lists if option not found already. 2020-07-23 14:17:56 +00:00
Thomas Adam
e0d984597b Merge branch 'obsd-master' 2020-07-22 08:01:18 +01:00
nicm
1f5e520def Correct checks for window borders. 2020-07-22 06:21:46 +00:00
Thomas Adam
90de0c1a9b Merge branch 'obsd-master' 2020-07-21 08:01:19 +01:00
nicm
743ab5728d Fix show-buffer when run from inside tmux, GitHub issue 2314. 2020-07-21 05:24:33 +00:00
Thomas Adam
70a674dde1 Merge branch 'obsd-master' 2020-07-18 06:01:20 +01:00
daniel
3b089fc69f Properly escape a backslash.
Found by CompCert which notes that \E is not a valid escape sequence.

ok nicm@
2020-07-18 02:53:47 +00:00
Thomas Adam
ab8d685302 Merge branch 'obsd-master' 2020-07-15 14:01:18 +01:00
nicm
5e008eefaa Renumber after killing windows for choose-tree. 2020-07-15 11:03:17 +00:00
Thomas Adam
c973801f92 Merge branch 'obsd-master' 2020-07-15 12:01:19 +01:00
nicm
8f1179d656 Handle padding cells correctly when searching, GitHub issue 2301. 2020-07-15 10:09:54 +00:00
Thomas Adam
405b71e016 Merge branch 'obsd-master' 2020-07-13 12:01:17 +01:00
nicm
468be2a37f Do not dereference NULL environment variable value, GitHub issue 2304. 2020-07-13 10:10:10 +00:00
Thomas Adam
7d6723b5f7 Merge branch 'obsd-master' 2020-07-13 10:01:18 +01:00
nicm
f26b7b7788 Clarify /tmp permissions and use, GitHub issue 2300. 2020-07-13 07:04:17 +00:00
Nicholas Marriott
a5f99e14c6 Update version. 2020-07-06 14:07:11 +01:00
Nicholas Marriott
b30989a964 Pull 3.2-rc up to master. 2020-07-06 14:03:33 +01:00
Thomas Adam
aa4f3a9b3d Merge branch 'obsd-master' 2020-07-06 12:01:22 +01:00
nicm
2aa177d102 Do not eliminate redundant clears, the code is wrong and doing it
correctly wouldn't be worth it. GitHub issue 2298.
2020-07-06 10:07:02 +00:00
nicm
66d5e5de7a Add a way for control mode clients to subscribe to a format and be
notified of changes rather than having to poll. GitHub issue 2242.
2020-07-06 09:14:20 +00:00
Thomas Adam
af82094439 Merge branch 'obsd-master' 2020-07-06 10:01:19 +01:00
nicm
2bf612a806 Always send xterm-style keys for M-Left and M-Right. GitHub issue 2296. 2020-07-06 07:27:39 +00:00
Thomas Adam
c0d9eaff9b Merge branch 'obsd-master' 2020-07-04 16:01:20 +01:00
nicm
1e42689661 kill-window -a cannot just walk the list of windows because if
renumber-windows is on, the window it wants to keep could be moved.
Change to renumber afterwards and also behave better if the window is
linked into the session twice. GitHub issue 2287.
2020-07-04 14:24:02 +00:00
Nicholas Marriott
a109e839d1 Fix version. 2020-07-03 12:03:25 +01:00
Nicholas Marriott
6b01eac774 Merge branch '3.2-rc' 2020-07-03 12:03:07 +01:00
nicm
5661346c41 Missing word, from annihilannic at hotmail dot com, GitHub issue 2288. 2020-07-03 12:02:52 +01:00
nicm
0d0fc13aaa Check if client is NULL before using it, GitHub issue 2295. 2020-07-03 12:02:46 +01:00
bket
83868ceb1a Replace TAILQ concatenation loop with TAILQ_CONCAT
As a result remove unneeded variables

OK @nicm
2020-07-03 12:02:37 +01:00
Thomas Adam
0fa306d73c Merge branch 'obsd-master' 2020-07-03 10:01:20 +01:00
nicm
43e1577b5d Missing word, from annihilannic at hotmail dot com, GitHub issue 2288. 2020-07-03 07:07:50 +00:00
nicm
2b1e8d06e1 Check if client is NULL before using it, GitHub issue 2295. 2020-07-03 07:00:12 +00:00
Thomas Adam
a284664e71 Merge branch 'obsd-master' 2020-06-29 18:01:18 +01:00
bket
2a9bdb700d Replace TAILQ concatenation loop with TAILQ_CONCAT
As a result remove unneeded variables

OK @nicm
2020-06-29 15:53:28 +00:00
nicm
629ba1b838 Check for no pane border status line separately from top/bottom. 2020-06-29 09:20:39 +01:00
nicm
c9b4d5a4a5 Fix 0x Unicode character parsing, GitHub issue 2286. 2020-06-29 09:20:32 +01:00
nicm
6cacaa94a5 Silently ignore -a or -b if the window index doesn't exist and create
using that index (this is how it used to work), reported by Romain
Francoise.
2020-06-29 09:20:25 +01:00
Thomas Adam
332aca754b Merge branch 'obsd-master' 2020-06-27 12:01:18 +01:00
nicm
b6aeb86c20 Check for no pane border status line separately from top/bottom. 2020-06-27 10:23:10 +00:00
nicm
74df7071ad Fix 0x Unicode character parsing, GitHub issue 2286. 2020-06-27 10:19:59 +00:00
Thomas Adam
04a1a84bb8 Merge branch 'obsd-master' 2020-06-25 12:01:17 +01:00
nicm
f69bdda950 Silently ignore -a or -b if the window index doesn't exist and create
using that index (this is how it used to work), reported by Romain
Francoise.
2020-06-25 08:56:02 +00:00
nicm
43295bd4a5 Correctly redraw pane border bottom line when the status line is on and
at the bottom, reported by Kaushal Modi.
2020-06-23 16:32:40 +01:00
nicm
e215a566a4 Use xvasprintf not vasprintf. 2020-06-23 16:32:40 +01:00
Thomas Adam
2a2ebf315f Merge branch 'obsd-master' 2020-06-23 16:01:18 +01:00
nicm
5340bf556e Correctly redraw pane border bottom line when the status line is on and
at the bottom, reported by Kaushal Modi.
2020-06-23 14:10:43 +00:00
Thomas Adam
1f515663d1 Merge branch 'obsd-master' 2020-06-23 08:01:18 +01:00
nicm
2964dde903 Use xvasprintf not vasprintf. 2020-06-23 05:23:26 +00:00
Nicholas Marriott
e450416c93 3.2-rc. 2020-06-22 12:55:10 +01:00
Nicholas Marriott
b730083d7a Add to CHANGES. 2020-06-22 12:53:43 +01:00
Nicholas Marriott
3a1fc7315c Add getline compat. 2020-06-18 21:01:55 +01:00
Nicholas Marriott
3df68d6b00 Fix regress test for am. 2020-06-18 21:01:45 +01:00
Thomas Adam
6c437d45ac Merge branch 'obsd-master' 2020-06-18 12:01:22 +01:00
nicm
068b92b051 The redraw callback could be fired with a NULL pane if it updates while
in a mode, problem reported by Martin Vahlensieck.
2020-06-18 08:41:56 +00:00
nicm
2372b0fdc6 Add a flag to make a client wait for an empty line before exiting in
control mode to avoid stray commands ending up in the shell.
2020-06-18 08:34:22 +00:00
Thomas Adam
eb448daa1a Merge branch 'obsd-master' 2020-06-16 10:01:21 +01:00
nicm
1bf9555e4f d and D keys to reset to default in customize mode. 2020-06-16 08:18:34 +00:00
nicm
afe4ea4250 Correctly move to previous line when looking for previous word, from
Derry Jing.
2020-06-16 07:28:57 +00:00
Thomas Adam
824efe7be4 Merge branch 'obsd-master' 2020-06-13 12:01:20 +01:00
nicm
1c78155e70 Add -b flags to insert a window before (like the existing -a for after)
to break-pane, move-window, new-window. GitHub issue 2261.
2020-06-13 09:05:53 +00:00
Thomas Adam
4000052d92 Merge branch 'obsd-master' 2020-06-12 12:01:17 +01:00
nicm
d52ac7d027 Do not wait on shutdown for commands started with run -b. 2020-06-12 10:31:12 +00:00
Thomas Adam
bd3fb2fb10 Merge branch 'obsd-master' 2020-06-12 10:01:19 +01:00
nicm
d8d7769104 Check if a pane needs to be paused when output is written rather than
just when it is queued.
2020-06-12 08:35:01 +00:00
nicm
4c3bdc5a36 move-pane also defaults to marked pane now, reported by Ben Challenor. 2020-06-12 07:52:38 +00:00
nicm
cf63465eb0 Fix quoting with newlines and single quotes. 2020-06-12 07:10:43 +00:00
Thomas Adam
b5c86fdc0c Merge branch 'obsd-master' 2020-06-11 22:01:23 +01:00
nicm
63c2ed1483 Add some formats for search in copy mode (search_present, search_match).
GitHub issue 2268.
2020-06-11 19:43:34 +00:00
Thomas Adam
2e5b496053 Merge branch 'obsd-master' 2020-06-11 14:01:19 +01:00
Thomas Adam
e8c99496cd Merge branch 'obsd-master' 2020-06-11 12:01:19 +01:00
nicm
cf13d1e110 Fix a crash when completing sessions, from Anindya Mukherjee. 2020-06-11 10:56:19 +00:00
nicm
50ee41423f Add a -A option to pause a pane manually. 2020-06-11 09:55:47 +00:00
Thomas Adam
ea4425b9bd Merge branch 'obsd-master' 2020-06-10 10:01:20 +01:00
nicm
23d79cfda8 Instead of a buffer size limit on each pane, set a limit of 300 seconds
of data for each client in control mode.
2020-06-10 07:27:10 +00:00
Thomas Adam
8b673cc4f2 Merge branch 'obsd-master' 2020-06-10 08:01:19 +01:00
nicm
fddcad6957 When the pause-after flag is set, send an alternative %extended-output
form instead of %output with the age of the output.
2020-06-10 06:23:43 +00:00
Thomas Adam
208d9449b7 Merge branch 'obsd-master' 2020-06-09 12:01:18 +01:00
nicm
fee585ea14 Include width in error message. 2020-06-09 10:37:00 +00:00
Thomas Adam
30eaf885c4 Merge branch 'obsd-master' 2020-06-09 10:01:17 +01:00
nicm
c60389acbf It is not sensible to store pointers into an array we are going to
realloc (duh), use two trees instead.
2020-06-09 08:34:33 +00:00
Thomas Adam
9ffdcc7656 Merge branch 'obsd-master' 2020-06-06 14:01:17 +01:00
nicm
a4a3d89598 Use bitshifts instead of a union for encoding UTF-8 into 32 bits, which
is more friendly to GCC3.

Reported by and ok aoyama@.
2020-06-06 12:38:32 +00:00
Nicholas Marriott
0d8ba2e57f Add to CHANGES. 2020-06-05 14:56:55 +01:00
Thomas Adam
92c8cc17c3 Merge branch 'obsd-master' 2020-06-05 14:01:19 +01:00
nicm
d919fa1ed0 Change how panes are resized so that the code is clearer and if the pane
is resized multiple times during one event loop, it is forced to resize
at the end. Also don't zoom/unzoom in switch-client if the pane hasn't
changed. GitHub issue 2260.
2020-06-05 11:20:51 +00:00
Thomas Adam
47a5afe5bf Merge branch 'obsd-master' 2020-06-05 12:01:18 +01:00
nicm
03b2998abe Do not take the address of a potentially unaligned member. 2020-06-05 09:35:41 +00:00
nicm
c908d2039f Fix various confusion about am vs xenl. 2020-06-05 09:32:15 +00:00
Thomas Adam
a06cf900c7 Merge branch 'obsd-master' 2020-06-05 10:01:22 +01:00
nicm
4e5e2c19d0 Now that we mostly only search visible text, the rate limit on repeating
search does not seem to be necessary, remove it for the moment.
2020-06-05 07:44:42 +00:00
nicm
c586208991 Add support for pausing a pane when the output buffered for a control
mode client gets too far behind. The pause-after flag with a time is set
on the pane with refresh-client -f and a paused pane may be resumed with
refresh-client -A. GitHub issue 2217.
2020-06-05 07:33:57 +00:00
Thomas Adam
976cf6c60f Merge branch 'obsd-master' 2020-06-05 00:01:19 +01:00
nicm
d9cd493d09 Reset wrapped flag when clearing or moving lines, GitHub issue 2215. 2020-06-04 21:41:31 +00:00
nicm
2154e1f4fb Search marks outside the visible text are not useful, so there is no
point in allocating a big buffer to store them - just allocate the
visible text size, and ignore any outside.
2020-06-04 21:40:27 +00:00
Thomas Adam
8b43fcd82b Merge branch 'obsd-master' 2020-06-04 22:01:17 +01:00
nicm
c4732af006 Some improvements to performance of searching:
- Do not allow searches to be repeated at intervals of less than 50
  milliseconds, to prevent a huge queue of repeat key presses blocking
  up everything for ages.

- If the search text hasn't changed, the match count can't have changed
  and there is no need to do a full search, so only search the visible
  text. This includes both scrolling and repeating the search.

- Do not redraw twice when jumping to the search location.

GitHub issue 2258.
2020-06-04 20:41:57 +00:00
Thomas Adam
c8bddfba2b Merge branch 'obsd-master' 2020-06-04 18:01:17 +01:00
nicm
4403afe29c A } can go on the same line as a command. 2020-06-04 16:06:01 +00:00
Thomas Adam
81ba6477ff Merge branch 'obsd-master' 2020-06-04 12:01:20 +01:00
Nicholas Marriott
23a3742dc8 Update CHANGES. 2020-06-04 11:43:11 +01:00
nicm
4ea3370316 Shorten some long lines. 2020-06-04 10:36:28 +00:00
nicm
a9bf5367da Correct respawn-* - they don't always use the creation command. 2020-06-04 10:34:40 +00:00
nicm
dc74d2e054 Make the -no-clear command variants not clear the search marks either. 2020-06-04 10:24:14 +00:00
Thomas Adam
b0a6025897 Merge branch 'obsd-master' 2020-06-04 10:01:20 +01:00
nicm
d3c5202f50 Allow strings to span multiple lines - newlines and any leading
whitespace are removed, as well as any following comments that couldn't
be part of a format. This allows long formats or other strings to be
annotated and indented.
2020-06-04 08:30:44 +00:00
nicm
b3782d2dc8 Instead of using a custom parse function to process {}, treat it as a
set of statements and parse with yacc, then convert back to a string as
the last step. This means the rules are consistent inside and outside
{}, %if and friends work at the right time, and the final result isn't
littered with unnecessary newlines.
2020-06-04 07:12:05 +00:00
Thomas Adam
f837dcdd58 Merge branch 'obsd-master' 2020-06-03 18:01:17 +01:00
nicm
3f6af4156f Make paste -p the default for ], GitHub issue 2248. 2020-06-03 16:35:40 +00:00
Thomas Adam
62c0617d79 Merge branch 'obsd-master' 2020-06-03 00:01:20 +01:00
Thomas Adam
3d5decb305 Merge branch 'obsd-master' 2020-06-02 22:01:20 +01:00
nicm
4694e9a2b6 Move the code to set up a padding cell into grid.c. 2020-06-02 20:51:46 +00:00
nicm
2a4d4bda2b Allow UTF-8 characters of width 0 to be stored, it is useful to be able
to put padding cells in as width 0.
2020-06-02 20:10:23 +00:00
nicm
f5366ff828 Missing ; in previous. 2020-06-02 19:16:46 +00:00
nicm
5fbae8c8c6 Fire copy-pipe command even if there is no text, means it works if it
has side effects.
2020-06-02 19:10:26 +00:00
Thomas Adam
ebe866c378 Merge branch 'obsd-master' 2020-06-02 20:01:18 +01:00
nicm
7e501f1993 UTF-8 keys need to be big endian so the size bits are at the top. 2020-06-02 17:17:44 +00:00
Thomas Adam
049ccb4a4b Merge branch 'obsd-master' 2020-06-02 14:01:17 +01:00
nicm
822ee4e0a6 Fail rather than fatal on UTF-8 width 0. 2020-06-02 11:29:00 +00:00
Thomas Adam
31a51cae1d Merge branch 'obsd-master' 2020-06-02 11:29:48 +01:00
nicm
f3931497f8 Use CLOCK_MONOTONIC for timer measurement and add a timestamp to control
mode %output blocks.
2020-06-02 08:17:27 +00:00
nicm
563b7331da Remove blocks from queue when pane disappears. 2020-06-01 21:08:05 +00:00
nicm
8339702d47 Check the right thing for maximum client buffer size. 2020-06-01 20:58:42 +00:00
nicm
9819470058 Change format callback to return value rather than storing it in the entry. 2020-06-01 19:39:25 +00:00
Thomas Adam
191a836560 Merge branch 'obsd-master' 2020-06-01 18:01:18 +01:00
nicm
674ec410b7 Try without cursor/keypad flags if a key doesn't exist, and limit ctrl
key translation to ASCII keys. Fixes send-keys, GitHub issue 2247.
2020-06-01 16:09:35 +00:00
Thomas Adam
91e40de2da Merge branch 'obsd-master' 2020-06-01 12:01:20 +01:00
nicm
a54a88edd6 Instead of sending all data to control mode clients as fast as possible,
add a limit of how much data will be sent to the client and try to use
it for panes with some degree of fairness. GitHub issue 2217, with
George Nachman.
2020-06-01 09:43:00 +00:00
Thomas Adam
5ef790a6c4 Merge branch 'obsd-master' 2020-05-29 16:01:19 +01:00
nicm
175e45005f Add -i to find-window to ignore case. 2020-05-29 13:42:13 +00:00
Nicholas Marriott
ce6b3a539d utf8proc_unicode_version is too new. 2020-05-28 08:41:56 +01:00
Thomas Adam
86159fca82 Merge branch 'obsd-master' 2020-05-27 16:01:18 +01:00
nicm
bda2a0282a Fix ASCII keys with send-keys -l. 2020-05-27 14:45:35 +00:00
Thomas Adam
38ce6adab6 Merge branch 'obsd-master' 2020-05-27 08:01:19 +01:00
nicm
f336599a3a Make padding cell a valid character. 2020-05-27 06:23:23 +00:00
Thomas Adam
fd8652ceda Merge branch 'obsd-master' 2020-05-26 16:01:19 +01:00
nicm
2ced370bee Tweak some out of date bits, reported by bcgraham. 2020-05-26 13:19:21 +00:00
Thomas Adam
a4cb700269 Merge branch 'obsd-master' 2020-05-26 14:02:15 +01:00
nicm
ff6f2ff6d9 Return new character properly when converting to data. 2020-05-26 12:50:03 +00:00
nicm
392b381d1c Apply -n when only one pane in the window. 2020-05-26 09:01:03 +00:00
nicm
370f0bb98d Remove leftover debug logging and fix comparison. 2020-05-26 08:56:48 +00:00
nicm
ca0166f26f Do not try to use the last marked pane if it is invalid. 2020-05-26 08:47:50 +00:00
nicm
ea610a3119 Pass the stdout file descriptor from the client as well as stdin and use
them for control clients directly instead of passing everything via the
client.
2020-05-26 08:41:47 +00:00
Nicholas Marriott
bc2e0cf7ff Remove bad merge. 2020-05-26 08:54:05 +01:00
Nicholas Marriott
d73fcfc176 Put the fix back for wcwidth() failing. 2020-05-26 08:49:36 +01:00
Thomas Adam
967e5f8be3 Merge branch 'obsd-master' 2020-05-26 08:42:55 +01:00
Nicholas Marriott
fd4d3e8793 Set IUTF8 again when it exists. 2020-05-26 06:15:57 +01:00
nicm
6f03e49e68 Use the internal representation for UTF-8 keys instead of wchar_t and
drop some code only needed for that.
2020-05-25 18:57:24 +00:00
nicm
35779d655d Fix definition of padding cells so they are not extended cells. 2020-05-25 18:55:36 +00:00
nicm
49ec074271 Tidy up new UTF-8 code and make it more generic. 2020-05-25 18:19:29 +00:00
nicm
dc893405e1 Fix some error strings, from Kris Katterjohn. 2020-05-25 18:17:14 +00:00
Thomas Adam
b34af611a5 Merge branch 'obsd-master' 2020-05-25 18:01:20 +01:00
nicm
bbfb44e9b2 Make some data types consistent. 2020-05-25 15:02:25 +00:00
Thomas Adam
32ce468b22 Merge branch 'obsd-master' 2020-05-25 14:01:19 +01:00
nicm
4589297e43 Do not attempt to divide by zero when working out copy position. 2020-05-25 12:12:58 +00:00
nicm
26e8e467e8 Include title for the width of the menu. 2020-05-25 11:59:50 +00:00
Thomas Adam
bb5a1925ab Merge branch 'obsd-master' 2020-05-25 12:01:19 +01:00
nicm
3a5219c6d0 Instead of storing all UTF-8 characters in the extended cell which means
that 14 bytes are wasted for each character in the BMP, only store
characters of three bytes or less in the cell itself and store others
(outside the BMP or with combining characters) in a separate global
tree. Can reduce grid memory use for heavy Unicode users by around 30%.
2020-05-25 09:32:10 +00:00
Thomas Adam
e16191dbfc Merge branch 'obsd-master' 2020-05-24 16:01:20 +01:00
nicm
14a9fd58d5 Remove leftover call to control_free_offsets and do not use for
non-control clients.
2020-05-24 14:45:00 +00:00
Thomas Adam
aeefd585a0 Merge branch 'obsd-master' 2020-05-24 12:01:21 +01:00
nicm
18aab90959 Give control code its own state struct. 2020-05-24 09:40:17 +00:00
nicm
6c82982711 Now the tty has a pointer back to the client there is no point (and a
bit confusing) in it keeping a copy of the fd as well. Remove it.
2020-05-24 09:13:06 +00:00
Thomas Adam
e71c5efd58 Merge branch 'obsd-master' 2020-05-22 18:01:20 +01:00
Nicholas Marriott
2ac6cc2633 Put headers back how they were. 2020-05-22 17:34:30 +01:00
Nicholas Marriott
a48cc458a6 Maybe this is better. 2020-05-22 17:27:07 +01:00
Nicholas Marriott
1fdacba111 Think Solaris needs term.h here. 2020-05-22 17:24:42 +01:00
Nicholas Marriott
b3e5a99c8f And tweak again. 2020-05-22 17:22:03 +01:00
Nicholas Marriott
6ae26a6b54 Fix utf8proc version logging. 2020-05-22 17:20:35 +01:00
Nicholas Marriott
87a59efc94 Log ncurses and utf8proc versions. 2020-05-22 17:14:35 +01:00
nicm
033d6472cb FocusIn keys can also update the latest client, like normal keys. 2020-05-22 15:43:38 +00:00
nicm
a06a0e1392 xterm* can have focus too. 2020-05-22 15:08:38 +00:00
Thomas Adam
d48f0e114e Merge branch 'obsd-master' 2020-05-22 13:40:33 +01:00
nicm
9a0763c3a0 Move client offset stuff into control.c since only control clients will
need it.
2020-05-22 11:07:04 +00:00
Thomas Adam
2420bd8584 spawn.c: fix up bad merge 2020-05-21 09:02:36 +01:00
Thomas Adam
40126ee96c Merge branch 'obsd-master' 2020-05-21 08:55:31 +01:00
nicm
31e3f2d530 Support code for control mode flow control: allow clients to have
separate offsets (used and acknowleged) into the pane buffers; turn off
reading from panes when no clients can accept the data; and add a -A
flag to refresh-client to let clients turn receiving a pane on and off.
2020-05-21 07:24:13 +00:00
Nicholas Marriott
98a18d064a Fix a regression test, size is not updated until end of event loop. 2020-05-21 08:20:37 +01:00
Thomas Adam
5ac5cd995e Merge branch 'obsd-master' 2020-05-20 10:01:19 +01:00
nicm
6bde1c1837 Fix a couple more places where the key flags need to be masked off. 2020-05-20 07:11:45 +00:00
Thomas Adam
fa835339fd Merge branch 'obsd-master' 2020-05-20 08:01:18 +01:00
nicm
b53e60f4c6 Remove a redundant if statement. 2020-05-20 06:18:22 +00:00
nicm
2a9e2b556a Key strings need to include the cursor and keypad flags now since the
output key lookup expects them already set.
2020-05-20 06:13:09 +00:00
Thomas Adam
fb9e53ba19 Merge branch 'obsd-master' 2020-05-19 14:01:17 +01:00
Nicholas Marriott
e10f5a72ce Add FreeBSD CI, from Jan Beich. 2020-05-19 12:34:34 +01:00
nicm
8425084b8a Some other ctrl keys need to be translated with extended keys on. 2020-05-19 10:59:09 +00:00
Nicholas Marriott
dc56b3cd32 No paths.h. 2020-05-16 20:27:00 +01:00
Thomas Adam
2bc05db54f remove vis.h: portable doesn't need this 2020-05-16 18:42:53 +01:00
Thomas Adam
bd87f6bf00 Merge branch 'obsd-master' 2020-05-16 18:36:35 +01:00
nicm
574a9e4b6c Move lazy resize from the pane to the window, there is no point in
resizing the window unless it is the current window, and if we do and
don't resize the pane until later there are problems if the size changes
from A to B then back to A.
2020-05-16 16:50:55 +00:00
nicm
844b363baf On select-window, make this client the latest client for the window. 2020-05-16 16:45:55 +00:00
nicm
0ab82d9531 Add a terminal feature for enable/disable extended keys (supported by
xterm and mintty) and add an option to make tmux send it. Only forward
extended keys if the application has requested them, even though we use
the CSI u sequence and xterm uses CSI 27 ~ - this is what mintty does as
well.
2020-05-16 16:44:54 +00:00
nicm
292b335ca5 Separate key flags and modifiers, log key flags, make the "xterm" flag
more explicit and fix M- keys with a leading escape.
2020-05-16 16:35:13 +00:00
nicm
e2a26740b9 Add an option to set the pane border lines style from a choice of single
lines (ACS or UTF-8), double or heavy (UTF-8), simple (plain ASCII) or
number (the pane numbers). Lines that won't work on a non-UTF-8 terminal
are translated back into ACS when they are output.
2020-05-16 16:26:34 +00:00
nicm
ecbdcc256f Add screen write flags instead of individual bits and fix line length
calculation with padding.
2020-05-16 16:22:01 +00:00
nicm
303d342d5f Add a client flag 'active-pane' which stores the active pane in the
client and allows it to be changed independently from the real active
pane stored in the window. This is can be used with session groups which
allow an independent current window (although it would be nice to have a
flag for this too and remove session groups). The client active pane is
only really useful interactively, many things (hooks, window-style,
zooming) still use the window active pane.
2020-05-16 16:20:59 +00:00
nicm
c914abfa19 Expand target from client and use it to expand the prompt. 2020-05-16 16:16:07 +00:00
nicm
72984c4834 Move editor stuff to common code in popup.c. 2020-05-16 16:13:09 +00:00
nicm
ff8dd150e0 Add a mark in copy mode. Set with set-mark command (bound to 'X') by
default and the mark and cursor position are swapped with 'jump-to-mark'
(bound to M-x). The line containing the mark is shown in
copy-mode-mark-style with the horizontal position in reverse.

From Anindya Mukherjee in GitHub issue 2209.
2020-05-16 16:10:28 +00:00
nicm
dceb6a15d0 Add a -D flag to ask tmux not to daemonize, useful both for running a
debugger (lldb does not have follow-fork-mode) and for running with a
managed supervisor init system. GitHub issue 2190.
2020-05-16 16:07:55 +00:00
nicm
126bacb473 Do not loop forever when search finds an empty match, GitHub issue 2203. 2020-05-16 16:03:57 +00:00
nicm
592f141dee Fix next-matching-bracket logic, from Chris Barber. 2020-05-16 16:03:30 +00:00
nicm
d67245c734 Add a customize mode where keys and options may be browsed and changed,
includes adding a brief description of each option. Bound to "C" by
default.
2020-05-16 16:02:24 +00:00
nicm
472d77fd0f Support embedded styles in the display-message message, GitHub issue
2206.
2020-05-16 15:54:20 +00:00
nicm
6ea6d46d0a Store and restore cursor position when copy mode is resized, from
Anindya Mukherjee.
2020-05-16 15:49:20 +00:00
nicm
daa95810b5 Allow a custom time format to be given to the t format modifier. 2020-05-16 15:48:35 +00:00
nicm
367b4e4e0f Change message log to be per server rather than per client and include
every command that is run.
2020-05-16 15:47:22 +00:00
nicm
4de0bd4c5c Add M-+ and M-- to expand and collapse all items in tree mode. 2020-05-16 15:46:01 +00:00
nicm
cf9baddd6f Change the existing client flags for control mode to apply for any
client, use the same mechanism for the read-only flag and add an
ignore-size flag.

refresh-client -F has become -f (-F stays for backwards compatibility)
and attach-session and switch-client now have -f flags also. A new
format "client_flags" lists the flags and is shown by list-clients by
default.

This separates the read-only flag from "ignore size" behaviour (new
ignore-size) flag - both behaviours are useful in different
circumstances.

attach -r and switchc -r remain and set or toggle both flags together.
2020-05-16 15:45:29 +00:00
nicm
469eda7e44 Only redraw popup on the client it belongs to. 2020-05-16 15:41:54 +00:00
nicm
4e053685df Export TERM_PROGRAM and TERM_PROGRAM_VERSION like various other
terminals.
2020-05-16 15:40:44 +00:00
nicm
beb214bcb3 Add formats for after hook command arguments. 2020-05-16 15:40:04 +00:00
nicm
d056144aa1 Try to search the entire history first for up to 200 ms so a search
count can be shown. If it takes too long, search the visible text only.
2020-05-16 15:38:14 +00:00
nicm
3fb4d4df43 Do not need to work out status line offset, we already have it. 2020-05-16 15:36:57 +00:00
nicm
2df75aa117 Use VIS_CSTYLE for paste buffers also. 2020-05-16 15:35:19 +00:00
nicm
9605b080f6 Do not hoke into struct window_pane from the tty code and instead set
everything up in tty_ctx. Provide a way to initialize the tty_ctx from a
callback and use it to let popups draw directly through input_parse in
the same way as panes do, rather than forcing a full redraw on every
change.
2020-05-16 15:34:08 +00:00
nicm
379ca54c80 Rename and tidy some stuff in struct tty_ctx. 2020-05-16 15:27:08 +00:00
nicm
edeb81ba9e Add -e for new-session to set environment variables. 2020-05-16 15:25:24 +00:00
nicm
78595457f9 Add 'e' key in buffer mode to open the buffer in an editor. 2020-05-16 15:24:28 +00:00
nicm
a3cbc014c3 Use formats for status-style and message-style. 2020-05-16 15:19:04 +00:00
nicm
58fb81d19a Complete partial window indexes properly. 2020-05-16 15:18:17 +00:00
nicm
463864f5a2 Add -W and -T flags to command-prompt to only complete a window and a
target, also complete aliases.
2020-05-16 15:16:36 +00:00
nicm
2391fe23ab Copy mode search improvements:
- Add styles for the search marking styles (copy-mode-match-style and
  copy-mode-current-match-style).

- Show the current match (the one with the cursor on it) in a different style.

- Copying without a selection will copy the current match if there is one.
2020-05-16 15:11:52 +00:00
nicm
80e52545a0 Improve command prompt completion:
- Show a menu with completions if there are multiple.

- Don't complete argument stuff (options, layouts) at start of text.

- For -t and -s, if there is no : then complete sessions but if there is
  a :, show a menu of all windows in the session rather than trying to
  complete the window name which is a bit useless if there are
  duplicates.
2020-05-16 15:06:03 +00:00
nicm
f03b61131b Drop having a separate type for style options and make them all strings,
which allows formats to be expanded. Any styles without a '#{' are still
validated when they are set but any with a '#{' are not. Formats are not
expanded usefully in many cases yet, that will be changed later.

To make this work, a few other changes:

- set-option -a with a style option automatically appends a ",".

- OSC 10 and 11 don't set the window-style option anymore, instead the
  fg and bg are stored in the pane struct and act as the defaults that
  can be overridden by window-style.

- status-fg and -bg now override status-style instead of trying to keep
  them in sync.
2020-05-16 15:01:30 +00:00
nicm
0487029fc5 Call format_defaults_window for panes as well. 2020-05-16 14:55:38 +00:00
nicm
5bf96c2f2c Use a grid cell not a style for the pane style. 2020-05-16 14:53:23 +00:00
nicm
428137d876 Instead of forbidding invalid session names, sanitize them like window
names.
2020-05-16 14:49:50 +00:00
nicm
7dbe623156 Instead of having a default set of terminals in terminal-overrides that
get XT added and using that as a marker for xterm(1)-like, assume that
if the terminfo(5) entry already has XT or the clear capability starts
with CSI then the terminal is VT100-like and it should be safe to send
DA requests. The DA responses trigger additional features being added.
2020-05-16 14:46:14 +00:00
nicm
21a39c997b Do not redraw or update mode if nothing has changed. 2020-05-16 14:42:06 +00:00
nicm
aebeeec1e9 Add feature and capabilities for focus reporting. Also document AX and
XT even though they aren't tmux's, and add some bits for rxvt.
2020-05-16 14:39:40 +00:00
nicm
26312a7774 Move terminal features into a single file. 2020-05-16 14:30:17 +00:00
nicm
a29196ca6a Build list of paths and weed out duplicates before loading configs, and
add TMUX_SOCK like TMUX_PATH for the socket directory.
2020-05-16 14:26:33 +00:00
nicm
4e0a718666 Add extension terminfo(5) capabilities for margins. 2020-05-16 14:22:51 +00:00
nicm
41dec585df Response is iTerm2 not not ITerm2. 2020-05-16 14:18:39 +00:00
nicm
9dd58470e4 Remove support for iTerm2's DSR 1337 extension and use the CSI > q
extension now supported by a few different terminals.
2020-05-16 14:16:25 +00:00
nicm
471f697423 Add an attribute for ACS. 2020-05-16 14:13:37 +00:00
nicm
0dd1944206 Tweak the default choose modes formats:
- Only show pane title if it is not default and not empty.
- Add a prettier time format and use that instead of long ctime().
- Remove clutter and change the order.
2020-05-16 14:10:29 +00:00
Nicholas Marriott
57fe03dc5a Move lazy resize from the pane to the window, there is no point in resizing the
window unless it is the current window, and if we do and don't resize the pane
until later there are problems if the size changes from A to B then back to A.
2020-05-16 14:57:36 +01:00
Nicholas Marriott
53c84fd4aa If the application has not requested extended keys, then C-1 sends 1 not
nothing.
2020-05-16 07:39:22 +01:00
Nicholas Marriott
740f047a85 Need to update features after all the sequences come in. 2020-05-16 07:32:46 +01:00
Nicholas Marriott
c2167c5ee8 On select-window, make this client the latest client for the window. 2020-05-15 22:52:55 +01:00
Nicholas Marriott
e8ca5a4c7d List needs to be sorted. 2020-05-15 19:17:56 +01:00
Nicholas Marriott
67090dd91d XTerm not xterm. 2020-05-15 19:10:06 +01:00
Nicholas Marriott
401f197750 Er, misread this and it is not needed. 2020-05-15 18:58:13 +01:00
Nicholas Marriott
ca60aabab5 Translate special CSI u keys on input. 2020-05-15 18:25:44 +01:00
Nicholas Marriott
7317a0865c Get == and != the right way round. 2020-05-15 17:49:58 +01:00
Nicholas Marriott
0b828b91a5 Only send XDA on 0. 2020-05-15 17:49:07 +01:00
Nicholas Marriott
dcf537519f Fix default values for new escape sequences. 2020-05-15 17:48:21 +01:00
Nicholas Marriott
c364a7142c Only forward extended keys if the application has requested them, even though
we use the CSI u sequence and xterm uses CSI 27 ~ - this is what mintty does as
well.
2020-05-15 17:40:24 +01:00
Nicholas Marriott
3a4f3ee087 Mask off flags bits in menu keys. 2020-05-15 16:17:20 +01:00
Nicholas Marriott
6d92b99dbc Add a terminal feature for enable/disable extended keys (supported by xterm and
mintty) and add an option to make tmux send it.
2020-05-15 16:15:24 +01:00
Nicholas Marriott
e6b17e77db C-M-S keys need the implied flag also. 2020-05-15 15:11:08 +01:00
Nicholas Marriott
e23c73457a Stop at end of buffer. 2020-05-15 15:05:49 +01:00
Nicholas Marriott
3e60ab1caf Send conventional \033 sequences for keys with just Meta even if they came in
as an extended CSI u key sequence. It is much more useful for applications that
don't understand CSI u to receive \033> for M-S-. rather than \033[62;3u.
2020-05-15 13:15:12 +01:00
Nicholas Marriott
7501e297dd Send CSI u sequences for any keys that do not have a defined sequence already -
this should only be similar sequences sent by the terminal outside tmux if
enabled.
2020-05-15 12:39:37 +01:00
Nicholas Marriott
340fd691cb Separate key flags and modifiers, log key flags, make the "xterm" flag more
explicit and fix M- keys with a leading escape.
2020-05-15 12:16:41 +01:00
Nicholas Marriott
031d4864a9 Rename KEYC_ESCAPE to KEYC_META. 2020-05-15 11:24:30 +01:00
Nicholas Marriott
2cf967ee67 Always set xterm flag. 2020-05-15 11:20:12 +01:00
Nicholas Marriott
e95b644139 Recognise extended key sequences on input (both the forms xterm offers). 2020-05-15 11:09:32 +01:00
Nicholas Marriott
5ee4d991b6 xterm-keys has been on by default for 5 years and all other modern terminals
use these key sequences by default. Merge the code into the main tty and input
tree processing (convering the latter to use a tree rather than a table at the
same time) and make the option a no-op.
2020-05-15 10:31:54 +01:00
Nicholas Marriott
c4d8100b2f Draw outside correctly with pane numbers. 2020-05-14 16:58:14 +01:00
Nicholas Marriott
bef70132ac Check if outside the window before checking if on the border so that cells that
are outside in one direction but not the other are not given the wrong type.
2020-05-14 16:53:04 +01:00
Nicholas Marriott
31621036ad Add an option to set the pane border lines style from a choice of single lines
(ACS or UTF-8), double or heavy (UTF-8), simple (plain ASCII) or number (the
pane numbers). Lines that won't work on a non-UTF-8 terminal are translated
back into ACS when they are output.
2020-05-14 16:49:08 +01:00
Nicholas Marriott
97c8374855 Tweak CHANGES. 2020-05-14 14:07:26 +01:00
Nicholas Marriott
4dc0f3ee6b Update CHANGES. 2020-05-14 14:01:32 +01:00
Nicholas Marriott
09a66451ce Add screen write flags instead of individual bits and fix line length
calculation with padding.
2020-05-14 13:18:05 +01:00
Nicholas Marriott
0bdbf47ef9 Add a client flag 'active-pane' which stores the active pane in the client and
allows it to be changed independently from the real active pane stored in the
window. This is can be used with session groups which allow an independent
current window (although it would be nice to have a flag for this too and
remove session groups). The client active pane is only really useful
interactively, many things (hooks, window-style, zooming) still use the window
active pane.
2020-05-14 11:18:19 +01:00
Nicholas Marriott
12eceaf2b3 Expand target from client and use it to expand the prompt. 2020-05-14 10:35:26 +01:00
Nicholas Marriott
09a2246b00 Use safe loop for freeing client files. 2020-05-13 21:11:46 +01:00
Nicholas Marriott
e6d9f3f90c Add -Z to customize-mode binding. 2020-05-13 20:58:42 +01:00
Nicholas Marriott
3f55d05386 Tidy up border redrawing, fix some errors in how the window border connects
with panes.
2020-05-13 17:49:37 +01:00
Nicholas Marriott
4cb1d3d7a9 Move editor stuff to common code in popup.c. 2020-05-13 06:58:07 +01:00
Nicholas Marriott
6214cd0726 Add a mark in copy mode. Set with set-mark command (bound to 'X') by default
and the mark and cursor position are swapped with 'jump-to-mark' (bound to
M-x). The line containing the mark is shown in copy-mode-mark-style with the
horizontal position in reverse.

From Anindya Mukherjee in GitHub issue 2209.
2020-05-13 06:29:57 +01:00
Thomas Adam
9d44df9da9 Merge branch 'master' of github.com:tmux/tmux 2020-05-13 01:15:31 +01:00
Thomas Adam
212cf53ea9 Merge branch 'obsd-master' 2020-05-13 01:05:04 +01:00
Nicholas Marriott
ba20e46bdc Do not log NULL text. 2020-05-12 10:36:31 +01:00
Nicholas Marriott
8d238491d0 Show default key bindings in customize mode. 2020-05-12 10:22:38 +01:00
Nicholas Marriott
5a34f51d33 Include key bindings in customize mode. 2020-05-12 08:57:55 +01:00
Nicholas Marriott
c489bf0a1e Support embedded styles in the display-message message, GitHub issue 2206. 2020-05-11 09:18:35 +01:00
Nicholas Marriott
8502517d30 Add to CHANGES. 2020-05-10 17:06:31 +01:00
Nicholas Marriott
0070313e28 Fix comparison of tty name. 2020-05-10 16:57:33 +01:00
Nicholas Marriott
d01e7aac89 Add a -D flag to ask tmux not to daemonize, useful both for running a debugger
(lldb does not have follow-fork-mode) and for running with a managed supervisor
init system. GitHub issue 2190.
2020-05-10 16:52:46 +01:00
Nicholas Marriott
5fa377d927 Do not loop forever when search finds an empty match, GitHub issue 2203. 2020-05-10 10:01:20 +01:00
Nicholas Marriott
79a9a7b931 Fix next-matching-bracket logic, from Chris Barber. 2020-05-09 16:15:08 +01:00
Nicholas Marriott
532d06c399 Initialize return code in case something mysterious happens. 2020-05-09 16:08:13 +01:00
Nicholas Marriott
013d857ef8 Wrap all lines in customize mode, not just the description. 2020-05-09 15:29:14 +01:00
Nicholas Marriott
690d72adb3 Remove unused variables. 2020-05-09 14:38:00 +01:00
Nicholas Marriott
ca18990826 Fix some warnings, from Jan Polensky. 2020-05-09 14:33:25 +01:00
Nicholas Marriott
5e97d79eb1 Fix some customize mode drawing nits. 2020-05-08 22:09:31 +01:00
Nicholas Marriott
a61cbf1c33 Add a customize mode where options may be browsed and changed, includes adding
a brief description of each option. Bound to "C" by default.
2020-05-08 19:10:09 +01:00
nicm
aa7dccf8e1 imsg.h needs uio.h, pointed out by deraadt 2020-05-08 14:15:11 +00:00
Nicholas Marriott
708e9bc072 Allow a custom time format to be given to the t format modifier. 2020-05-07 11:04:43 +01:00
Nicholas Marriott
b0fa36734e Fix pretty time function to actually work and allow time format to be applied
to any string that is suitable.
2020-05-07 09:55:06 +01:00
Nicholas Marriott
63e17d8cad Do not use client if NULL, from Thomas Adam. 2020-05-07 05:55:42 +01:00
Nicholas Marriott
66ecb1dff4 Update CHANGES. 2020-05-06 15:48:27 +01:00
Nicholas Marriott
7a95e9bf7e Change message log to be per server rather than per client and include every
command that is run.
2020-05-06 13:43:22 +01:00
Nicholas Marriott
c80fc6bf9e Add M-+ and M-- to expand and collapse all items in tree mode. 2020-05-05 16:33:58 +01:00
Nicholas Marriott
2f89d2e7d8 Change the existing client flags for control mode to apply for any client, use
the same mechanism for the read-only flag and add an ignore-size flag.

refresh-client -F has become -f (-F stays for backwards compatibility) and
attach-session and switch-client now have -f flags also. A new format
"client_flags" lists the flags and is shown by list-clients by default.

This separates the read-only flag from "ignore size" behaviour (new
ignore-size) flag - both behaviours are useful in different circumstances.

attach -r and switchc -r remain and set or toggle both flags together.
2020-05-05 15:42:20 +01:00
Nicholas Marriott
deacfedc65 Remove an extra space in clients output. 2020-05-05 13:34:53 +01:00
Nicholas Marriott
32c134f5a9 Wrap a line. 2020-05-05 12:39:20 +01:00
Nicholas Marriott
23b4e1b9d8 pane_path is not #T, from Chris Rawnsley. 2020-05-05 11:35:33 +01:00
Nicholas Marriott
e810f15272 Store and restore cursor position when copy mode is resized, from Anindya
Mukherjee.
2020-05-05 10:20:57 +01:00
Nicholas Marriott
1f6c00f8ef Only redraw popup on the client it belongs to. 2020-05-05 10:02:47 +01:00
Nicholas Marriott
63390d2dd6 Export TERM_PROGRAM and TERM_PROGRAM_VERSION like various other terminals. 2020-05-05 06:31:14 +01:00
Nicholas Marriott
9991a14e81 Add formats for after hook command arguments. 2020-05-05 06:19:29 +01:00
Nicholas Marriott
fc13e9bc2b Turn off cursor in menus again. 2020-05-04 17:37:03 +01:00
Nicholas Marriott
a08f1c8c59 Merge branch '3.1b-rc' 2020-05-04 09:14:36 +01:00
Nicholas Marriott
a10c4c60cb Add to CHANGES. 2020-05-04 09:06:57 +01:00
Nicholas Marriott
c89ed7c092 Try to search the entire history first for up to 200 ms so a search count can
be shown. If it takes too long, search the visible text only.
2020-05-03 15:58:29 +01:00
Nicholas Marriott
e7aeb77bd9 Use the cursor position not the current position when working out which marks
are current.
2020-05-03 15:44:38 +01:00
Nicholas Marriott
cb09705df3 Need musl-gcc for static also. 2020-05-03 12:37:38 +01:00
Nicholas Marriott
4fcbd6700f Add musl builds. 2020-05-03 12:33:47 +01:00
Nicholas Marriott
ff5e3d1a88 Ugh, enable not with. 2020-05-03 12:20:08 +01:00
Nicholas Marriott
fbc8fca067 Use termcap instead. 2020-05-03 12:18:04 +01:00
Nicholas Marriott
1cfa6b0d5c Try w/o database. 2020-05-03 12:12:47 +01:00
Nicholas Marriott
b203f7f19f Better ncurses URL and some other fixes. 2020-05-03 12:03:50 +01:00
Nicholas Marriott
97d490204b Add build of everything. 2020-05-03 11:47:28 +01:00
Nicholas Marriott
55901367d0 Add more stuff. 2020-05-03 11:16:30 +01:00
Nicholas Marriott
ff250aa30e Fix exclude. 2020-05-03 11:12:51 +01:00
Nicholas Marriott
955d9d22b9 Add static build. 2020-05-03 11:09:36 +01:00
Nicholas Marriott
daef6f6b67 Merge branch '3.1b-rc' 2020-05-03 10:49:35 +01:00
Nicholas Marriott
846b99e0cb Portable does not need sys/queue.h. 2020-05-03 10:49:16 +01:00
Nicholas Marriott
d9a4449307 Do not need to work out status line offset, we already have it. 2020-05-02 16:44:31 +01:00
Nicholas Marriott
af69289e0e Clamping to area needs to use the offset without the status line, since that is
where the window offsets are based.
2020-05-02 16:17:44 +01:00
Nicholas Marriott
cb1131a294 menu_mode_cb needs to return a screen also. 2020-05-02 15:15:52 +01:00
Nicholas Marriott
e078f975c5 Update CHANGES. 2020-05-01 18:24:20 +01:00
Nicholas Marriott
bf84359dfb Use VIS_CSTYLE for paste buffers also. 2020-05-01 17:59:13 +01:00
Nicholas Marriott
1fa9bcc183 Turn off overlay check when we know we are inside. 2020-05-01 17:55:08 +01:00
Nicholas Marriott
3f1fc9cde3 Get the whole overlay screen not just the mode so cursor changes are included. 2020-05-01 17:30:28 +01:00
Nicholas Marriott
8110c7a25f Do not hoke into struct window_pane from the tty code and instead set
everything up in tty_ctx. Provide a way to initialize the tty_ctx from a
callback and use it to let popups draw directly through input_parse in the same
way as panes do, rather than forcing a full redraw on every change.
2020-05-01 17:01:36 +01:00
Nicholas Marriott
dbebdb2d36 Rename tty_pane_full_width to tty_full_width. 2020-05-01 13:22:08 +01:00
Nicholas Marriott
93dca5ab3f Move size to tty_ctx. 2020-05-01 13:19:05 +01:00
Nicholas Marriott
5ce194f15d Rename some tty_ctx members. 2020-05-01 13:01:55 +01:00
Nicholas Marriott
af21e76fdb Add -e for new-session. 2020-05-01 12:01:58 +01:00
Nicholas Marriott
ec61aa3025 Solaris at least does not have _PATH_VI. 2020-05-01 09:11:56 +01:00
Nicholas Marriott
5c888e168e Typo in man page. 2020-05-01 09:05:56 +01:00
Nicholas Marriott
cc19203be2 Add 'e' key in buffer mode to open the buffer in an editor. 2020-05-01 09:02:44 +01:00
Thomas Adam
7af5817245 Merge branch 'obsd-master' 2020-04-30 16:01:27 +01:00
Nicholas Marriott
3d33a19102 Merge tag '3.1b'
3.1b
2020-04-30 15:21:47 +01:00
Nicholas Marriott
6a33a12798 Do not remove the automatic-rename option from the global set, only from
the window (it must stay in the global set or tmux will crash). GitHub
issue 2188.
2020-04-30 15:20:08 +01:00
Nicholas Marriott
8e01221d02 Allow formats for message-style. 2020-04-30 14:59:58 +01:00
Nicholas Marriott
272f3dbf2e Use format for status-style. 2020-04-30 14:56:46 +01:00
nicm
048f1ff18a Do not remove the automatic-rename option from the global set, only from
the window (it must stay in the global set or tmux will crash). GitHub
issue 2188.
2020-04-30 13:31:22 +00:00
Nicholas Marriott
66bab1f6cf Complete partial window indexes properly. 2020-04-30 13:05:21 +01:00
Nicholas Marriott
25487757bc Add -W and -T flags to command-prompt to only complete a window and a target. 2020-04-30 12:02:21 +01:00
Nicholas Marriott
5af6943940 Complete aliases as well as commands. 2020-04-29 19:55:20 +01:00
Nicholas Marriott
7324442b42 Add to CHANGES. 2020-04-29 19:48:26 +01:00
Nicholas Marriott
6f700904a9 Copy mode search improvements:
- Add styles for the search marking styles (copy-mode-match-style and
  copy-mode-current-match-style).

- Show the current match (the one with the cursor on it) in a different style.

- Copying without a selection will copy the current match if there is one.
2020-04-29 18:08:21 +01:00
Nicholas Marriott
881b8e9bb5 Handle cells outside any pane correctly. 2020-04-29 16:50:20 +01:00
Nicholas Marriott
a9743fa047 Did not mean to commit this bit. 2020-04-29 15:27:38 +01:00
Nicholas Marriott
04033add19 Close menu on backspace with TAB flag. 2020-04-29 15:26:49 +01:00
Nicholas Marriott
d9fa122fd2 Do not want -O0 by default. 2020-04-29 15:21:15 +01:00
Nicholas Marriott
fe601e5417 Update CHANGES. 2020-04-29 15:19:39 +01:00
Nicholas Marriott
b06235c345 Improve command prompt completion:
- Show a menu with completions if there are multiple.

- Don't complete argument stuff (options, layouts) at start of text.

- For -t and -s, if there is no : then complete sessions but if there is a :,
  show a menu of all windows in the session rather than trying to complete the
  window name which is a bit useless if there are duplicates.

Lots of scope for being more sophisticated left here.
2020-04-29 13:56:10 +01:00
Nicholas Marriott
7c52d702e4 Remove an unnecessary comma. 2020-04-29 08:59:20 +01:00
Nicholas Marriott
3d76748161 Need to redraw borders now when some things change. Also change default so that
the active border colour is different in a mode or with synchronize-panes on.
2020-04-29 08:55:21 +01:00
Nicholas Marriott
2d151d8ca5 Apply format to pane status line also. 2020-04-29 08:24:09 +01:00
Nicholas Marriott
24316bed49 Apply a format when redrawing pane borders. 2020-04-29 08:21:29 +01:00
Nicholas Marriott
c1acfb4341 Start with style initialized to default. 2020-04-28 17:27:07 +01:00
Nicholas Marriott
1f8256fc50 Drop having a separate type for style options and make them all strings, which
allows formats to be expanded. Any styles without a '#{' are still validated
when they are set but any with a '#{' are not. Formats are not expanded
usefully in many cases yet, that will be changed later.

To make this work, a few other changes:

- set-option -a with a style option automatically appends a ",".

- OSC 10 and 11 don't set the window-style option anymore, instead the fg and
  bg are stored in the pane struct and act as the defaults that can be
  overridden by window-style.

- status-fg and -bg now override status-style instead of trying to keep them in
  sync.
2020-04-28 13:50:07 +01:00
Nicholas Marriott
a43a156846 Call format_defaults_window for panes as well. 2020-04-28 10:53:35 +01:00
Nicholas Marriott
79b4d83952 Use a grid cell not a style for the pane style. 2020-04-27 15:15:12 +01:00
Nicholas Marriott
c30e765c7b Add some additional format helper functions. 2020-04-27 14:33:17 +01:00
Thomas Adam
e62db55713 Merge branch 'obsd-master' 2020-04-27 10:01:27 +01:00
Nicholas Marriott
266bbba484 Merge branch '3.1a-rc' 2020-04-27 09:39:17 +01:00
Nicholas Marriott
d0fa520788 Update CHANGES. 2020-04-27 09:38:04 +01:00
Nicholas Marriott
646bfe403e Do not close stdout file descriptor in control mode since it will be needed for
printing the exit messages.
2020-04-27 09:36:30 +01:00
nicm
1574126e8a Do not close the stdout file descriptor in control mode as it will be
needed for printing the exit messages. Fixes a bug when detaching with
iTerm2.
2020-04-27 08:35:09 +00:00
Nicholas Marriott
5811dd7ceb Do not close stdout file descriptor in control mode since it will be needed for
printing the exit messages.
2020-04-27 09:33:46 +01:00
Nicholas Marriott
f3d6d4e802 CUD is not a requirement and tweak some comments. 2020-04-24 16:47:38 +01:00
Nicholas Marriott
9b571dacee Instead of forbidding invalid session names, sanitize them. 2020-04-24 16:40:10 +01:00
Nicholas Marriott
527f66ed23 Instead of having a default set of terminals in terminal-overrides that get XT
added and using that as a marker for xterm(1)-like, assume that if the
terminfo(5) entry already has XT or the clear capability starts with CSI then
the terminal is VT100-like and it should be safe to send DA requests. The DA
responses trigger additional features being added.

This is all to detect extensions if terminfo(5) is wrong or inadequate. If it
fails, tmux will just fall back to using the capabilities in the terminfo(5)
entry alone.
2020-04-24 15:52:44 +01:00
Nicholas Marriott
e67d65064e rxvt needs XT also for the moment. 2020-04-24 14:20:33 +01:00
Nicholas Marriott
c107708bcc Focus reporting no longer under XT. 2020-04-24 14:20:17 +01:00
Nicholas Marriott
a477c03ad5 Do not update mode until actually drawing something. 2020-04-24 12:14:53 +01:00
Nicholas Marriott
ae73fd363b Do not redraw at all if nothing has changed. 2020-04-24 11:56:44 +01:00
Nicholas Marriott
650d38962f tmux 3.1. 2020-04-24 09:57:49 +01:00
Nicholas Marriott
bb107d2979 All of this stuff can be const. 2020-04-24 07:47:16 +01:00
Nicholas Marriott
61550ac2e0 Add feature and capabilities for focus reporting. Also document AX and XT even
though they aren't tmux's.
2020-04-24 07:37:11 +01:00
Nicholas Marriott
5d69b9c4a7 Add a feature for bracketed paste. 2020-04-24 07:13:02 +01:00
Nicholas Marriott
2d8fd35de2 Add a feature for strikethrough. 2020-04-24 06:51:15 +01:00
Nicholas Marriott
8650f44340 Move terminal features into a single file. 2020-04-24 06:40:51 +01:00
Thomas Adam
ca13208b6b Merge branch 'obsd-master' 2020-04-24 00:01:27 +01:00
jmc
18886cb510 ce examples of "Ar arg Ar arg" with "Ar arg arg" and stop the spread; 2020-04-23 21:28:09 +00:00
Nicholas Marriott
d1c1e05ea7 Update CHANGES. 2020-04-23 18:27:27 +01:00
Nicholas Marriott
d53e1fedd5 Add TMUX_SOCK like TMUX_PATH for the socket directory. 2020-04-23 18:15:02 +01:00
Nicholas Marriott
0d3fdae7b6 Build list of paths and weed out duplicates before loading configs. 2020-04-23 17:56:45 +01:00
Nicholas Marriott
f87be8d052 Add XDG_CONFIG home to the configuration search paths. 2020-04-23 17:27:39 +01:00
Nicholas Marriott
351c5423f0 time.h is needed. 2020-04-23 16:55:20 +01:00
Nicholas Marriott
ac91635f82 Add extension terminfo(5) capabilities for margins. 2020-04-23 12:12:02 +01:00
Nicholas Marriott
0c73dbb7e1 Response is iTerm2 not not ITerm2. 2020-04-23 12:12:02 +01:00
Thomas Adam
5653bc8287 Merge branch 'obsd-master' 2020-04-23 12:01:26 +01:00
nicm
766b425d05 Overrides need to be applied both before and after features in case they
change flags used to detect a feature.
2020-04-23 10:22:53 +00:00
Nicholas Marriott
c74572da92 Remove support for iTerm2's DSR 1337 extension and use the CSI > q extension
now supported by a few different terminals.
2020-04-23 10:29:03 +01:00
Thomas Adam
e94a15b3d6 Merge branch 'obsd-master' 2020-04-23 10:01:26 +01:00
Nicholas Marriott
1a612a5936 Add an attribute for ACS. 2020-04-23 07:15:17 +01:00
nicm
e25fa4ba1b Fix a couple of memory leaks, one when creating a new pane and one when
adding formats onto the queue item.
2020-04-23 05:48:42 +00:00
nicm
906dfe9f5c Fix a couple of memory leaks, one when creating a new pane and one when
adding formats onto the queue item.
2020-04-23 05:48:42 +00:00
Nicholas Marriott
106e5d07be Tweak the default choose modes formats:
- Only show pane title if it is not default and not empty.
- Add a prettier time format and use that instead of long ctime().
- Remove clutter and change the order.
2020-04-23 06:30:15 +01:00
Thomas Adam
63f2034f29 Merge branch 'obsd-master' 2020-04-23 04:01:30 +01:00
Thomas Adam
cf5f93b2b3 Merge branch 'obsd-master' 2020-04-23 02:01:33 +01:00
nicm
e46cf86d30 Improve join-pane, move-pane and break-pane:
- There is no need for join-pane and move-pane to be different.
- break-pane can just behave like move-window if the source has only one
  pane, instead of failing.
- Add -a to break-pane like move-window.

Also add missing man page bits for previous window-tree.c changes.

GitHub issue 2176.
2020-04-22 21:15:33 +00:00
nicm
950af33636 Improve join-pane, move-pane and break-pane:
- There is no need for join-pane and move-pane to be different.
- break-pane can just behave like move-window if the source has only one
  pane, instead of failing.
- Add -a to break-pane like move-window.

Also add missing man page bits for previous window-tree.c changes.

GitHub issue 2176.
2020-04-22 21:15:33 +00:00
Thomas Adam
4a31eedc26 Merge branch 'obsd-master' 2020-04-22 22:01:35 +01:00
nicm
4b21fd2ed1 Indicate the marked pane in choose mode in reverse and add key to set
and clear it (m and M) and a key to jump to the starting pane (H).
2020-04-22 21:01:28 +00:00
nicm
899b3d2436 Indicate the marked pane in choose mode in reverse and add key to set
and clear it (m and M) and a key to jump to the starting pane (H).
2020-04-22 21:01:28 +00:00
nicm
662728d6c7 Add a session_marked format like window_marked. 2020-04-22 20:47:00 +00:00
Thomas Adam
b4a21b5d80 Merge branch 'obsd-master' 2020-04-22 14:01:33 +01:00
Nicholas Marriott
bb31776dd3 Merge branch '3.1-rc' 2020-04-22 13:00:43 +01:00
Nicholas Marriott
ccd7368cc5 Update CHANGES. 2020-04-22 12:59:50 +01:00
Nicholas Marriott
ecb6db6b6a Update CHANGES. 2020-04-22 12:59:10 +01:00
Nicholas Marriott
d4826aa1aa Nope, OS X kqueue is still broken...
This reverts commit 94c90385d2.
2020-04-22 12:18:11 +01:00
Nicholas Marriott
df1bce40f0 Call the event_init wrapper again. 2020-04-22 12:09:25 +01:00
Thomas Adam
8ae3915cc2 Merge branch 'obsd-master' 2020-04-22 12:01:38 +01:00
nicm
4b5a16567a Update the cursor position when deleting lines from screens without
history, GitHub issue 2173.
2020-04-22 08:48:44 +00:00
nicm
b72498c4ff Update the cursor position when deleting lines from screens without
history, GitHub issue 2173.
2020-04-22 08:48:44 +00:00
nicm
5935100181 Change so main-pane-width and height can be given as a percentage. 2020-04-22 06:57:13 +00:00
nicm
de5163a634 Change so main-pane-width and height can be given as a percentage. 2020-04-22 06:57:13 +00:00
Thomas Adam
dd5299841a Merge branch 'obsd-master' 2020-04-21 16:01:30 +01:00
nicm
445dfa8512 Move the background colour to clear with (if any) up as well as the data
when scrolling, redraw problem reported by sthen@.
2020-04-21 13:48:56 +00:00
Thomas Adam
291b85746f Merge branch 'obsd-master' 2020-04-21 14:01:25 +01:00
Thomas Adam
2cbca7ce16 Merge branch 'obsd-master' 2020-04-21 12:01:35 +01:00
nicm
9a60d41db4 256 and RGB features can imply AX (for aixterm colours). 2020-04-21 10:37:11 +00:00
nicm
bd91015b13 256 and RGB features can imply AX (for aixterm colours). 2020-04-21 10:37:11 +00:00
Thomas Adam
985bc0ee4a Merge branch 'obsd-master' 2020-04-21 08:01:30 +01:00
nicm
18671a27b6 Turn off the block flag to reset the state or the cursor will not be
moved back to the right place.
2020-04-21 06:34:13 +00:00
nicm
57bd6e0447 Turn off the block flag to reset the state or the cursor will not be
moved back to the right place.
2020-04-21 06:34:13 +00:00
nicm
d524cb64e7 Do not clear client pane redraw flags until the redraw actually happens. 2020-04-21 06:32:40 +00:00
nicm
d0b8f5340e Do not clear client pane redraw flags until the redraw actually happens. 2020-04-21 06:32:40 +00:00
nicm
1cabccbb2b xterm* needs XT also. 2020-04-21 05:26:13 +00:00
Thomas Adam
32c3fe40eb Merge branch 'obsd-master' 2020-04-20 17:43:20 +01:00
Thomas Adam
c706aadf52 Merge branch 'obsd-master' 2020-04-20 17:42:29 +01:00
nicm
4a5182e665 Always start sync for output in panes that are not the active pane. 2020-04-20 15:49:05 +00:00
nicm
117ec1b2e6 Apply terminal-overrides after terminal detection, it always takes
precedence.
2020-04-20 15:37:32 +00:00
nicm
2083a6ea20 Change how sync works to always send the end sequence after all output
is done when we are returning to the event loop (since we always move
the cursor at that point). Also a man fix from jmc.
2020-04-20 14:59:31 +00:00
nicm
135bb1edee Change the Sync capability to be a string instead of a flag. 2020-04-20 13:38:48 +00:00
nicm
c91b4b2e14 Tidy up the terminal detection and feature code and add named sets of
terminal features, each of which are defined in one place and map to a
builtin set of terminfo(5) capabilities. Features can be specified based
on TERM with a new terminal-features option or with the -T flag when
running tmux. tmux will also detect a few common terminals from the DA
and DSR responses.

This is intended to make it easier to configure tmux's use of
terminfo(5) even in the presence of outdated ncurses(3) or terminfo(5)
databases or for features which do not yet have a terminfo(5) entry.
Instead of having to grok terminfo(5) capability names and what they
should be set to in the terminal-overrides option, the user can
hopefully just give tmux a feature name and let it do the right thing.

The terminal-overrides option remains both for backwards compatibility
and to allow tweaks of individual capabilities.

tmux already did much of this already, this makes it tidier and simpler
to configure.
2020-04-20 13:25:36 +00:00
Thomas Adam
3898d4e7c8 Merge branch 'obsd-master' 2020-04-20 12:01:32 +01:00
nicm
86862c976a Also redraw panes which aren't pane 0. Problem reported by tb@. 2020-04-20 09:07:55 +00:00
Thomas Adam
b1be668a3e Merge branch 'obsd-master' 2020-04-20 08:01:31 +01:00
nicm
b846ec2665 Only trim blank lines when the source pane is not the target pane,
otherwise the cursor moves which is a bit strange.
2020-04-20 06:08:37 +00:00
nicm
4bc0a83d51 Need to check for pane redrawing even if just the window flag is set
(the pane flag may not have been previously set to avoid looping the
windows).
2020-04-20 06:07:39 +00:00
Thomas Adam
8c9bbc3749 Merge branch 'obsd-master' 2020-04-19 00:01:31 +01:00
nicm
62ff5e4b01 The PANE_REDRAW flag bit might be needed by other panes so we can't
clear it on the first redraw, and it can't be set when we are finished
or they would be redrawn again, so if the redraw is deferred for a
client, copy the redraw flag into a separate set of bits just for that
client.
2020-04-18 21:35:32 +00:00
Thomas Adam
7da5418758 Merge branch 'obsd-master' 2020-04-18 20:01:29 +01:00
nicm
100db552d1 A resize can realloc so cannot cache the value of the list pointer. 2020-04-18 17:20:25 +00:00
Thomas Adam
2b83ee5557 Merge branch 'obsd-master' 2020-04-18 18:01:28 +01:00
nicm
deffef6f13 Reset background colour on scrolled line. 2020-04-18 15:22:05 +00:00
nicm
ea5fdd5331 There is no point in keeping a bunch of different text buffers for each
line when writing, we only need one as big as the line width - there
can't be any more text than that since newer will overwrite older.
2020-04-18 15:12:28 +00:00
Thomas Adam
2ccf15e5d8 Merge branch 'obsd-master' 2020-04-18 16:01:34 +01:00
nicm
4a93294152 Use size_t not u_int for the bytes counters and fix a const missing. 2020-04-18 14:21:39 +00:00
Thomas Adam
d55510ebc8 Merge branch 'obsd-master' 2020-04-18 12:01:31 +01:00
Nicholas Marriott
94c90385d2 Apple appear to have fixed kqueue in some OS X version (will wonder never
cease!) so use it since it appears to be faster.
2020-04-18 11:45:49 +01:00
Thomas Adam
e1799ed7c8 Merge branch 'obsd-master' 2020-04-18 10:01:31 +01:00
nicm
c87595326c Use peek line function instead of hoking in the array directly. 2020-04-18 09:00:31 +00:00
nicm
b0a37e7514 Bring back previons fix to only redraw panes that need it after a redraw
is deferred, but clear the pane flags when they are actually redrawn
rather than every time.
2020-04-18 07:32:53 +00:00
nicm
e153b928ff Add formats for pane written/skipped bytes for debugging. 2020-04-18 07:19:28 +00:00
Thomas Adam
349617a818 Merge branch 'obsd-master' 2020-04-18 08:01:37 +01:00
nicm
baf1fca273 Only update mode when actually going to redraw something. 2020-04-18 06:52:36 +00:00
nicm
1d2bd864f2 Add a flag to protect against nested syncs and add some extra logging to
redrawing.
2020-04-18 06:20:50 +00:00
nicm
d94bdf7420 Revert previous, there is still a problem. 2020-04-18 06:15:07 +00:00
nicm
5289d4ed13 When a redraw is deferred because the terminal hasn't finished reading
the data from the last one, other panes could update while waiting, so
we set the flag to redraw them all when the new redraw actually
happened. But this means a lot of redrawing panes unnecessarily if they
haven't changed - so instead set a flag to say "at least one pane needs
to be redrawed" then look at the invidual pane flags to see which ones
need it.
2020-04-18 06:10:15 +00:00
Thomas Adam
87d79e6d36 Merge branch 'obsd-master' 2020-04-18 00:01:30 +01:00
nicm
a7a9460d27 Set mode properly before and after redrawing, and don't bother
calculating cursor position if it won't be used.
2020-04-17 22:16:28 +00:00
nicm
a877a5d8c9 Do not move the cursor to the existing y position if it is invalid, go
home instead.
2020-04-17 21:33:18 +00:00
Thomas Adam
857fca1095 Merge branch 'obsd-master' 2020-04-17 18:01:30 +01:00
nicm
bbd6e899a8 There is no point allocating a new item and putting it on the list when
the whole line is cleared line, there is never any point in doing it
more than once. Instead store the background colour alone.
2020-04-17 15:44:58 +00:00
Thomas Adam
7a21e911e1 Merge branch 'obsd-master' 2020-04-17 16:01:33 +01:00
nicm
282a7a8d96 Make sure the cursor position is still on screen after we have trimmed
empty lines. Also improve some log messages.
2020-04-17 14:06:42 +00:00
Thomas Adam
abeb31dd3d Merge branch 'obsd-master' 2020-04-17 12:01:30 +01:00
nicm
7f2925a01d Support the application escape sequence mintty (means tmux doesn't have
to delay to wait for Escape).
2020-04-17 09:06:10 +00:00
Thomas Adam
413c4cfd1b Merge branch 'obsd-master' 2020-04-17 10:01:38 +01:00
nicm
5aba26f2cb Add a copy-command option and change copy-pipe and friends to pipe to it
if used without arguments, allows all copy key bindings to be changed to
pipe with one option.
2020-04-17 08:03:22 +00:00
Thomas Adam
2846be326a Merge branch 'obsd-master' 2020-04-17 00:01:35 +01:00
nicm
5f18844b32 Return to sending sync around clears. 2020-04-16 21:46:43 +00:00
nicm
d8433add47 Do not need to set up a tty context for clearing lines now. 2020-04-16 21:16:24 +00:00
nicm
d90ca7ecd6 Collect up line clears like text within the available data so we don't
need to flush everything.
2020-04-16 20:32:51 +00:00
Thomas Adam
9edef17698 Merge branch 'obsd-master' 2020-04-16 20:01:31 +01:00
nicm
c1b015f24e Log what caused a flush for better visibility on what could be improved. 2020-04-16 17:24:28 +00:00
nicm
9311ed049b Start menu with top item selected if no mouse, GitHub issue 2169. 2020-04-16 17:20:23 +00:00
Thomas Adam
21eb2ba419 Merge branch 'obsd-master' 2020-04-16 18:01:32 +01:00
nicm
2e347d6a38 Only start and stop sync for operations like clear and scroll where
there is a better chance more data will be on the way.
2020-04-16 16:13:56 +00:00
nicm
363d950ac0 Send secondary device attributes instead of primary which gives us a bit
more useful information on some terminals.
2020-04-16 15:14:25 +00:00
Thomas Adam
5e38d26257 Merge branch 'obsd-master' 2020-04-16 16:01:35 +01:00
nicm
5ec80bd249 Move the UTF-8 flag to terminal flags. 2020-04-16 14:25:35 +00:00
nicm
4744aa43af Add a helper function to get the terminal flags. 2020-04-16 14:03:51 +00:00
nicm
b2443aa2f9 Add support for the iTerm2 sychronized updates escape sequence which
drastically reduces flickering.
2020-04-16 13:35:24 +00:00
Nicholas Marriott
b3cadf8260 Fix sys_signame check. 2020-04-16 10:15:33 +01:00
Nicholas Marriott
1aa2845026 Check for sys_signame. 2020-04-16 10:08:16 +01:00
Thomas Adam
dd66ede38b Merge branch 'obsd-master' 2020-04-16 10:01:33 +01:00
nicm
a2e47b5279 Show signal name when process exits rather than number. 2020-04-16 07:28:36 +00:00
Thomas Adam
3aa1e5810c Merge branch 'obsd-master' 2020-04-16 08:01:26 +01:00
nicm
b6dfca9b4d Don't miss the last line off the screen when writing after resize, from
Anindya Mukherjee.
2020-04-16 05:22:08 +00:00
Thomas Adam
8dc06446ec Merge branch 'obsd-master' 2020-04-15 22:01:31 +01:00
nicm
fc1855f514 Clear the selection and repeat the search on refresh same as resize. 2020-04-15 19:06:49 +00:00
Thomas Adam
6d6309014e Merge branch 'obsd-master' 2020-04-15 20:01:27 +01:00
nicm
53a29a2ffa Instead of fixing with the cursor position when the copied screen is
created, resize it and let the resize/reflow code fix it up and return
it. Solves various problems with cursor position and resizing when in
copy mode. With Anindya Mukherjee.
2020-04-15 17:50:02 +00:00
Thomas Adam
ebeb457385 Merge branch 'obsd-master' 2020-04-15 18:01:27 +01:00
nicm
1e72f5ea43 Use mode-style for selected items, like choose modes. GitHub issue 2166. 2020-04-15 16:11:23 +00:00
Thomas Adam
fe1778e377 Merge branch 'obsd-master' 2020-04-15 16:01:27 +01:00
nicm
c7883d5c87 Use grid_empty_line rather than memset when adding new lines on resize.
Also remove some old test code.
2020-04-15 12:59:20 +00:00
Nicholas Marriott
c2c9b77f14 Do not use the command if the kernel didn't return the full size. 2020-04-15 13:04:53 +01:00
Thomas Adam
533c5ee7ad Merge branch 'obsd-master' 2020-04-14 22:01:27 +01:00
nicm
b9a00cbe8a Leave the cursor above empty lines. 2020-04-14 19:07:10 +00:00
nicm
e11295f42d Adjust cursor and scroll positions when entering copy mode so that the
cursor line is still visible even if the source and target panes are
different heights.
2020-04-14 18:33:01 +00:00
Thomas Adam
c68291f627 Merge branch 'obsd-master' 2020-04-14 16:01:27 +01:00
nicm
1ef9a69f4f Send keys when they are complete not before (!= vs ==). 2020-04-14 13:22:05 +00:00
Thomas Adam
6d9b3704f5 Merge branch 'obsd-master' 2020-04-14 08:01:33 +01:00
nicm
63ec791854 Provide an accessor for the running queue item and use it to not let
hooks recurse.
2020-04-14 06:00:52 +00:00
Thomas Adam
653a159225 Merge branch 'obsd-master' 2020-04-14 00:01:41 +01:00
Thomas Adam
2159ff3256 Merge branch 'obsd-master' 2020-04-13 22:01:30 +01:00
nicm
fc83517913 Missed a few warnings in previous. 2020-04-13 20:54:15 +00:00
nicm
3f7f9a0e20 Make client -c and -t handling common in cmd-queue.c and try to be
clearer about whether the client is the target client (must have a
session) or not.
2020-04-13 20:51:57 +00:00
nicm
187277eaad Add helpers for the simple case of parse string and add to command queue. 2020-04-13 18:59:41 +00:00
Thomas Adam
acc00cd13a Merge branch 'obsd-master' 2020-04-13 18:01:43 +01:00
nicm
34804f2709 When parsing strings, put all commands in one group even if there are
newlines. This means that for example bind q { a \n b } and bind q "a ;
b" are the same. Also log commands in different groups separated by ;;
rather than ; (a command list like this should never be user visible).
2020-04-13 16:19:37 +00:00
nicm
3f86d6d460 When adding a list of commands to the queue, instead of automatically
creating a new state for each group of commands, require the caller to
create one and use it for all the commands in the list. This means the
current target works even with list with multiple groups (which can
happen if they are defined with newlines).
2020-04-13 15:55:51 +00:00
Thomas Adam
0a11f1607b Merge branch 'obsd-master' 2020-04-13 16:01:46 +01:00
nicm
adb76fd1ce Move cmdq_state into cmd-queue.c. 2020-04-13 14:46:04 +00:00
nicm
9a65102bfc Rename cmdq_shared to cmdq_state which will better reflect what it is
(going to be) used for.
2020-04-13 14:04:25 +00:00
nicm
77d5b0cc53 Store a key event not a mouse event in the shared data. 2020-04-13 13:42:35 +00:00
nicm
53d6b94e8a Move the NOHOOKS flag into the shared flags. 2020-04-13 13:32:09 +00:00
Thomas Adam
8f2b5d714a Merge branch 'obsd-master' 2020-04-13 14:01:45 +01:00
nicm
04cdd03525 Also move cmdq_item and cmdq_list into cmd-queue.c (this is to make its
use more clearly defined and preparation for some future work).
2020-04-13 10:59:58 +00:00
Thomas Adam
b117c3b812 Merge branch 'obsd-master' 2020-04-13 10:30:00 +01:00
nicm
c20eb0c0ae Make struct cmd local to cmd.c and move it out of tmux.h. 2020-04-13 08:26:27 +00:00
nicm
9cbe9675ea Change so that the appropriate hooks for windows and panes belong to
pane/window options rather than all being session options. This is
useful for example to create a pane that is automatically closed on some
condition. From Anindya Mukherjee.
2020-04-13 07:25:33 +00:00
nicm
ad38ef6ff4 Print empty arguments properly. 2020-04-12 20:54:28 +00:00
nicm
de6b30a51c Mention RGB, pointed out by Jody Frankowski. 2020-04-12 20:16:36 +00:00
nicm
da4034944d Add a -f filter argument to the list commands like choose-tree. 2020-04-12 08:36:18 +00:00
nicm
756591b4ca Add a -f filter argument to the list commands like choose-tree. 2020-04-12 08:36:18 +00:00
nicm
70534cfde6 Clarify a couple of style options. 2020-04-12 08:13:41 +00:00
nicm
1c433f1354 Remove unused define, also a man fix from jmc. 2020-04-10 20:53:54 +00:00
nicm
c0602f357d Now that copy mode copies the pane content rather than keeping a
reference to it, it isn't necessary that the pane in copy mode is the
same as the one copying from. Add a -s flag to copy-mode to specify a
different pane for the source content. This means it is possible to view
two places in a pane's history at the same time in different panes, or
copy from a pane's history into an editor or shell in the same pane.

From Anindya Mukherjee.
2020-04-10 07:44:26 +00:00
nicm
a1fc8f8b23 More style nits. 2020-04-09 15:35:27 +00:00
Thomas Adam
52e3d960e7 Merge branch 'obsd-master' 2020-04-09 16:01:45 +01:00
nicm
26f5dfbe46 Fix history-bottom to use the right line when working out the length. 2020-04-09 14:30:28 +00:00
nicm
e9e5facb0e Some minor style nits. 2020-04-09 14:23:34 +00:00
nicm
b0b07fb585 Tweak how the default size is worked out so it is more obvious. 2020-04-09 13:57:18 +00:00
nicm
886fdb1f7e A couple of other redundant checks/assignments. 2020-04-09 13:56:46 +00:00
nicm
5288801d3e Do not try to use the client if the item containing it is NULL. 2020-04-09 13:54:38 +00:00
nicm
315961faec Some more, and use of wp->window before wp NULL check in format.c. 2020-04-09 13:53:50 +00:00
nicm
b96ac80901 Some unnecessary assignments and unused variables. 2020-04-09 13:52:31 +00:00
nicm
c4d0089edb Pass correct flags to fnmatch. 2020-04-09 13:49:21 +00:00
Thomas Adam
916c3787d7 Merge branch 'obsd-master' 2020-04-09 14:01:32 +01:00
Thomas Adam
9e0e860031 Merge branch 'obsd-master' 2020-04-09 13:41:59 +01:00
nicm
0e8710f507 Wait until the initial command sequence is done before sending a device
attributes request and other bits that prompt a reply from the terminal.
This means that stray relies are not left on the terminal if the command
has attached and then immediately detached and tmux will not be around
to receive them. Prompted by a problem report from espie@.
2020-04-09 12:16:16 +00:00
nicm
ff135b34a4 Mention paste at same place as copy, suggested by John Boyle. 2020-04-09 06:28:55 +00:00
nicm
5d0eb619f1 Restore pane_current_path format from portable tmux, it is no longer
used by default and is very useful.
2020-04-08 11:26:07 +00:00
nicm
d388dbdea9 Pass the cmd item to format expansion so that mouse formats work. 2020-04-08 10:58:09 +00:00
Thomas Adam
6a2f32b4fd Merge branch 'obsd-master' 2020-04-07 16:01:29 +01:00
nicm
1c8f7c1f7a Do not restore history flag if it was never set. 2020-04-07 13:55:24 +00:00
nicm
eff881b15a Do not send mouse events if the program has not requested them. 2020-04-07 13:38:30 +00:00
nicm
a2efdb21a8 Limit size to 1x1 (total size 3x3). 2020-04-07 13:33:00 +00:00
Thomas Adam
8fa0b0cd26 Merge branch 'obsd-master' 2020-04-06 20:01:33 +01:00
nicm
77b827f879 Change copy mode to make copy of the pane history so it does not need to
freeze updates (which does not play nicely with some applications, a
longstanding problem) and will allow some other changes later. From
Anindya Mukherjee.
2020-04-06 17:51:34 +00:00
Nicholas Marriott
0953b994ff Merge branch '3.1-rc' 2020-04-06 16:17:34 +01:00
Nicholas Marriott
9077b212c3 job_run needs fewer arguments. 2020-04-06 16:14:09 +01:00
Nicholas Marriott
a4e19bcd80 Various fixes for copy mode from master. 2020-04-06 16:09:49 +01:00
nicm
bc36b473f1 Check previous line rather than an extra line, from Anindya Mukherjee. 2020-04-06 16:07:20 +01:00
nicm
10975961de Only search the visible part of the history when marking (highlighting)
search terms, much faster than searching the whole history.
2020-04-06 16:06:14 +01:00
nicm
8d2af4fb54 Add a 10 second timeout to prevent searches taking too much time, from
Anindya Mukherjee.
2020-04-06 16:04:51 +01:00
nicm
ac050b2583 Stop logging the entire command queue every time we add something,
spotted by tb & sthen.
2020-04-06 16:04:10 +01:00
nicm
3234017260 Add an argument to list-commands to show only a single command. 2020-04-06 16:03:39 +01:00
nicm
938ad5a98c Use new window and new pane as well for -P to new-session or new-window. 2020-04-06 16:03:33 +01:00
Thomas Adam
71ab50eddd Merge branch 'obsd-master' 2020-04-06 04:01:42 +01:00
nicm
fccce69cf0 Add an argument to list-commands to show only a single command. 2020-04-05 08:40:31 +00:00
nicm
832b8a8cf5 Use new window and new pane as well for -P to new-session or new-window. 2020-04-03 13:54:31 +00:00
nicm
c9b9b0c7c3 Stop logging the entire command queue every time we add something,
spotted by tb & sthen.
2020-04-03 12:59:22 +00:00
nicm
b65eab5505 Check previous line rather than an extra line, from Anindya Mukherjee. 2020-04-03 05:18:02 +00:00
Thomas Adam
450315aa74 Merge branch 'obsd-master' 2020-04-02 20:01:26 +01:00
nicm
a20d96000e Only search the visible part of the history when marking (highlighting)
search terms, much faster than searching the whole history.
2020-04-02 17:03:10 +00:00
Thomas Adam
9bcf5c0b90 Merge branch 'obsd-master' 2020-04-02 08:01:29 +01:00
nicm
90f4e149c1 Add a W position to display-menu -y to use the line above (or below) the
status line containing the window list. Leave S meaning above (or below)
all status lines. GitHub issue 2145.
2020-04-02 05:35:15 +00:00
Thomas Adam
7e6db00dd2 Merge branch 'obsd-master' 2020-04-01 14:01:25 +01:00
nicm
05a15215c5 Do not ignore triple-click and send to pane. 2020-04-01 11:47:44 +00:00
Thomas Adam
66db12db31 Merge branch 'obsd-master' 2020-04-01 12:01:27 +01:00
nicm
567b27e10a Add a 10 second timeout to prevent searches taking too much time, from
Anindya Mukherjee.
2020-04-01 09:36:37 +00:00
Nicholas Marriott
faf2ed48fb Merge branch '3.1-rc' 2020-04-01 10:10:48 +01:00
Nicholas Marriott
9f378a163f 3.1-rc4. 2020-04-01 10:09:49 +01:00
nicm
a5922546ac Do not go down the regex search path (which is expensive because we need
to convert the grid data into a string for regexec and reverse it to
find the grid position) if the search string does not contain any regex
special characters.
2020-04-01 10:09:03 +01:00
nicm
3476eccf48 Use a comparison to check for wrap and avoid an expensive modulus. 2020-04-01 10:08:54 +01:00
nicm
0dbf414578 Performance improvements for regex searching, most notably:
- Use the grid data directly instead of copying it.

- Special case the most typical one byte character cells and use memcmp
  for multiple bytes instead of a handrolled loop.

- Hoist regcomp out of the loop into the calling functions.

GitHub issue 2143.

Also a man page from from jmc@.
2020-04-01 10:08:39 +01:00
nicm
8dedccaa20 Add non-regex search variants to avoid the performance cost for people
with large histories or long lines.
2020-04-01 10:08:09 +01:00
nicm
dd2fdcda79 Support mouse in popups. 2020-04-01 09:05:27 +00:00
Thomas Adam
e54d4e7fe0 Merge branch 'obsd-master' 2020-04-01 10:01:30 +01:00
Nicholas Marriott
0ced25ce50 Fix configure.ac. 2020-04-01 09:30:29 +01:00
Nicholas Marriott
1d4cdbc227 Merge branch '3.1-rc' 2020-04-01 09:30:12 +01:00
Nicholas Marriott
e5fd85415d Update CHANGES. 2020-04-01 09:29:44 +01:00
Nicholas Marriott
b8356c650a Update CHANGES. 2020-04-01 09:29:02 +01:00
nicm
cd30633d10 Do not go down the regex search path (which is expensive because we need
to convert the grid data into a string for regexec and reverse it to
find the grid position) if the search string does not contain any regex
special characters.
2020-04-01 08:07:05 +00:00
nicm
b66d62d2d0 Do not go down the regex search path (which is expensive because we need
to convert the grid data into a string for regexec and reverse it to
find the grid position) if the search string does not contain any regex
special characters.
2020-04-01 08:07:05 +00:00
nicm
c129ed3233 Use a comparison to check for wrap and avoid an expensive modulus. 2020-04-01 07:52:07 +00:00
nicm
46092f2760 Use a comparison to check for wrap and avoid an expensive modulus. 2020-04-01 07:52:07 +00:00
nicm
89d2a20e56 Performance improvements for regex searching, most notably:
- Use the grid data directly instead of copying it.

- Special case the most typical one byte character cells and use memcmp
  for multiple bytes instead of a handrolled loop.

- Hoist regcomp out of the loop into the calling functions.

GitHub issue 2143.

Also a man page from from jmc@.
2020-04-01 07:35:10 +00:00
nicm
46ed81fc45 Performance improvements for regex searching, most notably:
- Use the grid data directly instead of copying it.

- Special case the most typical one byte character cells and use memcmp
  for multiple bytes instead of a handrolled loop.

- Hoist regcomp out of the loop into the calling functions.

GitHub issue 2143.

Also a man page from from jmc@.
2020-04-01 07:35:10 +00:00
Thomas Adam
bb6630af31 Merge branch 'obsd-master' 2020-04-01 00:01:25 +01:00
Thomas Adam
dfd29977e0 Merge branch 'obsd-master' 2020-03-31 20:01:34 +01:00
nicm
38f1546a66 Add a way to mark environment variables as "hidden" so they can be used
by tmux but are not passed into the environment of new panes.
2020-03-31 17:14:40 +00:00
nicm
cc8b41f294 Add a way to mark environment variables as "hidden" so they can be used
by tmux but are not passed into the environment of new panes.
2020-03-31 17:14:40 +00:00
nicm
e221ef203c Add a -T flag to resize-pane to trim lines below the cursor, moving
lines out of the history. GitHub issue 2134.
2020-03-31 17:13:20 +00:00
nicm
e6cddcf752 Add a -T flag to resize-pane to trim lines below the cursor, moving
lines out of the history. GitHub issue 2134.
2020-03-31 17:13:20 +00:00
nicm
e6d1b6770c Add non-regex search variants to avoid the performance cost for people
with large histories or long lines.
2020-03-31 16:53:23 +00:00
nicm
2624edde46 Add non-regex search variants to avoid the performance cost for people
with large histories or long lines.
2020-03-31 16:53:23 +00:00
Thomas Adam
0bb1a50b88 Merge branch 'obsd-master' 2020-03-31 16:01:29 +01:00
nicm
2ca95840d1 Add session_path from Chris Ruegge in GitHub issue 2142. 2020-03-31 11:58:05 +00:00
nicm
2a4714e76b Add session_path from Chris Ruegge in GitHub issue 2142. 2020-03-31 11:58:05 +00:00
nicm
0dd4977d5c Add a "second click" key type which is fired for the second click of a
double click, even if the timer hasn't expired to confirm it isn't
actually a triple click. Provides a way for people who don't care about
triple clicks or can make their commands have no side effects to avoid
the double click timer delay.
2020-03-31 11:38:35 +00:00
nicm
01b3bb8e2c Add a "second click" key type which is fired for the second click of a
double click, even if the timer hasn't expired to confirm it isn't
actually a triple click. Provides a way for people who don't care about
triple clicks or can make their commands have no side effects to avoid
the double click timer delay.
2020-03-31 11:38:35 +00:00
Thomas Adam
c9cd8f9b5d Merge branch 'obsd-master' 2020-03-31 10:01:29 +01:00
nicm
3bbd66c013 Move alternate screen into the screen rather than the pane. 2020-03-31 07:00:34 +00:00
nicm
eedf059d00 Detach reply escape sequences from the pane so they work in popups. 2020-03-31 06:35:38 +00:00
Thomas Adam
588865152a Merge branch 'obsd-master' 2020-03-30 18:01:28 +01:00
nicm
1fb504d0d5 Tweak key numbers to avoid some special keys crossing over with modifier bits. 2020-03-30 16:16:48 +00:00
nicm
34de379c7d Add to rather than replace flags with -c. 2020-03-30 15:49:23 +00:00
Nicholas Marriott
a46916b452 Tweak text. 2020-03-30 14:18:29 +01:00
Nicholas Marriott
df633c527d Add to CHANGES. 2020-03-30 14:17:58 +01:00
Thomas Adam
aa264ae568 Merge branch 'obsd-master' 2020-03-30 12:01:25 +01:00
Thomas Adam
ecde339f59 Merge branch 'obsd-master' 2020-03-30 10:01:27 +01:00
nicm
c713b65b9e Do not check flags after the popup struct has been freed. 2020-03-30 07:42:44 +00:00
nicm
586cafff0f Do not check flags after the popup struct has been freed. 2020-03-30 07:42:44 +00:00
Thomas Adam
5aa9e425b4 Merge branch 'obsd-master' 2020-03-28 16:01:24 +00:00
Thomas Adam
374f5ea60c Merge branch 'obsd-master' 2020-03-28 14:01:28 +00:00
Thomas Adam
88ca500546 Merge branch 'obsd-master' 2020-03-28 10:01:27 +00:00
nicm
6d0376a679 Change default position for menu and popup to centre rather than top left. 2020-03-28 09:55:30 +00:00
nicm
8036d0f834 Change default position for menu and popup to centre rather than top left. 2020-03-28 09:55:30 +00:00
nicm
852a2f2e1f Make two -E only close popup automatically if the command exited with 0. 2020-03-28 09:51:12 +00:00
nicm
593fddf84b Make two -E only close popup automatically if the command exited with 0. 2020-03-28 09:51:12 +00:00
nicm
4346098e97 Fix how popup height is calculated to take embedded newlines into account. 2020-03-28 09:39:44 +00:00
nicm
e0b17e796b Add formats for top paste buffer by default. Also a tmux.1 fix from jmc. 2020-03-28 09:39:27 +00:00
Thomas Adam
f986539e3c Merge branch 'master' of github.com:tmux/tmux 2020-03-26 11:12:18 +00:00
Thomas Adam
8a57d14f4b Merge branch 'obsd-master' 2020-03-26 11:11:37 +00:00
Nicholas Marriott
75a93207d4 Update capture-pane test, from Johannes Altmanninger. 2020-03-26 10:16:05 +00:00
nicm
55b14cdc6a Add support for overlay popup boxes to show text or output temporarily
above the normal layout. These work similarly to menus and are created
with the display-popup command.
2020-03-24 08:09:43 +00:00
nicm
8a838b0372 Add support for overlay popup boxes to show text or output temporarily
above the normal layout. These work similarly to menus and are created
with the display-popup command.
2020-03-24 08:09:43 +00:00
Thomas Adam
f652d777a6 Merge branch 'obsd-master' 2020-03-21 16:01:25 +00:00
Thomas Adam
5123bb7db4 Merge branch 'obsd-master' 2020-03-21 14:01:27 +00:00
nicm
edca27ae45 AIX colours are always stored as 90-97, not 100-107. From Johannes
Altmanninger.
2020-03-21 13:51:30 +00:00
nicm
af6ae35900 Set end position correctly, GitHub issue 2129 from Anindya Mukherjee. 2020-03-21 13:19:56 +00:00
nicm
8828b958f0 Break code to convert an argument as a percentage into a common function. 2020-03-21 13:16:15 +00:00
nicm
5aeab5ab40 Preserve exit status from run-shell and pass to the client. 2020-03-21 13:15:38 +00:00
Thomas Adam
c6d4baa4e5 Merge branch 'obsd-master' 2020-03-20 22:01:26 +00:00
nicm
9a55f65702 Fix select-word when not on a word, from Anindya Mukherjee. 2020-03-20 20:12:39 +00:00
Thomas Adam
e4efd59fe0 Merge branch 'obsd-master' 2020-03-20 20:01:34 +00:00
nicm
1a4e64ba69 Apply same menu items to view mode like copy mode. 2020-03-20 18:35:53 +00:00
nicm
7c25f22074 Similarly, disable zoom if only one pane. 2020-03-20 18:22:37 +00:00
nicm
b66501df0c Put swap down back in the right place. 2020-03-20 18:20:58 +00:00
nicm
4d6805284b Disable swap entries if nothing to swap with. 2020-03-20 18:19:22 +00:00
nicm
68cf61aa46 Still want the per-mode menus outside copy mode. 2020-03-20 18:11:56 +00:00
nicm
005cd48620 Oops, typo in key binding. 2020-03-20 18:05:22 +00:00
Thomas Adam
9894e50c42 Merge branch 'obsd-master' 2020-03-20 18:01:25 +00:00
nicm
06c3079d66 Make the mouse_word and mouse_line formats work in copy mode and enable
the default pane menu in copy mode.
2020-03-20 17:59:39 +00:00
nicm
7bbca49395 Fix positioning of menu in choose modes and a couple of keys in tree mode. 2020-03-20 17:26:14 +00:00
Thomas Adam
5b71943f89 Merge branch 'obsd-master' 2020-03-20 14:01:26 +00:00
nicm
a3ff5a9e25 select_word_end needs to forward no_reset flag or select-word selects
too much.
2020-03-20 13:12:04 +00:00
Thomas Adam
159e648ccb Merge branch 'obsd-master' 2020-03-20 08:01:26 +00:00
nicm
c3e96cce4e Another fix to make other-end forget the selection mode, from Anindya Mukherjee. 2020-03-20 06:09:19 +00:00
Thomas Adam
35c4897d8f Merge branch 'obsd-master' 2020-03-19 16:01:29 +00:00
nicm
74ed17d41b Little bit of tidying. 2020-03-19 14:23:58 +00:00
Nicholas Marriott
c15396459b No util.h. 2020-03-19 14:06:37 +00:00
nicm
de34436d4c Change input path so it doesn't require a pane. 2020-03-19 14:03:48 +00:00
Thomas Adam
17e4f2394a Merge branch 'obsd-master' 2020-03-19 14:01:31 +00:00
nicm
ce61bf931b Do not set the history flag if there is no history. 2020-03-19 13:46:10 +00:00
nicm
e8273a993e Add a flag to run a background process in a pty as well, not used for
anything yet.
2020-03-19 13:43:18 +00:00
nicm
581ed718e7 Add C position for terminal centre with display-menu -x and -y. 2020-03-19 13:32:49 +00:00
nicm
2cd8ea7680 Various fixes to copying with select-word and select-line, including
making it consistent with keys and with the mouse, and using other-end.
From Anindya Mukherjee.
2020-03-19 13:28:52 +00:00
Thomas Adam
7595b22e72 Merge branch 'obsd-master' 2020-03-18 10:01:26 +00:00
nicm
7b0e688a96 Break position calculation into a helper function. 2020-03-18 09:13:49 +00:00
Nicholas Marriott
af4b62d10b 3.1-rc3. 2020-03-18 07:55:33 +00:00
nicm
0c06409c9d getopt is not required to set optarg to NULL when there is no argument
and some do not, so set it explicitly each time.
2020-03-18 07:54:37 +00:00
Thomas Adam
18cfd9befa Merge branch 'obsd-master' 2020-03-17 18:01:27 +00:00
Nicholas Marriott
76f373ab35 Merge branch '3.1-rc' 2020-03-17 16:17:09 +00:00
nicm
617136c234 Turn off mouse mode 1003 as well as the rest when exiting. 2020-03-17 16:16:23 +00:00
nicm
f16085a362 Fix C-Space key string. 2020-03-17 16:16:09 +00:00
nicm
4ffbebedce Terminate the output buffer for control mode output - it is now used as
a string. GitHub issue 2114.
2020-03-17 16:14:51 +00:00
nicm
c0d74661b7 Do not attempt to close a NULL pane when failing to create a new one. 2020-03-17 16:14:25 +00:00
Nicholas Marriott
b21a9b1c4e getopt varies too much between platforms, and we already use compat/getopt.c
for Linux so just use it everywhere.
2020-03-17 16:14:12 +00:00
Nicholas Marriott
80f20b8e4e getopt varies too much between platforms, and we already use compat/getopt.c
for Linux so just use it everywhere.
2020-03-17 16:07:06 +00:00
nicm
bd0342b0a7 getopt is not required to set optarg to NULL when there is no argument
and some do not, so set it explicitly each time.
2020-03-17 16:02:38 +00:00
Thomas Adam
5717633cf5 Merge branch 'obsd-master' 2020-03-17 14:01:25 +00:00
nicm
1ddc128860 Do not return early if no bits changed because may still need to change the style. 2020-03-17 12:20:12 +00:00
Thomas Adam
0610f66fa9 Merge branch 'obsd-master' 2020-03-17 12:01:28 +00:00
nicm
115bb33257 Ignore default-shell (and use /bin/sh) if it invalid not just if it is
tmux itself, also refuse to set the option to something invalid in the
first place. GitHub issue 2120.
2020-03-17 11:10:12 +00:00
Thomas Adam
71eb965dd9 Merge branch 'obsd-master' 2020-03-16 20:01:24 +00:00
nicm
fb396286ff Do not attempt to close a NULL pane when failing to create a new one. 2020-03-16 18:08:39 +00:00
Thomas Adam
c18a46cf56 Merge branch 'obsd-master' 2020-03-16 16:01:26 +00:00
Nicholas Marriott
62c646ac32 Add couple of CHANGES tweaks. 2020-03-16 15:13:35 +00:00
Nicholas Marriott
372841f70a Add to CHANGES. 2020-03-16 15:12:20 +00:00
Nicholas Marriott
69eff51538 Add. 2020-03-16 15:11:34 +00:00
nicm
7021757c9d Adjust selection correctly when scrolling, from Anindya Mukherjee. 2020-03-16 14:17:56 +00:00
Thomas Adam
cae2dfc95a Merge branch 'obsd-master' 2020-03-16 12:01:26 +00:00
nicm
37b7a29cca VTE treats each mouse mode bit as independent, so turning off 1000
doesn't also turn off 1001, so don't rely on that behaviour. GitHub
issue 2116.
2020-03-16 10:49:06 +00:00
Thomas Adam
45be93f604 Merge branch 'obsd-master' 2020-03-16 10:01:27 +00:00
nicm
7cae4e8e89 Turn off mouse mode 1003 as well as the rest when exiting. 2020-03-16 09:18:47 +00:00
nicm
7815b30c7d Terminate the output buffer for control mode output - it is now used as
a string. GitHub issue 2114.
2020-03-16 09:12:44 +00:00
nicm
9abeff7f0b FIx type for %u, from Thomas Adam. 2020-03-16 08:23:24 +00:00
Thomas Adam
f584fe1b00 Merge branch 'obsd-master' 2020-03-16 08:01:27 +00:00
nicm
d162ff48f3 Send mouse down event immediately rather than waiting for double click
to finish which would now mean it was out of order. Reported by Mark
Kelly.
2020-03-16 06:12:42 +00:00
Thomas Adam
55aeaffb1a Merge branch 'obsd-master' 2020-03-15 22:01:27 +00:00
nicm
882d0b785d Reset selection flag when clearing or stopping selection, from Mark
Kelly.
2020-03-15 20:44:19 +00:00
nicm
fa3871b1be Fix C-Space key string. 2020-03-15 20:35:52 +00:00
Thomas Adam
c859748210 Merge branch 'obsd-master' 2020-03-13 08:01:24 +00:00
nicm
fa36e9bc88 Do not add a reference to the session if no session is present. 2020-03-13 06:19:33 +00:00
Thomas Adam
c91a0948e3 Merge branch 'obsd-master' 2020-03-12 16:01:28 +00:00
Thomas Adam
6385bd1e08 Merge branch 'obsd-master' 2020-03-12 14:01:29 +00:00
nicm
6571dd50f8 Tidy up the default mouse key bindings and:
- Add double and triple click bindings to copy a word or line outside
  copy mode. The text is selected for a short period to show what has
  been copied. This is in line with the existing mouse selection where
  the text is copied and the selection is cleared when the mouse button
  is released.

- Change the existing double and triple click bindings in copy mode to
  behave in the same way.

- Add a button 2 binding to paste the top buffer.
2020-03-12 13:48:32 +00:00
nicm
516f6099fc Add a -d flag to run-shell to wait for delay before running the command,
also allow run-shell to accept no command to just delay.
2020-03-12 13:25:45 +00:00
nicm
7863445e5d Add a copy-mode -H flag to hide the position marker in the top right. 2020-03-12 13:19:20 +00:00
nicm
f7bc753442 Change how double and triple clicks works so that one or the other is
fired - a double click is no longer triggered on the way to a triple
click.
2020-03-12 13:16:16 +00:00
Thomas Adam
5625c62044 Merge branch 'obsd-master' 2020-03-12 12:01:25 +00:00
Thomas Adam
1a2e66f345 Merge branch 'obsd-master' 2020-03-12 10:01:25 +00:00
nicm
b8b48e2e37 Add C-g to cancel command prompt with vi(1) keys as well as emacs, and q
in command mode.
2020-03-12 09:49:43 +00:00
nicm
2a5702a936 When the server socket is given by the user with -S, create it with
umask 177 instead of 117 because it may not be in a safe directory like
the default directory in /tmp. The user can chmod it more open after it
is created if they want.
2020-03-12 09:26:34 +00:00
Thomas Adam
39dc809751 Merge branch 'obsd-master' 2020-03-11 20:01:26 +00:00
nicm
4eba98313c Start a new selection if outside the existing selection after a word has
been selected. From Anindya Mukherjee.
2020-03-11 18:46:42 +00:00
Nicholas Marriott
e4898de98d Only need one lm. 2020-03-11 18:41:14 +00:00
Thomas Adam
256f7e8f38 Merge branch 'master' of github.com:tmux/tmux 2020-03-11 17:24:42 +00:00
Thomas Adam
e512a3642a Merge branch 'obsd-master'
Also add a check for -lm via AC_SEARCH_LIBS in configure.ac for
portablility fixes.
2020-03-11 17:23:38 +00:00
Nicholas Marriott
6d9beccb41 Will need fmod. 2020-03-11 16:33:55 +00:00
Nicholas Marriott
8d1d7fd775 Lock much more quickly. 2020-03-11 14:41:25 +00:00
nicm
c820585dd0 Add some number operators for formats, from Tyler Culp. 2020-03-11 14:17:55 +00:00
Nicholas Marriott
07bf5cbd27 3.2 next. 2020-03-11 06:41:13 +00:00
Nicholas Marriott
444e9f3c58 Bump 3.1-rc up to master. 2020-03-11 06:38:43 +00:00
Thomas Adam
59cb022c42 Merge branch 'obsd-master' 2020-03-07 12:01:25 +00:00
nicm
2991f4aad0 Use correct width of right marker so it doesn't draw over status right
when more than one character. Reported by Tyler Culp.
2020-03-07 10:58:32 +00:00
Thomas Adam
9e4d0b2b6d Merge branch 'obsd-master' 2020-03-06 18:01:26 +00:00
nicm
add75a06cd Update latest client for target session on switch-client. 2020-03-06 15:35:03 +00:00
Thomas Adam
ccd24c9cb2 Merge branch 'obsd-master' 2020-03-02 23:09:48 +00:00
nicm
8be179de46 Use current session for cwd of new sessions, not the new session which
doesn't have one yet. GitHub issue 2091.
2020-03-02 08:30:30 +00:00
nicm
f65b9c0d36 Change mouse selection so that after selecting a word, dragging selects
only words and similar for lines. From Anindya Mukherjee.
2020-02-24 09:53:59 +00:00
Nicholas Marriott
549b3599ef Update CHANGES. 2020-02-20 20:42:26 +00:00
Thomas Adam
4694afbed4 Merge branch 'obsd-master' 2020-02-20 10:01:29 +00:00
nicm
229be034fb Add selection_active format for when the selection is present but not
moving with the cursor, from Mark Kelly.
2020-02-20 07:34:57 +00:00
Thomas Adam
ba542e42b7 Merge branch 'obsd-master' 2020-02-19 16:01:27 +00:00
nicm
b20753f2a3 A few fixes to make modifier keys and dragging work - need to remove the
modifiers before checking for the dragging marker key, and apply them
before looking up the end key. Also fix key-to-string with modifiers for
special keys.
2020-02-19 14:25:00 +00:00
Nicholas Marriott
22e9cf04ca Add GitHub. 2020-02-19 06:01:54 +00:00
Nicholas Marriott
37919a6b6a This site is too stupid. 2020-02-17 12:20:53 +00:00
Nicholas Marriott
fdbc1116ef Add to FUNDING.yml. 2020-02-17 12:19:04 +00:00
Thomas Adam
0c6c8c4efc Merge branch 'obsd-master' 2020-02-15 16:01:25 +00:00
nicm
a1f6bd55b6 Add -a to list-keys to also list keys without notes with -N, suggested
by Shehu Dikko.
2020-02-15 15:08:08 +00:00
Thomas Adam
c391d50cbb Merge branch 'obsd-master' 2020-02-14 16:01:26 +00:00
nicm
58b47bf01b Fix top/bottom pane calculation with pane border status enabled,
reported by Stanislav Spassov.
2020-02-14 13:57:58 +00:00
Nicholas Marriott
9900ccd04e Change lock.yml options. 2020-02-14 11:43:12 +00:00
Nicholas Marriott
24cd726dae Add lock.yml file. 2020-02-14 11:40:32 +00:00
Thomas Adam
6c28d0dd06 Merge branch 'obsd-master' 2020-02-13 10:01:27 +00:00
nicm
f48b041cf2 Do not jump to next word end if already on a word end when selecting a
word. Fixes select-word with single character words and vi(1) keys. From
Mark Kelly.
2020-02-13 09:02:07 +00:00
Thomas Adam
a4d8437bc2 Merge branch 'obsd-master' 2020-02-11 08:01:30 +00:00
nicm
dc882adb2e Remove unused variables from Ben Boeckel, and a Pp from jmc. 2020-02-11 07:01:08 +00:00
Nicholas Marriott
470cba356d Merge branch '3.1-rc' 2020-02-07 16:43:41 +00:00
Nicholas Marriott
ae9ca620bd Remove duplicates, from Thomas Sattler. 2020-02-07 16:42:10 +00:00
Nicholas Marriott
400750bb26 Merge branch '3.1-rc' 2020-02-06 12:49:50 +00:00
nicm
096f0d35a6 Make list-keys description clearer in tmux.1 and remove an unused variable. 2020-02-06 12:49:02 +00:00
Thomas Adam
54553903de Merge branch 'obsd-master' 2020-02-05 14:01:26 +00:00
nicm
fb29242168 Make list-keys description clearer in tmux.1 and remove an unused variable. 2020-02-05 13:06:49 +00:00
Nicholas Marriott
c915cfc7e4 Merge branch '3.1-rc' 2020-02-04 07:46:59 +00:00
Nicholas Marriott
3ad4a7a571 Style nit in CHANGES. 2020-02-04 07:46:26 +00:00
Nicholas Marriott
47174f5130 Next is 3.2. 2020-02-04 07:45:29 +00:00
Nicholas Marriott
4822130b3c Merge branch '3.1-rc' 2020-02-04 07:44:49 +00:00
Nicholas Marriott
0bf153daa6 Update CONTRIBUTING.md 2020-02-04 07:43:34 +00:00
Nicholas Marriott
63a69fe085 3.1-rc. 2020-02-04 07:21:04 +00:00
Nicholas Marriott
43b36752ce Remove a duplicate entry. 2020-02-03 20:26:03 +00:00
Thomas Adam
19d5f4a0bd Merge branch 'obsd-master' 2020-02-03 14:01:25 +00:00
nicm
265164d251 Instead of passing titles through vis() which doubles backslashes, just
ignore any containing control characters or invalid UTF-8. GitHub issue 2070.
2020-02-03 13:46:27 +00:00
Thomas Adam
6f0241e645 Merge branch 'obsd-master' 2020-01-30 10:01:24 +00:00
nicm
87bcc0c7e0 Remove bind-key -c which doesn't do anything and is undocumented. 2020-01-30 08:02:25 +00:00
Thomas Adam
32be954bdd Merge branch 'obsd-master' 2020-01-29 18:01:24 +00:00
nicm
44dad918f8 Warn if a message type that is no longer used is received. 2020-01-29 16:22:32 +00:00
Thomas Adam
bc36700d05 Merge branch 'obsd-master' 2020-01-29 16:01:24 +00:00
nicm
531daba584 Do not send DA and DSR again if already have a response. 2020-01-29 15:07:49 +00:00
Thomas Adam
8b22da69b6 Merge branch 'obsd-master' 2020-01-29 10:01:25 +00:00
nicm
7a15d10bf4 Remove extra Pp (from jmc) and add a missing word. 2020-01-29 08:28:17 +00:00
Nicholas Marriott
7f3feb1896 Add to CHANGES. 2020-01-28 15:52:04 +00:00
Thomas Adam
7eada28f96 Merge branch 'obsd-master' 2020-01-28 14:01:25 +00:00
nicm
b905c5d455 If ALL clients are readonly, allow them to affect the size, suggested by Thomas Sattler. 2020-01-28 13:23:24 +00:00
nicm
e388702260 Ignore empty commands rather than adding them to the command list rather
than trying to skip them later, fixes problem reported by M Kelly.
2020-01-28 13:10:14 +00:00
Thomas Adam
60ab714451 Merge branch 'obsd-master' 2020-01-28 12:01:28 +00:00
nicm
a6129e9974 If we can identify the terminal as iTerm2 or as tmux, we can be sure
they support 256 and RGB colours, so set those flags too.
2020-01-28 11:39:51 +00:00
nicm
84995ae172 -V also needs to go in usage. 2020-01-28 11:31:31 +00:00
Nicholas Marriott
685eb381de Fix for version changes. 2020-01-28 11:28:30 +00:00
Thomas Adam
ee3d3db364 Merge branch 'obsd-master' 2020-01-28 11:17:08 +00:00
nicm
90e962fff8 Add support for the iTerm2 DSR 1337 sequence to get the terminal version. 2020-01-28 10:59:29 +00:00
nicm
f165221dc4 Reduce a difference with portable tmux by adding the -V flag and
#{version} format; on OpenBSD these just report the OpenBSD version.
2020-01-28 10:44:30 +00:00
nicm
32816eaebd Set up working directory before killing the existing pane on respawn. 2020-01-28 10:21:21 +00:00
Thomas Adam
7cdf5ee9bc Merge branch 'obsd-master' 2020-01-28 10:01:25 +00:00
nicm
24350879cd Add a define for flags meaning a client is not attached, and fix
unattached counter, reported by Thomas Sattler.
2020-01-28 08:06:11 +00:00
Thomas Adam
f3ea318a04 Merge branch 'obsd-master' 2020-01-27 10:01:27 +00:00
nicm
2c38e01b54 Expand description of start-server. 2020-01-27 09:04:47 +00:00
nicm
d0b8d036be Add support for adding a note to a key binding (with bind-key -N) and
use this to add descriptions to the default key bindings. A new -N flag
to list-keys shows key bindings with notes rather than the default
bind-key command used to create them. Change the default ? binding to
use this to show a readable summary of keys.

Also extend command-prompt to return the name of the key pressed and add
a default binding (/) to show the note for the next key pressed

Suggested by Alex Tremblay in GitHub issue 2000.
2020-01-27 08:53:13 +00:00
nicm
2e39b621c9 Change so that assignments may be specified alone - a command isn't
required. GitHub issue 2062.
2020-01-27 08:23:42 +00:00
Thomas Adam
0eb7b54731 Merge branch 'obsd-master' 2020-01-25 18:01:26 +00:00
Nicholas Marriott
74b424075c Use FNM_IGNORECASE if present, from Eric N Vander Weele in GitHub issue 2067. 2020-01-25 16:41:49 +00:00
nicm
9169ee0e87 Mention swap-window -d, GitHub issue 2068. 2020-01-25 16:40:32 +00:00
Nicholas Marriott
cdf138372c Add to CHANGES. 2020-01-14 16:02:22 +00:00
Thomas Adam
a01c9ffc6c Merge branch 'obsd-master' 2020-01-13 14:01:25 +00:00
nicm
da515570dc Stop handling DA and DSR after a second (they should be the first thing
sent) so this should be plenty.
2020-01-13 11:59:21 +00:00
Thomas Adam
8457f54edc Merge branch 'obsd-master' 2020-01-13 10:01:27 +00:00
nicm
835a6c0cf0 Be more specific in the DSR we are looking for so it doesn't get
confused with mouse sequences. Also set a flag and don't bother checking
for it if we have already seen it (same for DA), and don't check if we
never asked for it.
2020-01-13 08:12:53 +00:00
nicm
04eee2410d Treat plausible but invalid keys (like C-BSpace) as literal like any
other unrecognised string passed to send-keys. Reported by Anthony
Sottile in GitHub issue 2049.
2020-01-13 07:51:54 +00:00
Thomas Adam
3e701309a4 Merge branch 'obsd-master' 2020-01-13 00:01:24 +00:00
Thomas Adam
e9b1294331 Merge branch 'obsd-master' 2020-01-12 22:01:26 +00:00
nicm
381333c4a9 Detect iTerm2 and enable DECSLRM. 2020-01-12 22:00:20 +00:00
nicm
193e637de0 The terminal type was never as much use as I expected so remove it in
favour of a couple of flags for the features used (DECSLRM and DECFRA).
Also rename the flag for no xenl to be more obvious while here.
2020-01-12 21:07:07 +00:00
nicm
deb734c7f6 Loop over all DA features, don't skip the first. 2020-01-12 20:20:20 +00:00
Thomas Adam
61b075a263 Merge branch 'obsd-master' 2020-01-08 16:01:23 +00:00
nicm
36eb16ce7d Do not hang in format_trim_* on invalid UTF-8 characters. 2020-01-08 14:40:52 +00:00
Thomas Adam
ed16f51e26 Merge branch 'obsd-master' 2020-01-08 08:01:24 +00:00
nicm
6628e542b5 Add -Z to default switch-client command in tree mode, matches previous
behaviour.
2020-01-08 06:38:55 +00:00
Thomas Adam
507816b1d6 Merge branch 'obsd-master' 2020-01-05 22:01:24 +00:00
nicm
73b8c2ef3c Common function to free key bindings. 2020-01-05 20:39:25 +00:00
Thomas Adam
36169d8a68 Merge branch 'obsd-master' 2020-01-05 14:01:23 +00:00
nicm
7c6c66cc3c Send errors to stdout in control mode so they don't get reordered with
other output, reported by George Nachman in GitHub issue 2048.
2020-01-05 12:51:43 +00:00
Thomas Adam
6d3d47c25b Merge branch 'obsd-master' 2020-01-04 20:01:26 +00:00
nicm
1870cc70ef Add ~ to quoted characters for %%%, reported by tb@. 2020-01-04 18:01:56 +00:00
Thomas Adam
6b0091e185 Merge branch 'obsd-master' 2020-01-02 14:01:26 +00:00
nicm
a770a3bf7e Add CMD_FIND_DEFAULT_MARKED to join-pane like move-pane, from
davidegirardi in GitHub issue 2046.
2020-01-02 13:44:17 +00:00
Thomas Adam
7110226b96 Merge branch 'obsd-master' 2020-01-02 00:01:29 +00:00
nicm
ac85a3e0d3 Document client exit messages. 2020-01-01 22:12:05 +00:00
nicm
9cc603cbad Fix format expansion in window names, reported by Suraj N Kurapati. 2020-01-01 21:51:33 +00:00
Thomas Adam
566ab9aa28 Merge branch 'obsd-master' 2019-12-30 22:01:25 +00:00
nicm
206d878127 Do not let readonly clients limit the size, suggested by Max Barraclough
in GitHub issue 2042.
2019-12-30 21:24:55 +00:00
Thomas Adam
47d06cb023 Merge branch 'obsd-master' 2019-12-27 20:01:24 +00:00
nicm
4ea07716de Support regex search in copy mode, from Anindya Mukherjee in GitHub
issue 2038.
2019-12-27 18:42:49 +00:00
Thomas Adam
0aa6c6f647 Merge branch 'obsd-master' 2019-12-26 16:01:25 +00:00
nicm
88ee5b1a73 Pass correct value into iterator callback for time formats. 2019-12-26 14:48:29 +00:00
Thomas Adam
b931bbb319 Merge branch 'obsd-master' 2019-12-26 12:01:26 +00:00
nicm
817d199cbb Add a number of new formats to inspect what sessions and clients a
window is present or active in. From Tyler Culp in GitHub issue 2034.
2019-12-26 11:04:58 +00:00
Thomas Adam
67d2408279 Merge branch 'obsd-master' 2019-12-24 12:01:25 +00:00
nicm
07e37479c2 Fix name of option, GitHub issue 2030. 2019-12-24 09:57:11 +00:00
Thomas Adam
a6b1cbba02 Merge branch 'obsd-master' 2019-12-21 18:01:24 +00:00
tim
5cd00eda0b Restore source-file -q behaviour, broken in r1.42; OK nicm@ 2019-12-21 17:30:48 +00:00
Thomas Adam
745233d6a1 Merge branch 'obsd-master' 2019-12-19 10:01:26 +00:00
nicm
1764f66b7d When adding a list with multiple commands to the queue, the next item to
insert after needs to be the last one added, not the first. Reported by
Jason Kim in GitHub issue 2023.
2019-12-19 09:22:33 +00:00
Nicholas Marriott
54efe33799 Add back utempter code, reported by Peter Schellenbach. 2019-12-18 15:58:06 +00:00
Thomas Adam
d0cd68d5e4 Merge branch 'obsd-master' 2019-12-18 08:01:23 +00:00
nicm
ef54a08080 Do not rely on errno after glob(3) fails. 2019-12-18 07:48:56 +00:00
Thomas Adam
4223293ed8 Merge branch 'obsd-master' 2019-12-17 12:01:24 +00:00
nicm
f8cb759bdb Use the message that has already been built rather than the va_list. 2019-12-17 11:43:23 +00:00
Nicholas Marriott
3879509426 Define FNM_CASEFOLD to 0 for AIX, from Eric N Vander Weele. 2019-12-16 21:34:36 +00:00
Nicholas Marriott
479d411dda Remove imsg.h. 2019-12-16 20:01:26 +00:00
Thomas Adam
52b6ca5706 Merge branch 'obsd-master' 2019-12-16 18:01:31 +00:00
nicm
1bdd4828bd If /dev/fd/X is a symlink and realpath() expands symlinks, /dev/fd/X
ends up pointing to the wrong place before it is passed to the client.
The path is only used internally so there is no real need for
realpath(), remove it and move the get_path function to file.c where all
the callers are.
2019-12-16 16:39:03 +00:00
nicm
b4520aaf2c Need to include message size in the maximum buffer calculation. 2019-12-16 16:09:28 +00:00
nicm
eaa58d28dc Instead of using large buffers in imsgs, add the data or path onto the end. 2019-12-16 15:48:50 +00:00
Nicholas Marriott
e6b02dec19 Add to CHANGES. 2019-12-13 11:31:53 +00:00
Thomas Adam
00723f1f5c Merge branch 'obsd-master' 2019-12-13 10:01:24 +00:00
nicm
21f9b39f06 Show UTF-8 in choose-buffer mode. From KOIE Hidetaka. 2019-12-13 09:15:13 +00:00
Thomas Adam
e24e9867ec Merge branch 'obsd-master' 2019-12-13 08:01:24 +00:00
nicm
6ce943f4d9 Need to check in the error callback also. 2019-12-13 07:00:22 +00:00
nicm
828001ecc5 Do not spin waiting for exit, instead check in the write callback. 2019-12-13 06:55:12 +00:00
Thomas Adam
58908b045b Merge branch 'obsd-master' 2019-12-12 15:38:33 +00:00
nicm
dcf41ec927 Do not crash in tree modes if the pane is only 1 in width, reported by
KOIE Hidetaka in GitHub issue 2015.
2019-12-12 15:03:13 +00:00
nicm
2b2b193791 Add function to the right file. 2019-12-12 15:01:54 +00:00
Thomas Adam
7922f4ee7b Merge branch 'obsd-master' 2019-12-12 14:33:47 +00:00
nicm
5134666702 Change source-file to use new file code which allows it to read from
stdin.
2019-12-12 12:49:36 +00:00
nicm
268f2b047a Do not check if client is dead if it is NULL. 2019-12-12 11:51:32 +00:00
nicm
c284ebe0ad Rewrite the code for reading and writing files. Now, if the client is
not attached, the server process asks it to open the file, similar to
how works for stdin, stdout, stderr. This makes special files like
/dev/fd/X work (used by some shells). stdin, stdout and stderr and
control mode are now just special cases of the same mechanism. This will
also make it easier to use for other commands that read files such as
source-file.
2019-12-12 11:39:56 +00:00
Thomas Adam
0d99519c3d Merge branch 'obsd-master' 2019-12-11 20:01:25 +00:00
nicm
64fb7e472a Tweak previous to check the wrapped flag and stop if not set. 2019-12-11 18:30:29 +00:00
nicm
ab630f72ed Allow search across wrapped lines and fix some inconsistencies in how th
position is represented, GitHub issue 2014 from Anindya Mukherjee.
2019-12-11 18:23:34 +00:00
Thomas Adam
96abf400a5 Merge branch 'obsd-master' 2019-12-11 14:01:25 +00:00
nicm
f733d3f3eb Do not set cursor colour to default unless it has been changed, GitHub
issue 2013.
2019-12-11 12:13:37 +00:00
Nicholas Marriott
6aeb679066 Add to CHANGES. 2019-12-10 19:02:27 +00:00
Nicholas Marriott
15d7e564dd Add ~/.config/tmux/tmux.conf to the default search path for configuration files
(in Makefile.am, so portable tmux only).
2019-12-10 16:31:01 +00:00
Thomas Adam
5b2048fbb9 Merge branch 'obsd-master' 2019-12-10 16:01:25 +00:00
nicm
55eb3e4773 Make TMUX_CONF a list of files and expand leading $FOO or ~. 2019-12-10 14:22:15 +00:00
Nicholas Marriott
92ecd611f6 Check each _PATH_* define individually (Solaris has paths.h but not all of the
defines). From Eric N Vander Weele.
2019-12-03 18:53:23 +00:00
Thomas Adam
875139f5fa Merge branch 'obsd-master' 2019-12-03 12:01:26 +00:00
nicm
7826d40ff9 Style nits in function arguments. 2019-12-03 10:47:22 +00:00
Thomas Adam
edf96b06a5 Merge branch 'obsd-master' 2019-12-02 20:01:24 +00:00
nicm
ec1b8e5f05 Remove client menu, I don't think it adds anything. 2019-12-02 19:25:52 +00:00
Nicholas Marriott
2173365f4f Fix keys in CHANGES. 2019-12-01 21:15:21 +00:00
Nicholas Marriott
7836779e21 Merge branch '3.0a-rc' 2019-12-01 09:00:46 +00:00
Nicholas Marriott
25ae028695 Add to CHANGES. 2019-12-01 08:53:10 +00:00
nicm
1b0cc4503e REG_STARTEND is not portable, but it turns out we don't actually need
it. From Evan Green, GitHub issue 1982.
2019-12-01 08:52:47 +00:00
Nicholas Marriott
a52fe9cf7f Add to CHANGES. 2019-12-01 08:50:45 +00:00
Thomas Adam
866b053f25 Merge branch 'obsd-master' 2019-11-29 18:01:24 +00:00
nicm
48897fbc44 Fix respawn-pane/window if default-command is set, reported by Janos Barbero. 2019-11-29 17:21:32 +00:00
nicm
67d995d100 If a window appears in only one attached session, there is no point in
worrying about which is the latest client (there is only one).
2019-11-29 16:04:07 +00:00
nicm
ad98fad9a3 Do not crash when a format doesn't exist, reported by Thomas Sattler. 2019-11-28 22:23:40 +00:00
Thomas Adam
34084fe666 Merge branch 'obsd-master' 2019-11-28 22:01:24 +00:00
nicm
c5d74b1deb Do not crash when a format doesn't exist, reported by Thomas Sattler. 2019-11-28 21:18:38 +00:00
Nicholas Marriott
3bb11ec484 Revert "add missing definition"
This reverts commit 743939ec84.
2019-11-28 14:36:32 +00:00
Thomas Adam
743939ec84 add missing definition 2019-11-28 12:31:43 +00:00
Nicholas Marriott
e00730d149 Fix bad merge. 2019-11-28 12:30:43 +00:00
nicm
640149337f Missing after-kill-pane option. 2019-11-28 12:22:32 +00:00
Thomas Adam
5f5f029e3b Merge branch 'obsd-master' 2019-11-28 12:18:41 +00:00
nicm
fa409194d3 Missing after-kill-pane option. 2019-11-28 10:55:45 +00:00
nicm
08e2828592 Parse out DA features. 2019-11-28 10:17:22 +00:00
nicm
bc5881c4d2 Long lines and spacing fixes. 2019-11-28 09:56:25 +00:00
nicm
c416fe0da4 Add xrecallocarray. 2019-11-28 09:51:58 +00:00
nicm
9ea05b2fb3 Bump the escape sequence timeout to five seconds to allow for longer
legitimate sequences.
2019-11-28 09:50:09 +00:00
nicm
2349b1dbef Make a best effort to set xpixel and ypixel for each pane and add
formats for them.
2019-11-28 09:45:15 +00:00
nicm
067604bf8c Store xpixel/ypixel from TIOCGWINSZ and add formats. 2019-11-28 09:05:34 +00:00
nicm
7fb8eec8f1 status-left and status-right need push-default also, reported by Eric
Pruitt in GitHub issue 1989.
2019-11-28 08:38:04 +00:00
Thomas Adam
c13838436e Merge branch 'obsd-master' 2019-11-27 22:01:24 +00:00
Nicholas Marriott
7a30e6b941 Merge branch '3.0-rc' into 3.0a-rc 2019-11-27 20:55:19 +00:00
nicm
eb4d60b1ce REG_STARTEND is not portable, but it turns out we don't actually need
it. From Evan Green, GitHub issue 1982.
2019-11-27 20:54:30 +00:00
Nicholas Marriott
0134574a67 3.0a. 2019-11-27 20:49:59 +00:00
Nicholas Marriott
c942f11ba8 Use a malloc'd buffer for lsk since commands can be very long, from Gregory Pakosz. 2019-11-27 20:48:30 +00:00
nicm
5afe7eb850 Do not lazily use BUFSIZ for "I don't care what size" when building
strings because it is only guaranteed to be 256 bytes and even the
default 1024 is not always enough. Reported by Gregory Pakosz.
2019-11-27 20:48:03 +00:00
nicm
b2fd161b07 Do not crash trying to fix layout size if only one cell, from Azat Khuzhin. 2019-11-27 20:47:27 +00:00
Thomas Adam
d0655f321f Merge branch 'obsd-master' 2019-11-26 16:01:25 +00:00
nicm
fef8ee23c0 Add default # and * binding with vi(1) keys. 2019-11-26 15:35:56 +00:00
Nicholas Marriott
c16faa4fed Fixes to CHANGES. 2019-11-26 14:12:05 +00:00
Nicholas Marriott
bbcb199174 3.0 version. 2019-11-26 13:16:51 +00:00
nicm
47c0405b33 Some old tmux versions can sometimes generate layout strings which have
the incorrect size for the top cell. Previously tmux didn't care but now
that panes can be partly hidden, the size matters and is checked more
strictly. So add some code to fix up the most common problem and a
sanity check to reject layouts with any other size problems. Reported by
Aleksandrs Ledovskis in GitHub issue 1930.
2019-11-26 13:14:00 +00:00
Thomas Adam
f378a0b24d Merge branch 'obsd-master' 2019-11-26 00:01:25 +00:00
nicm
58f870ef6e Don't use motion flag uninitialized. 2019-11-25 22:38:36 +00:00
Thomas Adam
eaf526b1ea Merge branch 'obsd-master' 2019-11-25 22:01:56 +00:00
nicm
87a11a9214 Fix a warning in previous. 2019-11-25 20:43:32 +00:00
nicm
c2fde58701 Do not clear search marks on cursor movement with vi(1) keys, from Eric
Pruitt in GitHub issue 1985.
2019-11-25 20:42:18 +00:00
Thomas Adam
daa93b3fdc Merge branch 'obsd-master' 2019-11-25 16:01:27 +00:00
nicm
1ebd8c1234 Add p format modifier for padding to width. 2019-11-25 15:04:15 +00:00
nicm
5d0504ee11 Allow multiple substitutions in a single format. 2019-11-25 15:02:48 +00:00
Thomas Adam
81d4f95c2f Merge branch 'obsd-master' 2019-11-24 20:01:24 +00:00
nicm
20c1f1aec6 Only substitute patterns starting with ^ once. 2019-11-24 18:37:23 +00:00
Thomas Adam
82d0d85675 Merge branch 'obsd-master' 2019-11-20 12:01:23 +00:00
nicm
3c312a9150 Do not check the client readonly flag when there is no client, GitHub issue 1980. 2019-11-20 11:42:51 +00:00
Nicholas Marriott
0ed96c4609 Update CHANGES. 2019-11-18 12:56:24 +00:00
Thomas Adam
0d3f306c8e Merge branch 'obsd-master' 2019-11-18 10:01:25 +00:00
nicm
350a434939 Add -f for full size to join-pane (like split-window), from Theo Buehler. 2019-11-18 09:43:31 +00:00
nicm
4bc445f080 Keep modifiers on backspace when translating it. 2019-11-18 09:42:09 +00:00
Thomas Adam
dbdff241b2 Merge branch 'obsd-master' 2019-11-15 12:01:27 +00:00
nicm
5dfe9db788 Do not add path if it is NULL, duh. 2019-11-15 11:21:32 +00:00
nicm
f3dc38dcae Handle OSC 7 (a VTE extension) and put the result in a new format (pane_path). 2019-11-15 11:16:53 +00:00
Thomas Adam
48cbbb8757 Merge branch 'obsd-master' 2019-11-14 18:01:24 +00:00
nicm
1f966c495c Change window-size default from smallest to latest. 2019-11-14 16:23:23 +00:00
Thomas Adam
b67fd8f472 Merge branch 'obsd-master' 2019-11-14 16:01:25 +00:00
nicm
16b7719418 Fix parsing of DA with only one argument in the response and add 65 for VT520. 2019-11-14 15:37:19 +00:00
Thomas Adam
518a687886 Merge branch 'obsd-master' 2019-11-14 10:01:29 +00:00
nicm
2dbf062a89 Change new-session -A without a session name (that is, no -s option
also) to attach to the best existing session like attach-session rather
than creating a new one.
2019-11-14 08:00:30 +00:00
nicm
eb399e64d5 CUB and CUF are also limited by the margins so use CUP instead when
margins are enabled (we already do this for linefeed).
2019-11-14 07:56:32 +00:00
nicm
08b07b1a08 Add an option to set the key sent by backspace for those whose system
uses ^H rather than ^?. GitHub issue 1969.
2019-11-14 07:55:01 +00:00
Thomas Adam
eb215d3d3f Merge branch 'obsd-master' 2019-11-07 08:01:26 +00:00
nicm
c225262e13 Add -F flag to send-keys to expand formats in search-backward and
forward copy mode commands, this makes it easier to use the cursor_word
and cursor_line formats. From Anindya Mukherjee in GitHub issue 1964.
2019-11-07 07:11:25 +00:00
Thomas Adam
4408df1e8a Merge branch 'obsd-master' 2019-11-01 22:01:24 +00:00
nicm
bad95db878 Limit lazy resize to panes in attached sessions only - those in
unattached are likely to have been resized by something like
split-window where the user probably wants the resize to happen
immediately. GitHub issue 1963.
2019-11-01 20:26:21 +00:00
Thomas Adam
4fc8741794 Merge branch 'obsd-master' 2019-11-01 10:01:25 +00:00
nicm
d9c95c900c Handle the various different forms of rgb colour strings. 2019-11-01 09:09:53 +00:00
Nicholas Marriott
a1006db91b Create FUNDING.yml 2019-10-29 16:59:15 +00:00
Thomas Adam
57948a0dfc Merge branch 'obsd-master' 2019-10-28 10:01:25 +00:00
nicm
ccdebead79 Start with empty rather than NULL window name to avoid NULL printf if
window_name is evaluated early. Reported by Mikolaj Kucharski.
2019-10-28 09:07:59 +00:00
Thomas Adam
4e5f80dc62 Merge branch 'obsd-master' 2019-10-23 16:01:25 +01:00
nicm
6700018ce5 Document Any key, from Jason Felice. 2019-10-23 14:10:13 +00:00
Thomas Adam
b5de0a20d8 Merge branch 'obsd-master' 2019-10-23 10:01:27 +01:00
nicm
f7fb5df543 Use the existing code in format.c to add foramts for word and line at
cursor position in copy mode, from Anindya Mukherjee.
2019-10-23 07:42:05 +00:00
Thomas Adam
004ee66227 Merge branch 'obsd-master' 2019-10-19 22:01:25 +01:00
nicm
56e5067c46 Add formats for cursor and selection position in copy mode, from Jason Felice. 2019-10-19 19:20:14 +00:00
Thomas Adam
1b96902d73 Merge branch 'obsd-master' 2019-10-19 16:01:24 +01:00
nicm
2cb268d51b Do not crash trying to fix layout size if only one cell, from Azat Khuzhin. 2019-10-19 12:40:42 +00:00
Thomas Adam
fb7ce5b5d5 Merge branch 'obsd-master' 2019-10-15 10:01:28 +01:00
nicm
9fd62efcf0 Rewrite options_array_set to be clearer and remove a spurious warning
with newer GCC. From Ben Boeckel.
2019-10-15 08:30:36 +00:00
nicm
0c5e9c6efa Add support for percentage sizes for resize-pane ("-x 10%"). Also change
split-window and join-pane -l to accept similar percentages and
deprecate -p. From Anindya Mukherjee.
2019-10-15 08:25:37 +00:00
Thomas Adam
eb57cbcc29 Merge branch 'obsd-master' 2019-10-14 12:01:26 +01:00
nicm
b598bbcc2e Do not crash with pane_current_command if the pane is newly created and
has no shell set, from Thomas Adam.
2019-10-14 09:24:06 +00:00
nicm
f18cd5b19c Turn automatic-rename back on if the rename escape sequence is used with
an empty name, GitHub issue 1921.
2019-10-14 09:19:40 +00:00
nicm
bbe8ebf9c2 Some old tmux versions can sometimes generate layout strings which have
the incorrect size for the top cell. Previously tmux didn't care but now
that panes can be partly hidden, the size matters and is checked more
strictly. So add some code to fix up the most common problem and a
sanity check to reject layouts with any other size problems. Reported by
Aleksandrs Ledovskis in GitHub issue 1930.
2019-10-14 09:16:48 +00:00
nicm
68d59a16ce Memory leaks, from Igor Wong in GitHub issue 1934. 2019-10-14 08:38:07 +00:00
Thomas Adam
7323ffeef2 Merge branch 'obsd-master' 2019-10-07 10:01:24 +01:00
nicm
4e2cc0ae2a Fix respawn-pane/window if default-command is set, reported by Janos Barbero. 2019-10-07 07:14:07 +00:00
Thomas Adam
341b330a04 Merge branch 'obsd-master' 2019-10-03 14:01:23 +01:00
Thomas Adam
eeedb43ae8 Merge branch 'obsd-master' 2019-10-03 12:01:25 +01:00
nicm
02253d1e5c Use a malloc'd buffer for lsk since commands can be very long, from Gregory Pakosz. 2019-10-03 10:39:08 +00:00
nicm
f4c7141f5d Do not lazily use BUFSIZ for "I don't care what size" when building
strings because it is only guaranteed to be 256 bytes and even the
default 1024 is not always enough. Reported by Gregory Pakosz.
2019-10-03 10:24:05 +00:00
Thomas Adam
8cf21feefd Merge branch 'obsd-master' 2019-09-25 22:01:24 +01:00
nicm
bbd1032a2a Style and line length nits. 2019-09-25 19:05:59 +00:00
nicm
f0712a7569 Do not set uninitialized signal mask when creating an empty pane. 2019-09-25 15:56:53 +01:00
nicm
9d1cecea8e Up and Down are already used, use < and > instead. 2019-09-25 15:56:39 +01:00
nicm
e6995196f2 Change menu key bindings to Up and Down and also close it on any mouse
press if opened by key.
2019-09-25 15:56:30 +01:00
nicm
a74e37d32d Mouse formats don't work in copy mode so don't try to use them. 2019-09-25 15:54:52 +01:00
Thomas Adam
d89510e1aa Merge branch 'obsd-master' 2019-09-25 00:01:25 +01:00
nicm
e3359f8349 Some minor performance improvements - most notably, don't search the
input state table if the next character matches the same state as before.
2019-09-24 20:44:58 +00:00
Thomas Adam
2534aa4d2d Merge branch 'obsd-master' 2019-09-24 18:01:24 +01:00
nicm
e8adcae0f2 Couple of bits of minor cleanup. 2019-09-24 15:52:14 +00:00
nicm
48c684cbc2 Mouse formats don't work in copy mode so don't try to use them. 2019-09-24 14:50:08 +00:00
nicm
6f8f4bb206 Make select-pane -P set window-active-style also to match previous
behaviour, reported by Thomas Sattler.
2019-09-24 12:20:25 +01:00
Thomas Adam
cb1a626692 Merge branch 'obsd-master' 2019-09-24 12:01:23 +01:00
nicm
232050830b Make select-pane -P set window-active-style also to match previous
behaviour, reported by Thomas Sattler.
2019-09-24 09:58:58 +00:00
Thomas Adam
dd254b90d7 Merge branch 'obsd-master' 2019-09-23 18:01:24 +01:00
nicm
77deef733b Use the correct size for new windows when window-size is latest,
reported by Vamsi Krishna Avula in GitHub issue 1917.
2019-09-23 15:41:11 +00:00
Thomas Adam
24ab1bc714 Merge branch 'obsd-master' 2019-09-19 12:01:30 +01:00
nicm
647887b794 Add a "latest" window-size option which tries to size windows based on
the most recently used client. From Tommie Gannert in GitHub issue 1869
based on earlier changes from me.
2019-09-19 09:02:30 +00:00
nicm
d018477359 Do not use bright when emulating 256 colours on an 8 colour terminal
because it is also bold on some terminals. GitHub issue 1914.
2019-09-19 08:56:37 +00:00
Thomas Adam
827913102e Merge branch 'obsd-master' 2019-09-18 18:01:23 +01:00
nicm
1ee40307b5 Up and Down are already used, use < and > instead. 2019-09-18 15:09:05 +00:00
Thomas Adam
d30b612809 Merge branch 'obsd-master' 2019-09-18 14:01:24 +01:00
nicm
697f938355 Do not set uninitialized signal mask when creating an empty pane. 2019-09-18 11:37:58 +00:00
Thomas Adam
5ae2d421fb Merge branch 'obsd-master' 2019-09-16 16:01:23 +01:00
nicm
83be3afc54 Change menu key bindings to Up and Down and also close it on any mouse
press if opened by key.
2019-09-16 13:27:14 +00:00
Nicholas Marriott
c739772436 3.0-rc5. 2019-09-16 09:01:56 +01:00
Nicholas Marriott
7a1abd66e7 These are in 3.0 now. 2019-09-16 09:01:27 +01:00
Nicholas Marriott
d70d24d360 Merge branch '3.0-rc' 2019-09-16 09:01:09 +01:00
Nicholas Marriott
f27cac585c Add to CHANGES. 2019-09-16 09:00:56 +01:00
nicm
846d57e1b8 Make client exit if pane where input is going is closed. 2019-09-16 09:00:08 +01:00
Nicholas Marriott
54670d898f Missing headers from compat/asprintf.c, from cyyever at outlook dot com. 2019-09-16 08:59:57 +01:00
nicm
c45b255a88 It is not longer necessary to double-escape ; in %%%, problem reported
by Theo Buehler.
2019-09-16 08:59:49 +01:00
nicm
5e4f371408 Fix swap-window -d to work as intended, GitHub issue 1879 from Sam Stuewe. 2019-09-16 08:59:36 +01:00
nicm
7e4439beb7 Remove check for same size - size has already been changed so this
breaks reflow.
2019-09-16 08:58:35 +01:00
Nicholas Marriott
74f150670a In the right place. 2019-09-16 08:57:56 +01:00
Nicholas Marriott
3c355ec3b0 Add to CHANGES. 2019-09-16 08:57:22 +01:00
Thomas Adam
d346d692eb Merge branch 'obsd-master' 2019-09-16 00:01:25 +01:00
nicm
63e07b245f Add push-default and pop-default in styles to change the default colours
and attributes and use them to restore the previous behaviour of
window-status-style being the default for window-status-format in the
status line. From John Drouhard in GitHub issue 1912.
2019-09-15 21:42:57 +00:00
Thomas Adam
a5e36a4bd6 Merge branch 'obsd-master' 2019-09-13 04:01:25 +01:00
Thomas Adam
658ecb0777 Merge branch 'obsd-master' 2019-09-11 16:48:58 +01:00
nicm
a23ce1b45f Add window_marked_flag, GitHub issue 1887. 2019-09-11 06:43:17 +00:00
nicm
0feae4d8ae Make client exit if pane where input is going is closed. 2019-09-10 19:35:34 +00:00
nicm
4b7e97ba53 Set up format tree for %if, GitHub issue 1896. 2019-09-10 07:50:33 +00:00
nicm
b6b7486423 Clarify server options slightly. 2019-09-09 11:47:25 +00:00
Thomas Adam
2e90841f2e Merge branch 'obsd-master' 2019-09-09 12:02:32 +01:00
nicm
b31515fec3 Add cursor-down-and-cancel, from Mark Kelly. 2019-09-09 08:01:21 +00:00
Nicholas Marriott
9a476c5f29 Fix "make ctags", GitHub issue 1888. 2019-09-08 21:42:26 +01:00
Nicholas Marriott
5423bf6db8 Missing headers from compat/asprintf.c, from cyyever at outlook dot com. 2019-09-08 21:29:22 +01:00
Thomas Adam
648471ecee Merge branch 'obsd-master' 2019-08-29 18:02:29 +01:00
nicm
7ce8135138 It is not longer necessary to double-escape ; in %%%, problem reported
by Theo Buehler.
2019-08-29 07:13:48 +00:00
Thomas Adam
4fa1f961f3 Merge branch 'obsd-master' 2019-08-28 20:02:24 +01:00
nicm
df0334d3b3 The resize event was never deciding to actually resize the pane if there
was output in the pane faster than the timer would fire, so change how
it works to only defer the timer again if the pane was actually resized
within the last timer period. Reported by James Tai in GitHub issue
1880.
2019-08-28 07:34:32 +00:00
Thomas Adam
6640790bdc Merge branch 'obsd-master' 2019-08-27 10:02:31 +01:00
nicm
39c55d5b6f Fix swap-window -d to work as intended, GitHub issue 1879 from Sam Stuewe. 2019-08-26 16:35:41 +00:00
nicm
79f09b4d85 Add support for the SD (scroll down) escape sequence, GitHub issue 1861. 2019-08-26 17:28:24 +01:00
nicm
e85ea9f67d grid_view_delete_cells does need to clear, GitHub issue 1871. 2019-08-16 19:34:29 +01:00
Thomas Adam
2db9a18362 Merge branch 'obsd-master' 2019-08-16 17:02:29 +01:00
nicm
37583f0a69 Add a flag to reverse sort in the various choose modes, from Benjamin
Poirier in GitHub issue 1875.
2019-08-16 11:49:12 +00:00
Thomas Adam
06ad86053c Merge branch 'obsd-master' 2019-08-16 11:02:31 +01:00
nicm
5644d37876 grid_view_delete_cells does need to clear, GitHub issue 1871. 2019-08-16 08:52:25 +00:00
Thomas Adam
ed0f2831b4 Merge branch 'obsd-master' 2019-08-15 11:02:48 +01:00
nicm
21fae50089 Default to previous search string for search-forward and
search-backward, from Leah Neukirchen.
2019-08-14 10:02:24 +00:00
nicm
0f243f0388 Add -Z flag to rotate-window, select-pane, swap-pane, switch-client to
preserve zoomed state. GitHub issue 1839.
2019-08-14 09:58:31 +00:00
Thomas Adam
9b3fefc435 Merge branch 'obsd-master' 2019-08-06 07:02:33 +01:00
nicm
45f4ff5485 Add support for the SD (scroll down) escape sequence, GitHub issue 1861. 2019-08-05 06:42:02 +00:00
Nicholas Marriott
eb8eeab05e Merge branch '3.0-rc' 2019-08-01 18:52:44 +01:00
nicm
26f2740110 xterm 348 now disables margins when resized, so send DECLRMM again. 2019-08-01 18:52:33 +01:00
Thomas Adam
a2d7f380b2 Merge branch 'obsd-master' 2019-08-01 17:02:26 +01:00
nicm
c4744620af Correctly wrap search in copy mode even if at the very top left, GitHub
issue 1845.
2019-08-01 14:31:39 +00:00
nicm
3d660b0023 Select the correct word for select-word when already at the start of a
word, GitHub issue 1820.
2019-08-01 14:30:31 +00:00
nicm
49bf7dc77e xterm 348 now disables margins when resized, so send DECLRMM again. 2019-08-01 11:45:34 +00:00
Thomas Adam
11315c589a Merge branch 'obsd-master' 2019-08-01 11:02:26 +01:00
nicm
2db5f9c215 Add -N to capture-pane to preserve trailing spaces, from Leon Winter. 2019-08-01 08:42:34 +00:00
Thomas Adam
cea87758e7 Merge branch 'obsd-master' 2019-08-01 09:02:26 +01:00
nicm
58bbce09e2 Remove check for same size - size has already been changed so this
breaks reflow.
2019-08-01 07:08:13 +00:00
Thomas Adam
900e583c7a Merge branch 'obsd-master' 2019-07-30 13:02:26 +01:00
nicm
e698ee01dd Reorder some text in the windows & panes section and add some better
explanation of modes.
2019-07-30 10:10:02 +00:00
Nicholas Marriott
2dd9a4fb9c Bump version again. 2019-07-29 11:03:15 +01:00
Nicholas Marriott
b8b865fb17 Bump 3.0-rc up to master. 2019-07-29 10:53:04 +01:00
Nicholas Marriott
da552eb73b Merge branch 'master' into 3.0-rc 2019-07-29 10:51:30 +01:00
Thomas Adam
b90a9fcd13 Merge branch 'obsd-master' 2019-07-26 23:02:27 +01:00
Nicholas Marriott
e19622b8db Add to CHANGES. 2019-07-26 21:22:53 +01:00
nicm
8f40f791d9 Change "lost server" message to "server exited unexpectedly", from Neal
McBurnett in GitHub issue 1857.
2019-07-26 20:08:40 +00:00
Thomas Adam
bb9a123ddd Merge branch 'obsd-master' 2019-07-24 23:02:30 +01:00
nicm
90dba3ec66 Mark pane status line jobs with FORMAT_STATUS also so it redraws when
they finish, GitHub issue 1852.
2019-07-24 21:16:17 +00:00
Thomas Adam
47712fc113 Merge branch 'obsd-master' 2019-07-19 09:02:26 +01:00
nicm
bf6d1aeaa4 Add a few vi(1) key aliases, from D Ben Knoble. 2019-07-19 07:20:51 +00:00
nicm
df7b5292ab More man page fixes from lacygoill at lacygoill dot me, GitHub issue
1805.
2019-07-19 07:18:03 +00:00
Thomas Adam
7e7c8faa34 Merge branch 'obsd-master' 2019-07-17 21:02:26 +01:00
nicm
f6a9f6b4ad Use the right client for if -b. 2019-07-17 17:49:23 +00:00
nicm
9e7774bb96 Clear overlay on normal key press. 2019-07-17 17:46:51 +00:00
Nicholas Marriott
7c78ebce45 cc, make, libevent, ncurses are dependencies for all builds so no need to list
them for VCS build.
2019-07-17 08:57:22 +01:00
Nicholas Marriott
80b82c8d14 Mention dependencies earlier. 2019-07-17 08:56:10 +01:00
Thomas Adam
8e33cc61b1 Merge branch 'obsd-master' 2019-07-16 17:02:25 +01:00
nicm
99852f8401 Fix check for wrapping when redrawing entire lines, GitHub issue 1836. 2019-07-16 14:11:52 +00:00
Thomas Adam
b749a39cdb Merge branch 'obsd-master' 2019-07-16 13:02:24 +01:00
nicm
b89f2f28bb Fix grid clear code to correctly clear with the default background
colour rather than ending up with the used count higher than the total
size, GitHub issue 1829.
2019-07-16 10:30:56 +00:00
Thomas Adam
a786a59176 Merge branch 'obsd-master' 2019-07-15 21:02:26 +01:00
nicm
eac055bfaf Simplify code to work out if an extra line is needed in the cell. 2019-07-15 18:43:32 +00:00
nicm
6ceeceab7a Make layout_fix_offsets take a window like layout_fix_panes. 2019-07-15 18:25:07 +00:00
Thomas Adam
c9216493cf Merge branch 'obsd-master' 2019-07-10 17:02:25 +01:00
nicm
91b6145499 The command item changes so can't keep getting the target out of it, need to use
the one from the first item. Fixes crash reported by M Kelly.
2019-07-10 14:33:24 +00:00
Thomas Adam
9cbbdb90bf Merge branch 'obsd-master' 2019-07-10 13:02:26 +01:00
nicm
f4d858e7a0 Add -F to refresh-client to specify flags for control clients - one flag
at the moment, no-output which turns off forwarding pane output. From
Thomas Adam. GitHub issue 1834.
2019-07-10 11:20:10 +00:00
Thomas Adam
98ef369b27 Merge branch 'obsd-master' 2019-07-09 17:02:26 +01:00
nicm
fc2016dbb6 Add a -H flag to send-keys to send literal keys given as hex numbers
(needed for control clients to send mouse sequences). Also add some
format flags for UTF-8 and SGR mouse mode. Requested by Bradley Smith in
GitHub issues 1832 and 1833.
2019-07-09 14:03:12 +00:00
Thomas Adam
177599efb7 Merge branch 'obsd-master' 2019-07-09 15:02:25 +01:00
nicm
ad11d49d64 Do not leak empty lines, GitHub issue 1824. 2019-07-09 13:19:36 +00:00
nicm
b74b8be680 Add j and k for navigation in menus, GitHub issue 1828. 2019-07-09 12:44:47 +00:00
Thomas Adam
ab244cc7ad Merge branch 'obsd-master' 2019-07-08 23:02:26 +01:00
nicm
a4be028b76 Clear search marks before resize, GitHub issue 1823. 2019-07-08 20:29:11 +00:00
Thomas Adam
29b2d07b6b Merge branch 'obsd-master' 2019-07-08 15:02:25 +01:00
nicm
cbe781203f Use the clear history function for the 3J sequence rather than doing it manually. 2019-07-08 11:38:14 +00:00
Thomas Adam
3a4cf62aa9 Merge branch 'obsd-master' 2019-07-06 23:02:26 +01:00
nicm
ddf53d6e4e Correctly adjust mouse position if the status line is at the top and
more than one line. GitHub issue 1822.
2019-07-06 20:56:34 +00:00
nicm
3635b3cd6c Correctly clear underscore colour in grid_get_cell1, also fix struct
grid_cell to avoid padding. Fixes increased memory use reported by Suraj
N Kurapati.
2019-07-06 20:37:29 +00:00
Thomas Adam
bc112a8c89 Merge branch 'obsd-master' 2019-07-05 11:02:26 +01:00
nicm
55c694a467 Do not use uninitialized buffer name. 2019-07-05 07:52:27 +00:00
Thomas Adam
be5af704ad Merge branch 'obsd-master' 2019-07-02 23:02:26 +01:00
nicm
6a489fa7f6 Command prompt key presses need to avoid the command queue, GitHub issue
1817. Also a tmux.1 fix from jmc.
2019-07-02 20:09:19 +00:00
Thomas Adam
b9fbf02ad5 Merge branch 'obsd-master' 2019-07-01 09:02:25 +01:00
nicm
2da050413c Add a "fill" style attribute to clear the entire format drawing area in
a colour, GitHub issue 1815.
2019-07-01 06:56:00 +00:00
Thomas Adam
abcd4bd246 Merge branch 'obsd-master' 2019-06-30 21:02:26 +01:00
nicm
cf30e0f935 Do not double free window if pane fails to start. 2019-06-30 19:21:53 +00:00
Thomas Adam
68c2fc6824 Merge branch 'obsd-master' 2019-06-28 17:02:26 +01:00
deraadt
4ff7bc3eb3 When system calls indicate an error they return -1, not some arbitrary
value < 0.  errno is only updated in this case.  Change all (most?)
callers of syscalls to follow this better, and let's see if this strictness
helps us in the future.
2019-06-28 13:35:05 +00:00
Thomas Adam
b6b4f86cfc Merge branch 'obsd-master' 2019-06-28 09:02:24 +01:00
deraadt
6ce38b7395 asprintf returns -1, not an arbitrary value < 0. Also upon error the
(very sloppy specification) leaves an undefined value in *ret, so it is
wrong to inspect it, the error condition is enough.
discussed a little with nicm, and then much more with millert until we
were exasperated
2019-06-28 05:44:09 +00:00
Thomas Adam
a07df21e79 Merge branch 'obsd-master' 2019-06-27 21:02:25 +01:00
jmc
b434692db2 minor eol issues; 2019-06-27 17:29:16 +00:00
Thomas Adam
e483ce138f Merge branch 'obsd-master' 2019-06-27 17:02:26 +01:00
nicm
dae2868d12 Add support for underscore colours with Setulc capability, mostly from
Kai Moschcau.
2019-06-27 15:17:41 +00:00
nicm
5a501a8ae2 Pass keys that aren't 0-9 on to normal key processing when display-panes
is active (restores previous behaviour).
2019-06-27 15:49:43 +01:00
Thomas Adam
c4a9299956 Merge branch 'obsd-master' 2019-06-26 21:02:26 +01:00
nicm
3a6d90adad Fix a typo in window_pane_find_down (w not wp) and a missing PANE_STATUS_TOP. 2019-06-26 18:44:22 +00:00
nicm
87ea14328c Pass keys that aren't 0-9 on to normal key processing when display-panes
is active (restores previous behaviour).
2019-06-26 18:28:31 +00:00
Thomas Adam
f797ac9ff6 Merge branch 'obsd-master' 2019-06-26 15:02:26 +01:00
nicm
c599ad63f8 Log window and pane resizes. 2019-06-26 13:05:24 +00:00
nicm
80d76612b8 Fix some comments (top/bottom not left/right). 2019-06-26 13:05:06 +00:00
nicm
d83f356218 Add #define for the pane status line option position numbers. 2019-06-26 13:03:47 +00:00
Thomas Adam
a1d4bf20f7 Merge branch 'obsd-master' 2019-06-24 13:02:26 +01:00
nicm
20b938bcb1 Expand arguments to C and s format modifiers (matches m which already expands). 2019-06-24 10:04:29 +00:00
Thomas Adam
c14b0d7c00 Merge branch 'obsd-master' 2019-06-24 11:02:26 +01:00
nicm
bdab595095 Trim trailing spaces when matching. 2019-06-24 08:20:02 +00:00
Thomas Adam
50c4c5917d Merge branch 'obsd-master' 2019-06-23 13:02:26 +01:00
nicm
f1100f97f7 Do not always set scope for panes because the window check might fail,
GitHub issue 1810.
2019-06-23 10:00:29 +00:00
Thomas Adam
69a2f73449 Merge branch 'obsd-master' 2019-06-21 09:02:25 +01:00
nicm
e3c2772d2f Man page fixes from lacygoill at lacygoill dot me. 2019-06-21 07:11:01 +00:00
Thomas Adam
70775b3c28 Merge branch 'obsd-master' 2019-06-20 23:02:28 +01:00
nicm
1d8e545bc1 Add -r to find-window for regex instead of fnmatch. 2019-06-20 20:31:04 +00:00
Thomas Adam
c4a92e5799 Merge branch 'obsd-master' 2019-06-20 21:02:27 +01:00
nicm
97a317a656 Need to always check focus even if not current window. 2019-06-20 19:29:38 +00:00
nicm
cb5e681ef6 FIx return of options_scope_from_name on error. 2019-06-20 18:13:04 +00:00
Thomas Adam
5aae58295e Merge branch 'obsd-master' 2019-06-20 19:02:27 +01:00
Thomas Adam
4a44ae06bf Merge branch 'obsd-master' 2019-06-20 17:02:26 +01:00
nicm
f4e835754c Fix how regex substitution works with empty matches. 2019-06-20 15:40:14 +00:00
Thomas Adam
f8ad72b2ee Merge branch 'obsd-master' 2019-06-20 15:02:26 +01:00
nicm
fc1df91e03 allow-rename and alternate-screen can be pane options. 2019-06-20 13:40:22 +00:00
nicm
c1573727f0 Still need to walk the options tree for user options. 2019-06-20 13:39:17 +00:00
Nicholas Marriott
a0e2c1b4ca Add to CHANGES. 2019-06-20 13:08:22 +01:00
nicm
5f92f92908 Add a per-pane option set. Pane options inherit from window options (so
there should be no change to existing behaviour) and are set and shown
with set-option -p and show-options -p.

Change remain-on-exit and window-style/window-active-style to be pane
options (some others will be changed later).

This makes select-pane -P and -g unnecessary so no longer document them
(they still work) and no longer document set-window-option and
show-window-options in favour of set-option -w and show-options -w.
2019-06-20 11:59:59 +00:00
Thomas Adam
adca856806 Merge branch 'obsd-master' 2019-06-20 11:02:28 +01:00
Thomas Adam
03945276f7 Merge branch 'obsd-master' 2019-06-20 09:02:26 +01:00
nicm
c1ede507d9 Add a helper function to work out option table from name. 2019-06-20 07:41:29 +00:00
nicm
cd1fc42df6 Add a -A flag to show-options to show parent options as well. 2019-06-20 07:10:56 +00:00
nicm
ae541287d3 Expand command formats in %if and move the config file loading later (to
when the first client has identified) so all the client formats are
available, fixes problems reported by Thomas Sattler.
2019-06-20 06:51:36 +00:00
Nicholas Marriott
b3ca410bc3 Use KERN_PROC_CWD on NetBSD, from Leonardo Taccari. 2019-06-20 06:57:37 +01:00
Nicholas Marriott
ec151b79ec Merge branch '3.0-rc' 2019-06-18 19:43:20 +01:00
nicm
797042584e Handle comments more correctly inside {}, from Avi Halachmi. 2019-06-18 19:43:13 +01:00
Nicholas Marriott
df07723e20 Add a config. 2019-06-18 19:42:52 +01:00
Thomas Adam
ee9bc355f5 Merge branch 'obsd-master' 2019-06-18 13:02:28 +01:00
nicm
250fdd08be Handle comments more correctly inside {}, from Avi Halachmi. 2019-06-18 11:17:40 +00:00
nicm
9272fe36e2 Add a cmdq_continue function rather than twiddling the flag directly. 2019-06-18 11:08:42 +00:00
Thomas Adam
5895f1d9f7 Merge branch 'obsd-master' 2019-06-15 09:02:26 +01:00
Nicholas Marriott
fadbf497a4 Merge branch '3.0-rc' 2019-06-15 07:45:58 +01:00
Nicholas Marriott
748633c887 Remove a stray abort. 2019-06-15 07:45:41 +01:00
Nicholas Marriott
d53c2d0ebe Merge branch '3.0-rc' 2019-06-15 07:44:58 +01:00
Nicholas Marriott
08f55414e1 Remove cmd-list.c line in master. 2019-06-15 07:42:49 +01:00
Nicholas Marriott
7a4a286ea2 Merge branch '3.0-rc' 2019-06-15 07:38:01 +01:00
nicm
9ae658983c Do not loop forever if a menu item contains invisible characters,
reported by Thomas Sattler.
2019-06-15 07:37:44 +01:00
nicm
03da0ced46 Use the right format modifier when comparing, and remove a couple of
unused variables.
2019-06-15 06:33:48 +00:00
Thomas Adam
539a6e7fa0 Merge branch 'obsd-master' 2019-06-14 19:02:26 +01:00
nicm
c95cd9ed5e Do not loop forever if a menu item contains invisible characters,
reported by Thomas Sattler.
2019-06-14 15:35:58 +00:00
Nicholas Marriott
4c28ed4e4e Merge branch '3.0-rc' 2019-06-14 16:10:38 +01:00
Nicholas Marriott
ae83a5b010 Add to CHANGES. 2019-06-14 16:09:49 +01:00
Nicholas Marriott
29b70e2757 Merge branch '3.0-rc' 2019-06-14 16:06:20 +01:00
Nicholas Marriott
dcb2bb33a2 Merge branch '3.0-rc' 2019-06-14 16:05:26 +01:00
Nicholas Marriott
8da756c4f0 Restore missing functions. 2019-06-14 16:02:34 +01:00
Nicholas Marriott
7bb8ab1c0e Add a bit to {}. 2019-06-14 15:54:36 +01:00
Thomas Adam
5e9757b30b Merge branch 'obsd-master' 2019-06-14 15:51:09 +01:00
nicm
d1d3bbb458 Show filename with -v for source-file. 2019-06-14 13:34:45 +00:00
nicm
45203582ff 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 12:04:11 +00:00
Nicholas Marriott
4bbf941436 Merge branch '3.0-rc' 2019-06-14 10:34:05 +01:00
nicm
f35f15b107 Use the right client when working out where to save or load the buffer,
reported by kn@.
2019-06-13 21:44:13 +00:00
nicm
eef11b64e1 Do not crash if the environment variable is present but empty. 2019-06-13 21:24:09 +00:00
jmc
b8a9c740bb tweak previous; 2019-06-13 21:04:21 +00:00
nicm
26b9a8e49b Set the cursor x at the same time as changing the y or the end of line
marker may not be redrawn.
2019-06-13 20:38:05 +00:00
nicm
3e72e98e3b Add regular expression support for the format search, match and
substitute modifiers.
2019-06-13 19:46:00 +00:00
Thomas Adam
d5902eeae9 Merge branch 'obsd-master' 2019-06-12 11:02:25 +01:00
nicm
7e6a26cc9d Do not use $TMUX to find the session because for windows in multiple
sessions it is wrong as often as it is right, and for windows in one
session it is pointless. Instead check TMUX_PANE to find the pane and
look for the MRU session as usual. GitHub issue 1793.
2019-06-12 09:10:29 +00:00
nicm
b12df01861 Pass target on to new commands with if -F. 2019-06-12 08:47:07 +00:00
nicm
9d42bd328c Do not always resize the window back to its original size after applying
a layout, let the normal window resize process do it. This means windows
are not resized at all if window-size is manual, and are not resized
multiple times if later attached to a different size terminal.
2019-06-12 08:08:33 +00:00
Thomas Adam
057c04e32a Merge branch 'obsd-master' 2019-06-11 15:02:26 +01:00
Nicholas Marriott
8e971f187a Update README.md 2019-06-11 14:27:40 +01:00
Nicholas Marriott
e8814a7e93 Add to CHANGES. 2019-06-11 14:23:47 +01:00
nicm
1a9f9c09b4 Do not resize panes unless they are in an attached, active window. From
Morten M Neergaard in GitHub issue 1782.
2019-06-11 13:09:00 +00:00
Thomas Adam
d9ad461b5e Merge branch 'obsd-master' 2019-06-09 09:02:26 +01:00
nicm
915097d312 Exiting alternate screen mode should restore cursor position and
attributes even if already outside alternate screen mode. GitHub issue
1789.
2019-06-09 06:50:24 +00:00
Thomas Adam
181841fb67 Merge branch 'obsd-master' 2019-06-09 01:02:26 +01:00
nicm
43796bf131 Do not try to parse command when unsetting, GitHub issue 1788. 2019-06-08 21:48:29 +00:00
Thomas Adam
e13c1e5320 Merge branch 'obsd-master' 2019-06-07 23:02:26 +01:00
nicm
e37f34facc Do not load the config file if the server is exiting because it failed
to start, otherwise commands like lsk which start the server again can
end up looping infinitely. Also make the first client exit
correctly. Problem reported by Wael M Nasreddine.
2019-06-07 20:09:17 +00:00
Thomas Adam
c91680822d Merge branch 'obsd-master' 2019-06-05 23:02:26 +01:00
Nicholas Marriott
37bb993f53 Merge branch '3.0-rc' 2019-06-05 21:06:30 +01:00
Thomas Adam
1ec3fb5f30 Merge branch 'obsd-master' 2019-06-05 21:02:26 +01:00
nicm
8f40796f05 Add a -v flag to source-file to show the commands and line numbers. 2019-06-05 20:00:53 +00:00
nicm
09e90c1645 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 19:00:36 +00:00
Nicholas Marriott
f274b1b9d7 Merge branch '3.0-rc' 2019-06-05 15:13:56 +01:00
Thomas Adam
d3f0c72e20 Merge branch 'obsd-master' 2019-06-03 21:02:26 +01:00
nicm
4ca1de1b8b Add new-session -X and attach-session -x to send SIGHUP to parent when
detaching (like detach-client -P). From Colin Watson in GitHub issue
1773.
2019-06-03 18:28:37 +00:00
Thomas Adam
f6933e43c2 Merge branch 'obsd-master' 2019-06-02 09:02:27 +01:00
nicm
900238a306 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 07:10:15 +00:00
Thomas Adam
027a7ac829 Merge branch 'obsd-master' 2019-06-01 19:02:26 +01:00
nicm
2c6c3a1d27 If only one of -x or -y is given, use the calculated size for the
other. Pointed out by Ben Boeckel.
2019-06-01 16:21:37 +00:00
Thomas Adam
8382ae65b7 Merge branch 'obsd-master' 2019-06-01 09:02:27 +01:00
Nicholas Marriott
ec690208a3 Move link. 2019-06-01 08:07:22 +01:00
Nicholas Marriott
b28b8312f2 Mention CHANGES. 2019-06-01 08:05:55 +01:00
Nicholas Marriott
c2d79add31 Should be caps. 2019-06-01 07:28:31 +01:00
Nicholas Marriott
feff55b92f Try this instead. 2019-06-01 07:26:39 +01:00
Nicholas Marriott
3d29b97768 Link to file. 2019-06-01 07:24:57 +01:00
nicm
39ea8a2787 Need stdlib.h, from Ben Boeckel. 2019-06-01 06:20:22 +00:00
Thomas Adam
480cdedcac Merge branch 'obsd-master' 2019-06-01 01:02:25 +01:00
Nicholas Marriott
88ee5a1a00 Add a crashing config. 2019-05-31 22:50:30 +01:00
nicm
2c5f3074bc Fix warnings, from Ben Boeckel. 2019-05-31 21:41:17 +00:00
Nicholas Marriott
9d2ef8bf0d Merge branch '3.0-rc' 2019-05-31 15:18:56 +01:00
Thomas Adam
adf9e77702 Merge branch 'obsd-master' 2019-05-31 15:02:27 +01:00
nicm
82e47403c6 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 11:34:09 +00:00
Thomas Adam
41b8bb4eef Merge branch 'obsd-master' 2019-05-30 23:02:27 +01:00
nicm
b26523c26d Remove a leftover abort and some fixes from cppcheck. 2019-05-30 20:54:03 +00:00
Nicholas Marriott
200a1c62c6 Merge branch '3.0-rc' 2019-05-30 13:12:50 +01:00
Thomas Adam
2df757521a Merge branch 'obsd-master' 2019-05-30 13:02:26 +01:00
nicm
8fb796b5b3 No longer need to reduce line number by one. 2019-05-30 10:04:33 +00:00
Thomas Adam
82b25a9d62 Merge branch 'obsd-master' 2019-05-30 11:02:27 +01:00
nicm
89d2c7eb26 I had hoped that non-xenl terminals had died out, at least in fairly
modern OSs, but no - DragonFly BSD's console returns to haunt us. Fix it
at least somewhat. GitHub issue 1763.
2019-05-30 07:42:41 +00:00
Nicholas Marriott
026450c1a8 Add test for xenl terminals. 2019-05-30 07:52:24 +01:00
Nicholas Marriott
c5e2532b67 Merge branch '3.0-rc' 2019-05-29 23:04:28 +01:00
Thomas Adam
414208aab1 Merge branch 'obsd-master' 2019-05-29 23:02:25 +01:00
nicm
7dced37673 Use VIS_CSTYLE for the arguments and add the missing escapes it can
generate to the parser.
2019-05-29 20:05:14 +00:00
Nicholas Marriott
95d68fcba1 Merge branch '3.0-rc' 2019-05-29 20:43:29 +01:00
nicm
c17edd594e 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 19:34:42 +00:00
Nicholas Marriott
2ce8e0110c Don't even need this? 2019-05-29 14:32:49 +01:00
Nicholas Marriott
4425c1e1b3 Tweak again. 2019-05-29 14:24:09 +01:00
Nicholas Marriott
409d52ed41 Try OS X. 2019-05-29 14:19:37 +01:00
Thomas Adam
e90b5dcea3 Merge branch 'obsd-master' 2019-05-29 13:02:35 +01:00
Nicholas Marriott
ffcc60211d Merge branch '3.0-rc' 2019-05-29 12:13:55 +01:00
Nicholas Marriott
480ba99a16 Merge branch '3.0-rc' 2019-05-29 12:07:05 +01:00
nicm
a4424fbebf Support \ooo escapes, from Avi Halachmi. 2019-05-29 10:08:36 +00:00
Nicholas Marriott
eefbbfde77 Merge branch '3.0-rc' 2019-05-28 21:05:00 +01:00
Thomas Adam
c96957583f Merge branch 'obsd-master' 2019-05-28 21:02:28 +01:00
nicm
580cd16f4c Redraw status line if size changes, GitHub issue 1762. Also fix length
of target buffer when pasting into status line.
2019-05-28 18:53:36 +00:00
nicm
4382538e4b Do not read past the end of the argument string if it is empty. 2019-05-28 18:30:30 +00:00
Nicholas Marriott
e7a530fe4c Next will be 3.1. 2019-05-28 15:48:31 +01:00
175 changed files with 29036 additions and 9534 deletions

View File

@@ -2,13 +2,20 @@
Before opening an issue, please ensure that:
- Your problem is a specific problem or question or suggestion, not a general
complaint.
- `$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).
- Your question or issue is not covered [in the
manual](https://man.openbsd.org/tmux.1) (run `man tmux`).
- Your problem is not mentioned in [the CHANGES
file](https://raw.githubusercontent.com/tmux/tmux/master/CHANGES).
- Nobody else has opened the same issue recently.

2
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,2 @@
github: nicm
liberapay: tmux

View File

@@ -3,6 +3,9 @@
Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md
before opening an issue.
If you have upgraded, make sure your issue is not covered in the CHANGES file
for your version: https://raw.githubusercontent.com/tmux/tmux/master/CHANGES
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.

33
.github/README.md vendored
View File

@@ -14,8 +14,17 @@ 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/).
To build tmux, a C compiler (for example gcc or clang), make, pkg-config and a
suitable yacc (yacc or bison) are needed.
## Installation
### Binary packages
Some platforms provide binary packages for tmux, although these are sometimes
out of date. Examples are listed on
[this page](https://github.com/tmux/tmux/wiki/Installing).
### From release tarball
To build and install tmux from a release tarball, use:
@@ -28,9 +37,13 @@ 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.
For more detailed instructions on building and installing tmux, see
[this page](https://github.com/tmux/tmux/wiki/Installing).
### From version control
To get and build the latest from version control:
To get and build the latest from version control - note that this requires
`autoconf`, `automake` and `pkg-config`:
~~~bash
git clone https://github.com/tmux/tmux.git
@@ -39,10 +52,6 @@ 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
@@ -50,14 +59,12 @@ welcome. Please send by email to:
tmux-users@googlegroups.com
Or open a GitHub issue or pull request.
Or open a GitHub issue or pull request. **Please read [this
document](CONTRIBUTING.md) before opening an issue.**
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.
There is [a list of suggestions for contributions](https://github.com/tmux/tmux/wiki/Contributing).
Please feel free to ask on the mailing list if you're thinking of working on something or need
further information.
## Documentation
@@ -74,7 +81,7 @@ 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
For debugging, run tmux with `-v` or `-vv` to generate server and client log
files in the current directory.
## Support

10
.github/lock.yml vendored Normal file
View File

@@ -0,0 +1,10 @@
daysUntilLock: 30
skipCreatedBefore: false
exemptLabels: []
lockLabel: false
lockComment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.
setLockReason: false
#only: issues

24
.github/travis/before-install.sh vendored Normal file
View File

@@ -0,0 +1,24 @@
#!/bin/sh
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
sudo apt-get update -qq
sudo apt-get -y install bison \
autotools-dev \
libncurses5-dev \
libevent-dev \
pkg-config \
libutempter-dev \
build-essential
if [ "$BUILD" = "musl" -o "$BUILD" = "musl-static" ]; then
sudo apt-get -y install musl-dev \
musl-tools
fi
fi
if [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
sudo pkg install -y \
automake \
libevent \
pkgconf
fi

38
.github/travis/build-all.sh vendored Normal file
View File

@@ -0,0 +1,38 @@
#!/bin/sh
BUILD=$PWD/build
LIBEVENT=https://github.com/libevent/libevent/releases/download/release-2.1.11-stable/libevent-2.1.11-stab\
le.tar.gz
NCURSES=https://ftp.gnu.org/gnu/ncurses/ncurses-6.2.tar.gz
wget -4q $LIBEVENT || exit 1
tar -zxf libevent-*.tar.gz || exit 1
(cd libevent-*/ &&
./configure --prefix=$BUILD \
--enable-shared \
--disable-libevent-regress \
--disable-samples &&
make && make install) || exit 1
wget -4q $NCURSES || exit 1
tar -zxf ncurses-*.tar.gz || exit 1
(cd ncurses-*/ &&
CPPFLAGS=-P ./configure --prefix=$BUILD \
--with-shared \
--with-termlib \
--without-ada \
--without-cxx \
--without-manpages \
--without-progs \
--without-tests \
--without-tack \
--disable-database \
--enable-termcap \
--enable-pc-files \
--with-pkg-config-libdir=$BUILD/lib/pkgconfig &&
make && make install) || exit 1
sh autogen.sh || exit 1
PKG_CONFIG_PATH=$BUILD/lib/pkgconfig ./configure --prefix=$BUILD "$@"
make && make install || (cat config.log; exit 1)

25
.github/travis/build.sh vendored Normal file
View File

@@ -0,0 +1,25 @@
#!/bin/sh
sh autogen.sh || exit 1
case "$BUILD" in
static)
./configure --enable-static || exit 1
exec make
;;
all)
sh $(dirname $0)/build-all.sh
exec make
;;
musl)
CC=musl-gcc sh $(dirname $0)/build-all.sh
exec make
;;
musl-static)
CC=musl-gcc sh $(dirname $0)/build-all.sh --enable-static
exec make
;;
*)
./configure || exit 1
exec make
;;
esac

2
.gitignore vendored
View File

@@ -19,3 +19,5 @@ configure
tmux.1.*
*.dSYM
cmd-parse.c
fuzz/*-fuzzer
.dirstamp

View File

@@ -1,16 +1,88 @@
language: c
os:
- linux
- osx
- linux
- freebsd
- osx
compiler:
- gcc
- clang
- gcc
- clang
arch:
- amd64
- arm64
env:
- BUILD=
- BUILD=static
- BUILD=all
- BUILD=musl
- BUILD=musl-static
jobs:
exclude:
# Static builds are broken on OS X (by Apple)
- os: osx
compiler: gcc
env: BUILD=static
- os: osx
compiler: clang
env: BUILD=static
# No musl on FreeBSD
- os: freebsd
compiler: gcc
env: BUILD=musl
- os: freebsd
compiler: clang
env: BUILD=musl
- os: freebsd
compiler: gcc
env: BUILD=musl-static
- os: freebsd
compiler: clang
env: BUILD=musl-static
# No musl on OS X
- os: osx
compiler: gcc
env: BUILD=musl
- os: osx
compiler: clang
env: BUILD=musl
- os: osx
compiler: gcc
env: BUILD=musl-static
- os: osx
compiler: clang
env: BUILD=musl-static
# arm64 doesn't link ncurses
- os: linux
compiler: gcc
arch: arm64
env: BUILD=all
- os: linux
compiler: clang
arch: arm64
env: BUILD=all
- os: linux
compiler: gcc
arch: arm64
env: BUILD=musl
- os: linux
compiler: clang
arch: arm64
env: BUILD=musl
- os: linux
compiler: gcc
arch: arm64
env: BUILD=musl-static
- os: linux
compiler: clang
arch: arm64
env: BUILD=musl-static
before_install:
- 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
- sh .github/travis/before-install.sh
script:
- ./autogen.sh && ./configure && make
- sh .github/travis/build.sh

615
CHANGES
View File

@@ -1,4 +1,609 @@
CHANGES FROM 2.9 to 3.0
CHANGES FROM 3.2 TO 3.2a
* Add an "always" value for the "extended-keys" option; if set then tmux will
forward extended keys to applications even if they do not request them.
* Add a "mouse" terminal feature so tmux can enable the mouse on terminals
where it is known to be supported even if terminfo(5) says otherwise.
* Do not expand the filename given to -f so it can contain colons.
* Fixes for problems with extended keys and modifiers, scroll region,
source-file, crosscompiling, format modifiers and other minor issues.
CHANGES FROM 3.1c TO 3.2
* Add a flag to disable keys to close a message.
* Permit shortcut keys in buffer, client, tree modes to be configured with a
format (-K flag to choose-buffer, choose-client, choose-tree).
* Add a current_file format for the config file being parsed.
* When display-message used in config file, show the message after the config
file finishes.
* Add client-detached notification in control mode.
* Improve performance of format evaluation.
* Make jump command support UTF-8 in copy mode.
* Support X11 colour names and other colour formats for OSC 10 and 11.
* Add "pipe" variants of "copy-pipe" commands which do not copy.
* Include "focused" in client flags.
* Send Unicode directional isolate characters around horizontal pane borders if
the terminal supports UTF-8 and an extension terminfo(5) capability "Bidi" is
present.
* Add a -S flag to new-window to make it select the existing window if one
with the given name already exists rather than failing with an error.
* Add a format modifier to check if a window or session name exists (N/w or
N/s).
* Add compat clock_gettime for older macOS.
* Add a no-detached choice to detach-on-destroy which detaches only if there
are no other detached sessions to switch to.
* Add rectangle-on and rectangle-off copy mode commands.
* Change so that window_flags escapes # automatically. A new format
window_raw_flags contains the old unescaped version.
* Add -N flag to never start server even if command would normally do so.
* With incremental search, start empty and only repeat the previous search if
the user tries to search again with an empty prompt.
* Add a value for remain-on-exit that only keeps the pane if the program
failed.
* Add a -C flag to run-shell to use a tmux command rather than a shell command.
* Do not list user options with show-hooks.
* Remove current match indicator in copy mode which can't work anymore since we
only search the visible region.
* Make synchronize-panes a pane option and add -U flag to set-option to unset
an option on all panes.
* Make replacement of ##s consistent when drawing formats, whether followed by
[ or not. Add a flag (e) to the q: format modifier to double up #s.
* Add -N flag to display-panes to ignore keys.
* Change how escaping is processed for formats so that ## and # can be used in
styles.
* Add a 'w' format modifier for string width.
* Add support for Haiku.
* Expand menu and popup -x and -y as formats.
* Add numeric comparisons for formats.
* Fire focus events even when the pane is in a mode.
* Add -O flag to display-menu to not automatically close when all mouse buttons
are released.
* Allow fnmatch(3) wildcards in update-environment.
* Disable nested job expansion so that the result of #() is not expanded again.
* Use the setal capability as well as (tmux's) Setulc.
* Add -q flag to unbind-key to hide errors.
* Allow -N without a command to change or add a note to an existing key.
* Add a -w flag to set- and load-buffer to send to clipboard using OSC 52.
* Add -F to set-environment and source-file.
* Allow colour to be spelt as color in various places.
* Add n: modifier to get length of a format.
* Respond to OSC colour requests if a colour is available.
* Add a -d option to display-message to set delay.
* Add a way for control mode clients to subscribe to a format and be notified
of changes rather than having to poll.
* Add some formats for search in copy mode (search_present, search_match).
* Do not wait on shutdown for commands started with run -b.
* Add -b flags to insert a window before (like the existing -a for after) to
break-pane, move-window, new-window.
* Make paste -p the default for ].
* Add support for pausing a pane when the output buffered for a control mode
client gets too far behind. The pause-after flag with a time is set on the
pane with refresh-client -f and a paused pane may be resumed with
refresh-client -A.
* Allow strings in configuration files to span multiple lines - newlines and
any leading whitespace are removed, as well as any following comments that
couldn't be part of a format. This allows long formats or other strings to be
annotated and indented.
* Instead of using a custom parse function to process {} in configuration
files, treat as a set of statements the same as outside {} and convert back
to a string as the last step. This means the rules are consistent inside and
outside {}, %if and friends work at the right time, and the final result
isn't littered with unnecessary newlines.
* Add support for extended keys - both xterm(1)'s CSI 27 ~ sequence and the
libtickit CSI u sequence are accepted; only the latter is output. tmux will
only attempt to use these if the extended-keys option is on and it can detect
that the terminal outside supports them (or is told it does with the
"extkeys" terminal feature).
* Add an option to set the pane border lines style from a choice of single
lines (ACS or UTF-8), double or heavy (UTF-8), simple (plain ASCII) or number
(the pane numbers). Lines that won't work on a non-UTF-8 terminal are
translated back into ACS when they are output.
* Make focus events update the latest client (like a key press).
* Store UTF-8 characters differently to reduce memory use.
* Fix break-pane -n when only one pane in the window.
* Instead of sending all data to control mode clients as fast as possible, add
a limit of how much data will be sent to the client and try to use it for
panes with some degree of fairness.
* Add an active-pane client flag (set with attach-session -f, new-session -f
or refresh-client -f). This allows a client to have an independent active
pane for interactive use (the window client pane is still used for many
things however).
* Add a mark to copy mode, this is set with the set-mark command (bound to X)
and appears with the entire line shown using copy-mode-mark-style and the
marked character in reverse. The jump-to-mark command (bound to M-x) swaps
the mark and the cursor positions.
* Add a -D flag to make the tmux server run in the foreground and not as a
daemon.
* Do not loop forever in copy mode when search finds an empty match.
* Fix the next-matching-bracket logic when using vi(1) keys.
* Add a customize mode where options may be browsed and changed, includes
adding a brief description of each option. Bound to C-b C by default.
* Change message log (C-b ~) so there is one for the server rather than one per
client and it remains after detach, and make it useful by logging every
command.
* Add M-+ and M-- to tree mode to expand and collapse all.
* Change the existing client flags for control mode to apply for any client,
use the same mechanism for the read-only flag and add an ignore-size flag.
refresh-client -F has become -f (-F stays for backwards compatibility) and
attach-session and switch-client now have -f flags also. A new format
client_flags lists the flags and is shown by list-clients by default.
This separates the read-only flag from "ignore size" behaviour (new
ignore-size) flag - both behaviours are useful in different circumstances.
attach -r and switchc -r remain and set or toggle both flags together.
* Store and restore cursor position when copy mode is resized.
* Export TERM_PROGRAM and TERM_PROGRAM_VERSION like various other terminals.
* Add formats for after hook command arguments: hook_arguments with all the
arguments together; hook_argument_0, hook_argument_1 and so on with
individual arguments; hook_flag_X if flag -X is present; hook_flag_X_0,
hook_flag_X_1 and so on if -X appears multiple times.
* Try to search the entire history first for up to 200 ms so a search count can
be shown. If it takes too long, search the visible text only.
* Use VIS_CSTYLE for paste buffers also (show \012 as \n).
* Change default formats for tree mode, client mode and buffer mode to be more
compact and remove some clutter.
* Add a key (e) in buffer mode to open the buffer in an editor. The buffer
contents is updated when the editor exits.
* Add -e flag for new-session to set environment variables, like the same flag
for new-window.
* Improve search match marking in copy mode. Two new options
copy-mode-match-style and copy-mode-current-match-style to set the style for
matches and for the current match respectively. Also a change so that if a
copy key is pressed with no selection, the current match (if any) is copied.
* Sanitize session names like window names instead of forbidding invalid ones.
* Check if the clear terminfo(5) capability starts with CSI and if so then
assume the terminal is VT100-like, rather than relying on the XT capability.
* Improve command prompt tab completion and add menus both for strings and -t
and -s (when used without a trailing space). command-prompt has additional
flags for only completing a window (-W) and a target (-T), allowing C-b ' to
only show windows and C-b . only targets.
* Change all the style options to string options so they can support formats.
Change pane-border-active-style to use this to change the border colour when
in a mode or with synchronize-panes on. This also implies a few minor changes
to existing behaviour:
- set-option -a with a style option automatically inserts a comma between the
old value and appended text.
- OSC 10 and 11 no longer set the window-style option, instead they store the
colour internally in the pane data and it is used as the default when the
option is evaluated.
- status-fg and -bg now override status-style instead of the option values
being changed.
* Add extension terminfo(5) capabilities for margins and focus reporting.
* Try $XDG_CONFIG_HOME/tmux/tmux.conf as well as ~/.config/tmux/tmux.conf for
configuration file (the search paths are in TMUX_CONF in Makefile.am).
* Remove the DSR 1337 iTerm2 extension and replace by the extended device
attributes sequence (CSI > q) supported by more terminals.
* Add a -s flag to copy-mode to specify a different pane for the source
content. This means it is possible to view two places in a pane's history at
the same time in different panes, or view the history while still using the
pane. Pressing r refreshes the content from the source pane.
* Add an argument to list-commands to show only a single command.
* Change copy mode to make copy of the pane history so it does not need to
freeze the pane.
* Restore pane_current_path format from portable tmux on OpenBSD.
* Wait until the initial command sequence is done before sending a device
attributes request and other bits that prompt a reply from the terminal. This
means that stray replies are not left on the terminal if the command has
attached and then immediately detached and tmux will not be around to receive
them.
* Add a -f filter argument to the list commands like choose-tree.
* Move specific hooks for panes to pane options and windows for window options
rather than all hooks being session options. These hooks are now window options:
window-layout-changed
window-linked
window-pane-changed
window-renamed
window-unlinked
And these are now pane options:
pane-died
pane-exited
pane-focus-in
pane-focus-out
pane-mode-changed
pane-set-clipboard
Any existing configurations using these hooks on a session rather than
globally (that is, set-hook or set-option without -g) may need to be changed.
* Show signal names when a process exits with remain-on-exit on platforms which
have a way to get them.
* Start menu with top item selected if no mouse and use mode-style for the
selected item.
* Add a copy-command option and change copy-pipe and friends to pipe to it if
used without arguments, allows all the default copy key bindings to be
changed to pipe with one option rather than needing to change each key
binding individually.
* Tidy up the terminal detection and feature code and add named sets of
terminal features, each of which are defined in one place and map to a
builtin set of terminfo(5) capabilities. Features can be specified based on
TERM with a new terminal-features option or with the -T flag when running
tmux. tmux will also detect a few common terminals from the DA and DSR
responses.
This is intended to make it easier to configure tmux's use of terminfo(5)
even in the presence of outdated ncurses(3) or terminfo(5) databases or for
features which do not yet have a terminfo(5) entry. Instead of having to grok
terminfo(5) capability names and what they should be set to in the
terminal-overrides option, the user can hopefully just give tmux a feature
name and let it do the right thing.
The terminal-overrides option remains both for backwards compatibility and to
allow tweaks of individual capabilities.
* Support mintty's application escape sequence (means tmux doesn't have to
delay to wait for Escape, so no need to reduce escape-time when using
mintty).
* Change so main-pane-width and height can be given as a percentage.
* Support for the iTerm2 synchronized updates feature (allows the terminal to
avoid unnecessary drawing while output is still in progress).
* Make the mouse_word and mouse_line formats work in copy mode and enable the
default pane menu in copy mode.
* Add a -T flag to resize-pane to trim lines below the cursor, moving lines out
of the history.
* Add a way to mark environment variables as "hidden" so they can be used by
tmux (for example in formats) but are not set in the environment for new
panes. set-environment and show-environment have a new -h flag and there is a
new %hidden statement for the configuration file.
* Change default position for display-menu -x and -y to centre rather than top
left.
* Add support for per-client transient popups, similar to menus but which are
connected to an external command (like a pane). These are created with new
command display-popup.
* Change double and triple click bindings so that only one is fired (previously
double click was fired on the way to triple click). Also add default double
and triple click bindings to copy the word or line under the cursor and
change the existing bindings in copy mode to do the same.
* Add a default binding for button 2 to paste.
* Add -d flag to run-shell to delay before running the command and allow it to
be used without a command so it just delays.
* Add C-g to cancel command prompt with vi keys as well as emacs, and q in
command mode.
* When the server socket is given with -S, create it with umask 177 instead of
117 (because it may not be in a safe directory like the default directory in
/tmp).
* Add a copy-mode -H flag to hide the position marker in the top right.
* Add number operators for formats (+, -, *, / and m),
CHANGED FROM 3.1b TO 3.1c
* Do not write after the end of the array and overwrite the stack when
colon-separated SGR sequences contain empty arguments.
CHANGES FROM 3.1a TO 3.1b
* Fix build on systems without sys/queue.h.
* Fix crash when allow-rename is on and an empty name is set.
CHANGES FROM 3.1 TO 3.1a
* Do not close stdout prematurely in control mode since it is needed to print
exit messages. Prevents hanging when detaching with iTerm2.
CHANGES FROM 3.0a TO 3.1
* Only search the visible part of the history when marking (highlighting)
search terms. This is much faster than searching the whole history and solves
problems with large histories. The count of matches shown is now the visible
matches rather than all matches.
* Search using regular expressions in copy mode. search-forward and
search-backward use regular expressions by default; the incremental versions
do not.
* Turn off mouse mode 1003 as well as the rest when exiting.
* Add selection_active format for when the selection is present but not moving
with the cursor.
* Fix dragging with modifier keys, so binding keys such as C-MouseDrag1Pane and
C-MouseDragEnd1Pane now work.
* Add -a to list-keys to also list keys without notes with -N.
* Do not jump to next word end if already on a word end when selecting a word;
fixes select-word with single character words and vi(1) keys.
* Fix top and bottom pane calculation with pane border status enabled.
* Add support for adding a note to a key binding (with bind-key -N) and use
this to add descriptions to the default key bindings. A new -N flag to
list-keys shows key bindings with notes. Change the default ? binding to use
this to show a readable summary of keys. Also extend command-prompt to return
the name of the key pressed and add a default binding (/) to show the note
for the next key pressed.
* Add support for the iTerm2 DSR 1337 sequence to get the terminal version.
* Treat plausible but invalid keys (like C-BSpace) as literal like any other
unrecognised string passed to send-keys.
* Detect iTerm2 and enable use of DECSLRM (much faster with horizontally split
windows).
* Add -Z to default switch-client command in tree mode.
* Add ~ to quoted characters for %%%.
* Document client exit messages in the manual page.
* Do not let read-only clients limit the size, unless all clients are
read-only.
* Add a number of new formats to inspect what sessions and clients a window is
present or active in.
* Change file reading and writing to go through the client if necessary. This
fixes commands like "tmux loadb /dev/fd/X". Also modify source-file to
support "-" for standard input, like load-buffer and save-buffer.
* Add ~/.config/tmux/tmux.conf to the default search path for configuration
files.
* Bump the escape sequence timeout to five seconds to allow for longer
legitimate sequences.
* Make a best effort to set xpixel and ypixel for each pane and add formats for
them.
* Add push-default to status-left and status-right in status-format[0].
* Do not clear search marks on cursor movement with vi(1) keys.
* Add p format modifier for padding to width and allow multiple substitutions
in a single format.
* Add -f for full size to join-pane (like split-window).
* Do not use bright when emulating 256 colours on an 8 colour terminal because
it is also bold on some terminals.
* Make select-pane -P set window-active-style also to match previous behaviour.
* Do not truncate list-keys output.
* Turn automatic-rename back on if the \033k rename escape sequence is used
with an empty name.
* Add support for percentage sizes for resize-pane ("-x 10%"). Also change
split-window and join-pane -l to accept similar percentages and deprecate the
-p flag.
* Add -F flag to send-keys to expand formats in search-backward and forward
copy mode commands and copy_cursor_word and copy_cursor_line formats for word
and line at cursor in copy mode. Use for default # and * binding with vi(1)
keys.
* Add formats for word and line at cursor position in copy mode.
* Add formats for cursor and selection position in copy mode.
* Support all the forms of RGB colour strings in OSC sequences rather than
requiring two digits.
* Limit lazy resize to panes in attached sessions only.
* Add an option to set the key sent by backspace for those whose system uses ^H
rather than ^?.
* Change new-session -A without a session name (that is, no -s option also) to
attach to the best existing session like attach-session rather than a new
one.
* Add a "latest" window-size option which tries to size windows based on the
most recently used client. This is now the default.
* Add simple support for OSC 7 (result is available in the pane_path format).
* Add push-default and pop-default for styles which change the colours and
attributes used for #[default]. These are used in status-format to restore
the behaviour of window-status-style being the default for
window-status-format.
* Add window_marked_flag.
* Add cursor-down-and-cancel in copy mode.
* Default to previous search string for search-forward and search-backward.
* Add -Z flag to rotate-window, select-pane, swap-pane, switch-client to
preserve zoomed state.
* Add -N to capture-pane to preserve trailing spaces.
* Add reverse sorting in tree, client and buffer modes.
CHANGES FROM 3.0 TO 3.0a
* Do not require REG_STARTEND.
* Respawn panes or windows correctly if default-command is set.
* Add missing option for after-kill-pane hook.
* Fix for crash with a format variable that doesn't exist.
* Do not truncate list-keys output on some platforms.
* Do not crash when restoring a layout with only one pane.
CHANGES FROM 2.9 TO 3.0
* Workaround invalid layout strings generated by older tmux versions and add
some additional sanity checks
* xterm 348 now disables margins when resized, so send DECLRMM again after
resize.
* Add support for the SD (scroll down) escape sequence.
* Expand arguments to C and s format modifiers to match the m modifier.
* Add support for underscore colours (Setulc capability must be added with
terminal-overrides as described in tmux(1)).
* Add a "fill" style attribute for the fill colour of the drawing area (where
appropriate).
* New -H flag to send-keys to send literal keys.
* Format variables for pane mouse modes (mouse_utf8_flag and mouse_sgr_flag)
and for origin mode (origin_flag).
* Add -F to refresh-client for flags for control mode clients, only one flag
(no-output) supported at the moment.
* Add a few vi(1) keys for menus.
* Add pane options, set with set-option -p and displayed with show-options -p.
Pane options inherit from window options (so every pane option is also
a window option). The pane style is now configured by setting window-style
and window-active-style in the pane options; select-pane -P and -g now change
the option but are no longer documented.
* Do not document set-window-option and show-window-options. set-option -w and
show-options -w should be used instead.
* Add a -A flag to show-options to show parent options as well (they are marked
with a *).
* Resize panes lazily - do not resize unless they are in an attached, active
window.
* Add regular expression support for the format search, match and substitute
modifiers and make them able to ignore case. find-window now accepts -r to
use regular expressions.
* Do not use $TMUX to find the session because for windows in multiple sessions
it is wrong as often as it is right, and for windows in one session it is
pointless. Instead use TMUX_PANE if it is present.
* Do not always resize the window back to its original size after applying a
layout, keep it at the layout size until it must be resized (for example when
attached and window-size is not manual).
* Add new-session -X and attach-session -x to send SIGHUP to parent when
detaching (like detach-client -P).
* Support for octal escapes in strings (such as \007) and improve list-keys
output so it parses correctly if copied into a configuration file.
* 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
@@ -29,7 +634,7 @@ CHANGES FROM 2.9 to 3.0
* 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.
buffer modes; and C-b < and >.
* 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
@@ -64,11 +669,11 @@ CHANGES FROM 2.9 to 3.0
* 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
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
CHANGES FROM 2.8 TO 2.9
* Attempt to preserve horizontal cursor position as well as vertical with
reflow.
@@ -193,7 +798,7 @@ CHANGES FROM 2.8 to 2.9
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
CHANGES FROM 2.7 TO 2.8
* Make display-panes block the client until a pane is chosen or it
times out.

View File

@@ -6,11 +6,14 @@ CLEANFILES = tmux.1.mdoc tmux.1.man cmd-parse.c
# Distribution tarball options.
EXTRA_DIST = \
CHANGES README README.ja COPYING example_tmux.conf compat/*.[ch] \
CHANGES README README.ja COPYING example_tmux.conf \
osdep-*.c mdoc2man.awk tmux.1
dist_EXTRA_tmux_SOURCES = compat/*.[ch]
# Preprocessor flags.
AM_CPPFLAGS += @XOPEN_DEFINES@ -DTMUX_CONF="\"$(sysconfdir)/tmux.conf\""
AM_CPPFLAGS += @XOPEN_DEFINES@ \
-DTMUX_VERSION='"@VERSION@"' \
-DTMUX_CONF='"$(sysconfdir)/tmux.conf:~/.tmux.conf:$$XDG_CONFIG_HOME/tmux/tmux.conf:~/.config/tmux/tmux.conf"'
# Additional object files.
LDADD = $(LIBOBJS)
@@ -25,7 +28,7 @@ AM_CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
AM_CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
AM_CFLAGS += -Wno-unused-result
AM_CFLAGS += -Wno-unused-result -Wno-format-y2k
AM_CPPFLAGS += -DDEBUG
endif
AM_CPPFLAGS += -iquote.
@@ -55,6 +58,11 @@ if IS_NETBSD
AM_CPPFLAGS += -D_OPENBSD_SOURCE
endif
# Set flags for Haiku.
if IS_HAIKU
AM_CPPFLAGS += -D_BSD_SOURCE
endif
# List of sources.
dist_tmux_SOURCES = \
alerts.c \
@@ -88,7 +96,6 @@ dist_tmux_SOURCES = \
cmd-list-panes.c \
cmd-list-sessions.c \
cmd-list-windows.c \
cmd-list.c \
cmd-load-buffer.c \
cmd-lock-server.c \
cmd-move-window.c \
@@ -131,8 +138,10 @@ dist_tmux_SOURCES = \
control-notify.c \
control.c \
environ.c \
file.c \
format.c \
format-draw.c \
grid-reader.c \
grid-view.c \
grid.c \
input-keys.c \
@@ -151,7 +160,9 @@ dist_tmux_SOURCES = \
options-table.c \
options.c \
paste.c \
popup.c \
proc.c \
regsub.c \
resize.c \
screen-redraw.c \
screen-write.c \
@@ -166,6 +177,7 @@ dist_tmux_SOURCES = \
tmux.c \
tmux.h \
tty-acs.c \
tty-features.c \
tty-keys.c \
tty-term.c \
tty.c \
@@ -174,11 +186,11 @@ dist_tmux_SOURCES = \
window-client.c \
window-clock.c \
window-copy.c \
window-customize.c \
window-tree.c \
window.c \
xmalloc.c \
xmalloc.h \
xterm-keys.c
xmalloc.h
nodist_tmux_SOURCES = osdep-@PLATFORM@.c
# Add compat file for forkpty.
@@ -191,6 +203,12 @@ if HAVE_UTF8PROC
nodist_tmux_SOURCES += compat/utf8proc.c
endif
if NEED_FUZZING
check_PROGRAMS = fuzz/input-fuzzer
fuzz_input_fuzzer_LDFLAGS = $(FUZZING_LIBS)
fuzz_input_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
endif
# Install tmux.1 in the right format.
install-exec-hook:
if test x@MANFORMAT@ = xmdoc; then \

9
README
View File

@@ -16,6 +16,9 @@ It also depends on ncurses, available from:
https://invisible-mirror.net/archives/ncurses/
To build tmux, a C compiler (for example gcc or clang), make, pkg-config and a
suitable yacc (yacc or bison) are needed.
* Installation
To build and install tmux from a release tarball, use:
@@ -26,16 +29,14 @@ To build and install tmux from a release tarball, use:
tmux can use the utempter library to update utmp(5), if it is installed - run
configure with --enable-utempter to enable this.
To get and build the latest from version control:
To get and build the latest from version control - note that this requires
autoconf, automake and pkg-config:
$ 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

View File

@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <event.h>
#include <stdlib.h>
#include "tmux.h"
@@ -200,7 +199,7 @@ alerts_check_bell(struct window *w)
* not check WINLINK_BELL).
*/
s = wl->session;
if (s->curw != wl) {
if (s->curw != wl || s->attached == 0) {
wl->flags |= WINLINK_BELL;
server_status_session(s);
}
@@ -236,7 +235,7 @@ alerts_check_activity(struct window *w)
if (wl->flags & WINLINK_ACTIVITY)
continue;
s = wl->session;
if (s->curw != wl) {
if (s->curw != wl || s->attached == 0) {
wl->flags |= WINLINK_ACTIVITY;
server_status_session(s);
}
@@ -272,7 +271,7 @@ alerts_check_silence(struct window *w)
if (wl->flags & WINLINK_SILENCE)
continue;
s = wl->session;
if (s->curw != wl) {
if (s->curw != wl || s->attached == 0) {
wl->flags |= WINLINK_SILENCE;
server_status_session(s);
}
@@ -315,9 +314,12 @@ alerts_set_message(struct winlink *wl, const char *type, const char *option)
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);
if (c->session->curw == wl) {
status_message_set(c, -1, 1, 0, "%s in current window",
type);
} else {
status_message_set(c, -1, 1, 0, "%s in window %d", type,
wl->idx);
}
}
}

View File

@@ -37,6 +37,7 @@ TAILQ_HEAD(args_values, args_value);
struct args_entry {
u_char flag;
struct args_values values;
u_int count;
RB_ENTRY(args_entry) entry;
};
@@ -54,11 +55,11 @@ args_cmp(struct args_entry *a1, struct args_entry *a2)
/* Find a flag in the arguments tree. */
static struct args_entry *
args_find(struct args *args, u_char ch)
args_find(struct args *args, u_char flag)
{
struct args_entry entry;
entry.flag = ch;
entry.flag = flag;
return (RB_FIND(args_tree, &args->tree, &entry));
}
@@ -73,6 +74,7 @@ args_parse(const char *template, int argc, char **argv)
optreset = 1;
optind = 1;
optarg = NULL;
while ((opt = getopt(argc, argv, template)) != -1) {
if (opt < 0)
@@ -82,6 +84,7 @@ args_parse(const char *template, int argc, char **argv)
return (NULL);
}
args_set(args, opt, optarg);
optarg = NULL;
}
argc -= optind;
argv += optind;
@@ -173,6 +176,7 @@ args_print(struct args *args)
size_t len;
char *buf;
int i;
u_int j;
struct args_entry *entry;
struct args_value *value;
@@ -186,7 +190,8 @@ args_print(struct args *args)
if (*buf == '\0')
args_print_add(&buf, &len, "-");
args_print_add(&buf, &len, "%c", entry->flag);
for (j = 0; j < entry->count; j++)
args_print_add(&buf, &len, "%c", entry->flag);
}
/* Then the flags with arguments. */
@@ -206,23 +211,35 @@ args_print(struct args *args)
char *
args_escape(const char *s)
{
static const char quoted[] = " #\"';${}";
static const char dquoted[] = " #';${}";
static const char squoted[] = " \"";
char *escaped, *result;
int flags;
int flags, quotes = 0;
if (*s == '\0')
return (xstrdup(s));
if ((strchr(quoted, s[0]) != NULL || s[0] == '~') && s[1] == '\0') {
if (*s == '\0') {
xasprintf(&result, "''");
return (result);
}
if (s[strcspn(s, dquoted)] != '\0')
quotes = '"';
else if (s[strcspn(s, squoted)] != '\0')
quotes = '\'';
if (s[0] != ' ' &&
s[1] == '\0' &&
(quotes != 0 || s[0] == '~')) {
xasprintf(&escaped, "\\%c", s[0]);
return (escaped);
}
flags = VIS_OCTAL|VIS_TAB|VIS_NL;
if (s[strcspn(s, quoted)] != '\0')
flags = VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL;
if (quotes == '"')
flags |= VIS_DQ;
utf8_stravis(&escaped, s, flags);
if (flags & VIS_DQ) {
if (quotes == '\'')
xasprintf(&result, "'%s'", escaped);
else if (quotes == '"') {
if (*escaped == '~')
xasprintf(&result, "\"\\%s\"", escaped);
else
@@ -239,25 +256,32 @@ args_escape(const char *s)
/* Return if an argument is present. */
int
args_has(struct args *args, u_char ch)
args_has(struct args *args, u_char flag)
{
return (args_find(args, ch) != NULL);
struct args_entry *entry;
entry = args_find(args, flag);
if (entry == NULL)
return (0);
return (entry->count);
}
/* Set argument value in the arguments tree. */
void
args_set(struct args *args, u_char ch, const char *s)
args_set(struct args *args, u_char flag, const char *s)
{
struct args_entry *entry;
struct args_value *value;
entry = args_find(args, ch);
entry = args_find(args, flag);
if (entry == NULL) {
entry = xcalloc(1, sizeof *entry);
entry->flag = ch;
entry->flag = flag;
entry->count = 1;
TAILQ_INIT(&entry->values);
RB_INSERT(args_tree, &args->tree, entry);
}
} else
entry->count++;
if (s != NULL) {
value = xcalloc(1, sizeof *value);
@@ -268,22 +292,44 @@ args_set(struct args *args, u_char ch, const char *s)
/* Get argument value. Will be NULL if it isn't present. */
const char *
args_get(struct args *args, u_char ch)
args_get(struct args *args, u_char flag)
{
struct args_entry *entry;
if ((entry = args_find(args, ch)) == NULL)
if ((entry = args_find(args, flag)) == NULL)
return (NULL);
if (TAILQ_EMPTY(&entry->values))
return (NULL);
return (TAILQ_LAST(&entry->values, args_values)->value);
}
/* Get first argument. */
u_char
args_first(struct args *args, struct args_entry **entry)
{
*entry = RB_MIN(args_tree, &args->tree);
if (*entry == NULL)
return (0);
return ((*entry)->flag);
}
/* Get next argument. */
u_char
args_next(struct args_entry **entry)
{
*entry = RB_NEXT(args_tree, &args->tree, *entry);
if (*entry == NULL)
return (0);
return ((*entry)->flag);
}
/* Get first value in argument. */
const char *
args_first_value(struct args *args, u_char ch, struct args_value **value)
args_first_value(struct args *args, u_char flag, struct args_value **value)
{
struct args_entry *entry;
if ((entry = args_find(args, ch)) == NULL)
if ((entry = args_find(args, flag)) == NULL)
return (NULL);
*value = TAILQ_FIRST(&entry->values);
@@ -306,15 +352,15 @@ args_next_value(struct args_value **value)
/* Convert an argument value to a number. */
long long
args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
char **cause)
args_strtonum(struct args *args, u_char flag, long long minval,
long long maxval, char **cause)
{
const char *errstr;
long long ll;
struct args_entry *entry;
struct args_value *value;
if ((entry = args_find(args, ch)) == NULL) {
if ((entry = args_find(args, flag)) == NULL) {
*cause = xstrdup("missing");
return (0);
}
@@ -329,3 +375,60 @@ args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
*cause = NULL;
return (ll);
}
/* Convert an argument to a number which may be a percentage. */
long long
args_percentage(struct args *args, u_char flag, long long minval,
long long maxval, long long curval, char **cause)
{
const char *value;
struct args_entry *entry;
if ((entry = args_find(args, flag)) == NULL) {
*cause = xstrdup("missing");
return (0);
}
value = TAILQ_LAST(&entry->values, args_values)->value;
return (args_string_percentage(value, minval, maxval, curval, cause));
}
/* Convert a string to a number which may be a percentage. */
long long
args_string_percentage(const char *value, long long minval, long long maxval,
long long curval, char **cause)
{
const char *errstr;
long long ll;
size_t valuelen = strlen(value);
char *copy;
if (value[valuelen - 1] == '%') {
copy = xstrdup(value);
copy[valuelen - 1] = '\0';
ll = strtonum(copy, 0, 100, &errstr);
free(copy);
if (errstr != NULL) {
*cause = xstrdup(errstr);
return (0);
}
ll = (curval * ll) / 100;
if (ll < minval) {
*cause = xstrdup("too small");
return (0);
}
if (ll > maxval) {
*cause = xstrdup("too large");
return (0);
}
} else {
ll = strtonum(value, minval, maxval, &errstr);
if (errstr != NULL) {
*cause = xstrdup(errstr);
return (0);
}
}
*cause = NULL;
return (ll);
}

View File

@@ -31,7 +31,8 @@ attributes_tostring(int attr)
if (attr == 0)
return ("none");
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%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%s",
(attr & GRID_ATTR_CHARSET) ? "acs," : "",
(attr & GRID_ATTR_BRIGHT) ? "bright," : "",
(attr & GRID_ATTR_DIM) ? "dim," : "",
(attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "",
@@ -59,9 +60,10 @@ attributes_fromstring(const char *str)
size_t end;
u_int i;
struct {
const char* name;
int attr;
const char *name;
int attr;
} table[] = {
{ "acs", GRID_ATTR_CHARSET },
{ "bright", GRID_ATTR_BRIGHT },
{ "bold", GRID_ATTR_BRIGHT },
{ "dim", GRID_ATTR_DIM },

104
cfg.c
View File

@@ -27,12 +27,15 @@
#include "tmux.h"
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;
int cfg_quiet = 1;
char **cfg_files;
u_int cfg_nfiles;
static enum cmd_retval
cfg_client_done(__unused struct cmdq_item *item, __unused void *data)
{
@@ -52,26 +55,18 @@ cfg_done(__unused struct cmdq_item *item, __unused void *data)
cfg_show_causes(RB_MIN(sessions, &sessions));
if (cfg_item != NULL)
cfg_item->flags &= ~CMDQ_WAITING;
cmdq_continue(cfg_item);
status_prompt_load_history();
return (CMD_RETURN_NORMAL);
}
void
set_cfg_file(const char *path)
{
free(cfg_file);
cfg_file = xstrdup(path);
}
void
start_cfg(void)
{
const char *home;
int flags = 0;
struct client *c;
struct client *c;
u_int i;
/*
* Configuration files are loaded without a client, so commands are run
@@ -89,15 +84,12 @@ start_cfg(void)
cmdq_append(c, cfg_item);
}
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);
flags = CMD_PARSE_QUIET;
for (i = 0; i < cfg_nfiles; i++) {
if (cfg_quiet)
load_cfg(cfg_files[i], c, NULL, CMD_PARSE_QUIET, NULL);
else
load_cfg(cfg_files[i], c, NULL, 0, NULL);
}
if (cfg_file != NULL)
load_cfg(cfg_file, NULL, NULL, flags, NULL);
cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
}
@@ -110,6 +102,7 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
struct cmd_parse_input pi;
struct cmd_parse_result *pr;
struct cmdq_item *new_item0;
struct cmdq_state *state;
if (new_item != NULL)
*new_item = NULL;
@@ -126,6 +119,8 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
pi.flags = flags;
pi.file = path;
pi.line = 1;
pi.item = item;
pi.c = c;
pr = cmd_parse_from_file(f, &pi);
fclose(f);
@@ -141,12 +136,73 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
return (0);
}
new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
if (item != NULL)
cmdq_insert_after(item, new_item0);
state = cmdq_copy_state(cmdq_get_state(item));
else
cmdq_append(c, new_item0);
state = cmdq_new_state(NULL, NULL, 0);
cmdq_add_format(state, "current_file", "%s", pi.file);
new_item0 = cmdq_get_command(pr->cmdlist, state);
if (item != NULL)
new_item0 = cmdq_insert_after(item, new_item0);
else
new_item0 = cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist);
cmdq_free_state(state);
if (new_item != NULL)
*new_item = new_item0;
return (0);
}
int
load_cfg_from_buffer(const void *buf, size_t len, const char *path,
struct client *c, struct cmdq_item *item, int flags,
struct cmdq_item **new_item)
{
struct cmd_parse_input pi;
struct cmd_parse_result *pr;
struct cmdq_item *new_item0;
struct cmdq_state *state;
if (new_item != NULL)
*new_item = NULL;
log_debug("loading %s", path);
memset(&pi, 0, sizeof pi);
pi.flags = flags;
pi.file = path;
pi.line = 1;
pi.item = item;
pi.c = c;
pr = cmd_parse_from_buffer(buf, len, &pi);
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);
}
if (item != NULL)
state = cmdq_copy_state(cmdq_get_state(item));
else
state = cmdq_new_state(NULL, NULL, 0);
cmdq_add_format(state, "current_file", "%s", pi.file);
new_item0 = cmdq_get_command(pr->cmdlist, state);
if (item != NULL)
new_item0 = cmdq_insert_after(item, new_item0);
else
new_item0 = cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist);
cmdq_free_state(state);
if (new_item != NULL)
*new_item = new_item0;
@@ -196,7 +252,7 @@ cfg_show_causes(struct session *s)
wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL);
for (i = 0; i < cfg_ncauses; i++) {
window_copy_add(wp, "%s", cfg_causes[i]);
free(cfg_causes[i]);

327
client.c
View File

@@ -18,12 +18,12 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <errno.h>
#include <event.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
@@ -34,8 +34,8 @@
static struct tmuxproc *client_proc;
static struct tmuxpeer *client_peer;
static int client_flags;
static struct event client_stdin;
static uint64_t client_flags;
static int client_suspended;
static enum {
CLIENT_EXIT_NONE,
CLIENT_EXIT_DETACHED,
@@ -45,20 +45,24 @@ static enum {
CLIENT_EXIT_LOST_SERVER,
CLIENT_EXIT_EXITED,
CLIENT_EXIT_SERVER_EXITED,
CLIENT_EXIT_MESSAGE_PROVIDED
} client_exitreason = CLIENT_EXIT_NONE;
static int client_exitflag;
static int client_exitval;
static enum msgtype client_exittype;
static const char *client_exitsession;
static char *client_exitmessage;
static const char *client_execshell;
static const char *client_execcmd;
static int client_attached;
static struct client_files client_files = RB_INITIALIZER(&client_files);
static __dead void client_exec(const char *,const char *);
static int client_get_lock(char *);
static int client_connect(struct event_base *, const char *, int);
static void client_send_identify(const char *, const char *);
static void client_stdin_callback(int, short, void *);
static void client_write(int, const char *, size_t);
static int client_connect(struct event_base *, const char *,
uint64_t);
static void client_send_identify(const char *, const char *,
char **, u_int, const char *, int);
static void client_signal(int);
static void client_dispatch(struct imsg *, void *);
static void client_dispatch_attached(struct imsg *);
@@ -98,7 +102,7 @@ client_get_lock(char *lockfile)
/* Connect client to server. */
static int
client_connect(struct event_base *base, const char *path, int start_server)
client_connect(struct event_base *base, const char *path, uint64_t flags)
{
struct sockaddr_un sa;
size_t size;
@@ -123,7 +127,9 @@ retry:
log_debug("connect failed: %s", strerror(errno));
if (errno != ECONNREFUSED && errno != ENOENT)
goto failed;
if (!start_server)
if (flags & CLIENT_NOSTARTSERVER)
goto failed;
if (~flags & CLIENT_STARTSERVER)
goto failed;
close(fd);
@@ -155,7 +161,7 @@ retry:
close(lockfd);
return (-1);
}
fd = server_start(client_proc, base, lockfd, lockfile);
fd = server_start(client_proc, flags, base, lockfd, lockfile);
}
if (locked && lockfd >= 0) {
@@ -202,43 +208,52 @@ client_exit_message(void)
case CLIENT_EXIT_TERMINATED:
return ("terminated");
case CLIENT_EXIT_LOST_SERVER:
return ("lost server");
return ("server exited unexpectedly");
case CLIENT_EXIT_EXITED:
return ("exited");
case CLIENT_EXIT_SERVER_EXITED:
return ("server exited");
case CLIENT_EXIT_MESSAGE_PROVIDED:
return (client_exitmessage);
}
return ("unknown reason");
}
/* Exit if all streams flushed. */
static void
client_exit(void)
{
if (!file_write_left(&client_files))
proc_exit(client_proc);
}
/* Client main loop. */
int
client_main(struct event_base *base, int argc, char **argv, int flags)
client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
int feat)
{
struct cmd_parse_result *pr;
struct cmd *cmd;
struct msg_command_data *data;
int cmdflags, fd, i;
const char *ttynam, *cwd;
struct msg_command *data;
int fd, i;
const char *ttynam, *termname, *cwd;
pid_t ppid;
enum msgtype msg;
struct termios tio, saved_tio;
size_t size;
size_t size, linesize = 0;
ssize_t linelen;
char *line = NULL, **caps = NULL, *cause;
u_int ncaps = 0;
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
signal(SIGCHLD, SIG_IGN);
/* Save the flags. */
client_flags = flags;
/* Set up the initial command. */
cmdflags = 0;
if (shell_command != NULL) {
msg = MSG_SHELL;
cmdflags = CMD_STARTSERVER;
flags |= CLIENT_STARTSERVER;
} else if (argc == 0) {
msg = MSG_COMMAND;
cmdflags = CMD_STARTSERVER;
flags |= CLIENT_STARTSERVER;
} else {
msg = MSG_COMMAND;
@@ -249,10 +264,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
*/
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;
}
if (cmd_list_any_have(pr->cmdlist, CMD_STARTSERVER))
flags |= CLIENT_STARTSERVER;
cmd_list_free(pr->cmdlist);
} else
free(pr->error);
@@ -262,8 +275,12 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
client_proc = proc_start("client");
proc_set_signals(client_proc, client_signal);
/* Save the flags. */
client_flags = flags;
log_debug("flags are %#llx", (unsigned long long)client_flags);
/* Initialize the client socket and start the server. */
fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
fd = client_connect(base, socket_path, client_flags);
if (fd == -1) {
if (errno == ECONNREFUSED) {
fprintf(stderr, "no server running on %s\n",
@@ -281,6 +298,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
cwd = "/";
if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
ttynam = "";
if ((termname = getenv("TERM")) == NULL)
termname = "";
/*
* Drop privileges for client. "proc exec" is needed for -c and for
@@ -291,9 +310,21 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
*
* "sendfd" is dropped later in client_dispatch_wait().
*/
if (pledge("stdio unix sendfd proc exec tty", NULL) != 0)
if (pledge(
"stdio rpath wpath cpath unix sendfd proc exec tty",
NULL) != 0)
fatal("pledge failed");
/* Load terminfo entry if any. */
if (isatty(STDIN_FILENO) &&
*termname != '\0' &&
tty_term_read_list(termname, STDIN_FILENO, &caps, &ncaps,
&cause) != 0) {
fprintf(stderr, "%s\n", cause);
free(cause);
return (1);
}
/* Free stuff that is not used in the client. */
if (ptm_fd != -1)
close(ptm_fd);
@@ -302,10 +333,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
options_free(global_w_options);
environ_free(global_environ);
/* Create stdin handler. */
setblocking(STDIN_FILENO, 0);
event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
client_stdin_callback, NULL);
/* Set up control mode. */
if (client_flags & CLIENT_CONTROLCONTROL) {
if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) {
fprintf(stderr, "tcgetattr failed: %s\n",
@@ -327,7 +355,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
}
/* Send identify messages. */
client_send_identify(ttynam, cwd);
client_send_identify(ttynam, termname, caps, ncaps, cwd, feat);
tty_term_free_list(caps, ncaps);
/* Send first command. */
if (msg == MSG_COMMAND) {
@@ -370,6 +399,11 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
client_exec(client_execshell, client_execcmd);
}
/* Restore streams to blocking. */
setblocking(STDIN_FILENO, 1);
setblocking(STDOUT_FILENO, 1);
setblocking(STDERR_FILENO, 1);
/* Print the exit message, if any, and exit. */
if (client_attached) {
if (client_exitreason != CLIENT_EXIT_NONE)
@@ -378,42 +412,65 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
ppid = getppid();
if (client_exittype == MSG_DETACHKILL && ppid > 1)
kill(ppid, SIGHUP);
} else if (client_flags & CLIENT_CONTROLCONTROL) {
} else if (client_flags & CLIENT_CONTROL) {
if (client_exitreason != CLIENT_EXIT_NONE)
printf("%%exit %s\n", client_exit_message());
else
printf("%%exit\n");
printf("\033\\");
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
fflush(stdout);
if (client_flags & CLIENT_CONTROL_WAITEXIT) {
setvbuf(stdin, NULL, _IOLBF, 0);
for (;;) {
linelen = getline(&line, &linesize, stdin);
if (linelen <= 1)
break;
}
free(line);
}
if (client_flags & CLIENT_CONTROLCONTROL) {
printf("\033\\");
fflush(stdout);
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
}
} else if (client_exitreason != CLIENT_EXIT_NONE)
fprintf(stderr, "%s\n", client_exit_message());
setblocking(STDIN_FILENO, 1);
return (client_exitval);
}
/* Send identify messages to server. */
static void
client_send_identify(const char *ttynam, const char *cwd)
client_send_identify(const char *ttynam, const char *termname, char **caps,
u_int ncaps, const char *cwd, int feat)
{
const char *s;
char **ss;
size_t sslen;
int fd, flags = client_flags;
pid_t pid;
char **ss;
size_t sslen;
int fd, flags = client_flags;
pid_t pid;
u_int i;
proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags,
sizeof client_flags);
if ((s = getenv("TERM")) == NULL)
s = "";
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, termname,
strlen(termname) + 1);
proc_send(client_peer, MSG_IDENTIFY_FEATURES, -1, &feat, sizeof feat);
proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
strlen(ttynam) + 1);
proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
for (i = 0; i < ncaps; i++) {
proc_send(client_peer, MSG_IDENTIFY_TERMINFO, -1,
caps[i], strlen(caps[i]) + 1);
}
if ((fd = dup(STDIN_FILENO)) == -1)
fatal("dup failed");
proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
if ((fd = dup(STDOUT_FILENO)) == -1)
fatal("dup failed");
proc_send(client_peer, MSG_IDENTIFY_STDOUT, fd, NULL, 0);
pid = getpid();
proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
@@ -428,41 +485,6 @@ client_send_identify(const char *ttynam, const char *cwd)
proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0);
}
/* Callback for client stdin read events. */
static void
client_stdin_callback(__unused int fd, __unused short events,
__unused void *arg)
{
struct msg_stdin_data data;
data.size = read(STDIN_FILENO, data.data, sizeof data.data);
if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
return;
proc_send(client_peer, MSG_STDIN, -1, &data, sizeof data);
if (data.size <= 0)
event_del(&client_stdin);
}
/* Force write to file descriptor. */
static void
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) {
if (errno == EINTR || errno == EAGAIN)
continue;
break;
}
data += used;
size -= used;
}
}
/* Run command in shell; used for -c. */
static __dead void
client_exec(const char *shell, const char *shellcmd)
@@ -501,6 +523,7 @@ client_signal(int sig)
struct sigaction sigact;
int status;
log_debug("%s: %s", __func__, strsignal(sig));
if (sig == SIGCHLD)
waitpid(WAIT_ANY, &status, WNOHANG);
else if (!client_attached) {
@@ -514,7 +537,8 @@ client_signal(int sig)
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
case SIGTERM:
client_exitreason = CLIENT_EXIT_TERMINATED;
if (!client_suspended)
client_exitreason = CLIENT_EXIT_TERMINATED;
client_exitval = 1;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
@@ -529,18 +553,31 @@ client_signal(int sig)
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0);
client_suspended = 0;
break;
}
}
}
/* Callback for file write error or close. */
static void
client_file_check_cb(__unused struct client *c, __unused const char *path,
__unused int error, __unused int closed, __unused struct evbuffer *buffer,
__unused void *data)
{
if (client_exitflag)
client_exit();
}
/* Callback for client read events. */
static void
client_dispatch(struct imsg *imsg, __unused void *arg)
{
if (imsg == NULL) {
client_exitreason = CLIENT_EXIT_LOST_SERVER;
client_exitval = 1;
if (!client_exitflag) {
client_exitreason = CLIENT_EXIT_LOST_SERVER;
client_exitval = 1;
}
proc_exit(client_proc);
return;
}
@@ -551,16 +588,39 @@ client_dispatch(struct imsg *imsg, __unused void *arg)
client_dispatch_wait(imsg);
}
/* Process an exit message. */
static void
client_dispatch_exit_message(char *data, size_t datalen)
{
int retval;
if (datalen < sizeof retval && datalen != 0)
fatalx("bad MSG_EXIT size");
if (datalen >= sizeof retval) {
memcpy(&retval, data, sizeof retval);
client_exitval = retval;
}
if (datalen > sizeof retval) {
datalen -= sizeof retval;
data += sizeof retval;
client_exitmessage = xmalloc(datalen);
memcpy(client_exitmessage, data, datalen);
client_exitmessage[datalen - 1] = '\0';
client_exitreason = CLIENT_EXIT_MESSAGE_PROVIDED;
}
}
/* Dispatch imsgs when in wait state (before MSG_READY). */
static void
client_dispatch_wait(struct imsg *imsg)
{
char *data;
ssize_t datalen;
struct msg_stdout_data stdoutdata;
struct msg_stderr_data stderrdata;
int retval;
static int pledge_applied;
char *data;
ssize_t datalen;
static int pledge_applied;
/*
* "sendfd" is no longer required once all of the identify messages
@@ -569,10 +629,12 @@ client_dispatch_wait(struct imsg *imsg)
* get the first message from the server.
*/
if (!pledge_applied) {
if (pledge("stdio unix proc exec tty", NULL) != 0)
if (pledge(
"stdio rpath wpath cpath unix proc exec tty",
NULL) != 0)
fatal("pledge failed");
pledge_applied = 1;
};
}
data = imsg->data;
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
@@ -580,44 +642,17 @@ client_dispatch_wait(struct imsg *imsg)
switch (imsg->hdr.type) {
case MSG_EXIT:
case MSG_SHUTDOWN:
if (datalen != sizeof retval && datalen != 0)
fatalx("bad MSG_EXIT size");
if (datalen == sizeof retval) {
memcpy(&retval, data, sizeof retval);
client_exitval = retval;
}
proc_exit(client_proc);
client_dispatch_exit_message(data, datalen);
client_exitflag = 1;
client_exit();
break;
case MSG_READY:
if (datalen != 0)
fatalx("bad MSG_READY size");
event_del(&client_stdin);
client_attached = 1;
proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
break;
case MSG_STDIN:
if (datalen != 0)
fatalx("bad MSG_STDIN size");
event_add(&client_stdin, NULL);
break;
case MSG_STDOUT:
if (datalen != sizeof stdoutdata)
fatalx("bad MSG_STDOUT size");
memcpy(&stdoutdata, data, sizeof stdoutdata);
client_write(STDOUT_FILENO, stdoutdata.data,
stdoutdata.size);
break;
case MSG_STDERR:
if (datalen != sizeof stderrdata)
fatalx("bad MSG_STDERR size");
memcpy(&stderrdata, data, sizeof stderrdata);
client_write(STDERR_FILENO, stderrdata.data,
stderrdata.size);
break;
case MSG_VERSION:
if (datalen != 0)
fatalx("bad MSG_VERSION size");
@@ -628,6 +663,14 @@ client_dispatch_wait(struct imsg *imsg)
client_exitval = 1;
proc_exit(client_proc);
break;
case MSG_FLAGS:
if (datalen != sizeof client_flags)
fatalx("bad MSG_FLAGS string");
memcpy(&client_flags, data, sizeof client_flags);
log_debug("new flags are %#llx",
(unsigned long long)client_flags);
break;
case MSG_SHELL:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_SHELL string");
@@ -641,6 +684,28 @@ client_dispatch_wait(struct imsg *imsg)
case MSG_EXITED:
proc_exit(client_proc);
break;
case MSG_READ_OPEN:
file_read_open(&client_files, client_peer, imsg, 1,
!(client_flags & CLIENT_CONTROL), client_file_check_cb,
NULL);
break;
case MSG_WRITE_OPEN:
file_write_open(&client_files, client_peer, imsg, 1,
!(client_flags & CLIENT_CONTROL), client_file_check_cb,
NULL);
break;
case MSG_WRITE:
file_write_data(&client_files, imsg);
break;
case MSG_WRITE_CLOSE:
file_write_close(&client_files, imsg);
break;
case MSG_OLDSTDERR:
case MSG_OLDSTDIN:
case MSG_OLDSTDOUT:
fprintf(stderr, "server version is too old for client\n");
proc_exit(client_proc);
break;
}
}
@@ -656,6 +721,14 @@ client_dispatch_attached(struct imsg *imsg)
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
switch (imsg->hdr.type) {
case MSG_FLAGS:
if (datalen != sizeof client_flags)
fatalx("bad MSG_FLAGS string");
memcpy(&client_flags, data, sizeof client_flags);
log_debug("new flags are %#llx",
(unsigned long long)client_flags);
break;
case MSG_DETACH:
case MSG_DETACHKILL:
if (datalen == 0 || data[datalen - 1] != '\0')
@@ -680,11 +753,10 @@ client_dispatch_attached(struct imsg *imsg)
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
case MSG_EXIT:
if (datalen != 0 && datalen != sizeof (int))
fatalx("bad MSG_EXIT size");
client_dispatch_exit_message(data, datalen);
if (client_exitreason == CLIENT_EXIT_NONE)
client_exitreason = CLIENT_EXIT_EXITED;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
client_exitreason = CLIENT_EXIT_EXITED;
break;
case MSG_EXITED:
if (datalen != 0)
@@ -710,6 +782,7 @@ client_dispatch_attached(struct imsg *imsg)
sigact.sa_handler = SIG_DFL;
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
client_suspended = 1;
kill(getpid(), SIGTSTP);
break;
case MSG_LOCK:

View File

@@ -37,8 +37,9 @@ const struct cmd_entry cmd_attach_session_entry = {
.name = "attach-session",
.alias = "attach",
.args = { "c:dErt:", 0, 0 },
.usage = "[-dEr] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
.args = { "c:dEf:rt:x", 0, 0 },
.usage = "[-dErx] [-c working-directory] [-f flags] "
CMD_TARGET_SESSION_USAGE,
/* -t is special */
@@ -48,16 +49,18 @@ const struct cmd_entry cmd_attach_session_entry = {
enum cmd_retval
cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
int rflag, const char *cflag, int Eflag)
int xflag, int rflag, const char *cflag, int Eflag, const char *fflag)
{
struct cmd_find_state *current = &item->shared->current;
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state target;
enum cmd_find_type type;
int flags;
struct client *c = item->client, *c_loop;
struct client *c = cmdq_get_client(item), *c_loop;
struct session *s;
struct winlink *wl;
struct window_pane *wp;
char *cause;
char *cwd, *cause;
enum msgtype msgtype;
if (RB_EMPTY(&sessions)) {
cmdq_error(item, "no sessions");
@@ -79,11 +82,11 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
type = CMD_FIND_SESSION;
flags = CMD_FIND_PREFER_UNATTACHED;
}
if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
if (cmd_find_target(&target, item, tflag, type, flags) != 0)
return (CMD_RETURN_ERROR);
s = item->target.s;
wl = item->target.wl;
wp = item->target.wp;
s = target.s;
wl = target.wl;
wp = target.wp;
if (wl != NULL) {
if (wp != NULL)
@@ -96,24 +99,33 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
}
if (cflag != NULL) {
cwd = format_single(item, cflag, c, s, wl, wp);
free((void *)s->cwd);
s->cwd = format_single(item, cflag, c, s, wl, wp);
s->cwd = cwd;
}
if (fflag)
server_client_set_flags(c, fflag);
if (rflag)
c->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE);
c->last_session = c->session;
if (c->session != NULL) {
if (dflag) {
if (dflag || xflag) {
if (xflag)
msgtype = MSG_DETACHKILL;
else
msgtype = MSG_DETACH;
TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session != s || c == c_loop)
continue;
server_client_detach(c_loop, MSG_DETACH);
server_client_detach(c_loop, msgtype);
}
}
if (!Eflag)
environ_update(s->options, c->environ, s->environ);
c->session = s;
if (~item->shared->flags & CMDQ_SHARED_REPEAT)
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
@@ -122,20 +134,23 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
s->curw->window->latest = c;
} else {
if (server_client_open(c, &cause) != 0) {
cmdq_error(item, "open terminal failed: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (rflag)
c->flags |= CLIENT_READONLY;
if (dflag) {
if (dflag || xflag) {
if (xflag)
msgtype = MSG_DETACHKILL;
else
msgtype = MSG_DETACH;
TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session != s || c == c_loop)
continue;
server_client_detach(c_loop, MSG_DETACH);
server_client_detach(c_loop, msgtype);
}
}
if (!Eflag)
@@ -150,6 +165,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
s->curw->window->latest = c;
if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0);
@@ -166,9 +182,9 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
static enum cmd_retval
cmd_attach_session_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
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')));
args_has(args, 'd'), args_has(args, 'x'), args_has(args, 'r'),
args_get(args, 'c'), args_has(args, 'E'), args_get(args, 'f')));
}

View File

@@ -33,9 +33,9 @@ const struct cmd_entry cmd_bind_key_entry = {
.name = "bind-key",
.alias = "bind",
.args = { "cnrT:", 2, -1 },
.usage = "[-cnr] [-T key-table] key "
"command [arguments]",
.args = { "nrN:T:", 1, -1 },
.usage = "[-nr] [-T key-table] [-N note] key "
"[command [arguments]]",
.flags = CMD_AFTERHOOK,
.exec = cmd_bind_key_exec
@@ -44,12 +44,12 @@ 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;
struct args *args = cmd_get_args(self);
key_code key;
const char *tablename;
const char *tablename, *note = args_get(args, 'N');
struct cmd_parse_result *pr;
char **argv = args->argv;
int argc = args->argc;
int argc = args->argc, repeat;
key = key_string_lookup_string(argv[0]);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
@@ -63,22 +63,26 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
tablename = "root";
else
tablename = "prefix";
repeat = args_has(args, 'r');
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'), pr->cmdlist);
if (argc != 1) {
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, note, repeat, pr->cmdlist);
} else
key_bindings_add(tablename, key, note, repeat, NULL);
return (CMD_RETURN_NORMAL);
}

View File

@@ -34,8 +34,8 @@ const struct cmd_entry cmd_break_pane_entry = {
.name = "break-pane",
.alias = "breakp",
.args = { "dPF:n:s:t:", 0, 0 },
.usage = "[-dP] [-F format] [-n window-name] [-s src-pane] "
.args = { "abdPF:n:s:t:", 0, 0 },
.usage = "[-abdP] [-F format] [-n window-name] [-s src-pane] "
"[-t dst-window]",
.source = { 's', CMD_FIND_PANE, 0 },
@@ -48,37 +48,61 @@ const struct cmd_entry cmd_break_pane_entry = {
static enum cmd_retval
cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
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 args *args = cmd_get_args(self);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct cmd_find_state *source = cmdq_get_source(item);
struct client *tc = cmdq_get_target_client(item);
struct winlink *wl = source->wl;
struct session *src_s = source->s;
struct session *dst_s = target->s;
struct window_pane *wp = source->wp;
struct window *w = wl->window;
char *name, *cause;
int idx = item->target.idx;
char *name, *cause, *cp;
int idx = target->idx, before;
const char *template;
char *cp;
if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) {
cmdq_error(item, "index %d already in use", idx);
return (CMD_RETURN_ERROR);
}
if (window_count_panes(w) == 1) {
cmdq_error(item, "can't break with only one pane");
return (CMD_RETURN_ERROR);
before = args_has(args, 'b');
if (args_has(args, 'a') || before) {
if (target->wl != NULL)
idx = winlink_shuffle_up(dst_s, target->wl, before);
else
idx = winlink_shuffle_up(dst_s, dst_s->curw, before);
if (idx == -1)
return (CMD_RETURN_ERROR);
}
server_unzoom_window(w);
if (window_count_panes(w) == 1) {
if (server_link_window(src_s, wl, dst_s, idx, 0,
!args_has(args, 'd'), &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'n')) {
window_set_name(w, args_get(args, 'n'));
options_set_number(w->options, "automatic-rename", 0);
}
server_unlink_window(src_s, wl);
return (CMD_RETURN_NORMAL);
}
if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) {
cmdq_error(item, "index in use: %d", idx);
return (CMD_RETURN_ERROR);
}
TAILQ_REMOVE(&w->panes, wp, entry);
server_client_remove_pane(wp);
window_lost_pane(w, wp);
layout_close_pane(wp);
w = wp->window = window_create(w->sx, w->sy);
w = wp->window = window_create(w->sx, w->sy, w->xpixel, w->ypixel);
options_set_parent(wp->options, w->options);
wp->flags |= PANE_STYLECHANGED;
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp;
w->latest = tc;
if (!args_has(args, 'n')) {
name = default_window_name(w);
@@ -95,7 +119,7 @@ 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(args, 'd')) {
session_select(dst_s, wl->idx);
cmd_find_from_session(current, dst_s, 0);
}
@@ -110,7 +134,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = BREAK_PANE_TEMPLATE;
cp = format_single(item, template, c, dst_s, wl, wp);
cp = format_single(item, template, tc, dst_s, wl, wp);
cmdq_print(item, "%s", cp);
free(cp);
}

View File

@@ -39,8 +39,8 @@ const struct cmd_entry cmd_capture_pane_entry = {
.name = "capture-pane",
.alias = "capturep",
.args = { "ab:CeE:JpPqS:t:", 0, 0 },
.usage = "[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] "
.args = { "ab:CeE:JNpPqS:t:", 0, 0 },
.usage = "[-aCeJNpPq] " CMD_BUFFER_USAGE " [-E end-line] "
"[-S start-line] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
@@ -80,7 +80,7 @@ cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
size_t linelen;
u_int i;
pending = input_pending(wp);
pending = input_pending(wp->ictx);
if (pending == NULL)
return (xstrdup(""));
@@ -110,7 +110,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
struct grid *gd;
const struct grid_line *gl;
struct grid_cell *gc = NULL;
int n, with_codes, escape_c0, join_lines;
int n, with_codes, escape_c0, join_lines, no_trim;
u_int i, sx, top, bottom, tmp;
char *cause, *buf, *line;
const char *Sflag, *Eflag;
@@ -118,7 +118,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
sx = screen_size_x(&wp->base);
if (args_has(args, 'a')) {
gd = wp->saved_grid;
gd = wp->base.saved_grid;
if (gd == NULL) {
if (!args_has(args, 'q')) {
cmdq_error(item, "no alternate screen");
@@ -170,11 +170,12 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
with_codes = args_has(args, 'e');
escape_c0 = args_has(args, 'C');
join_lines = args_has(args, 'J');
no_trim = args_has(args, 'N');
buf = NULL;
for (i = top; i <= bottom; i++) {
line = grid_string_cells(gd, 0, i, sx, &gc, with_codes,
escape_c0, !join_lines);
escape_c0, !join_lines && !no_trim);
linelen = strlen(line);
buf = cmd_capture_pane_append(buf, len, line, linelen);
@@ -191,14 +192,14 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
static enum cmd_retval
cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c;
struct window_pane *wp = item->target.wp;
struct args *args = cmd_get_args(self);
struct client *c = cmdq_get_client(item);
struct window_pane *wp = cmdq_get_target(item)->wp;
char *buf, *cause;
const char *bufname;
size_t len;
if (self->entry == &cmd_clear_history_entry) {
if (cmd_get_entry(self) == &cmd_clear_history_entry) {
window_pane_reset_mode_all(wp);
grid_clear_history(wp->base.grid);
return (CMD_RETURN_NORMAL);
@@ -213,18 +214,20 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
if (args_has(args, 'p')) {
c = item->client;
if (c == NULL ||
(c->session != NULL && !(c->flags & CLIENT_CONTROL))) {
cmdq_error(item, "can't write to stdout");
if (len > 0 && buf[len - 1] == '\n')
len--;
if (c->flags & CLIENT_CONTROL)
control_write(c, "%.*s", (int)len, buf);
else {
if (!file_can_print(c)) {
cmdq_error(item, "can't write to client");
free(buf);
return (CMD_RETURN_ERROR);
}
file_print_buffer(c, buf, len);
file_print(c, "\n");
free(buf);
return (CMD_RETURN_ERROR);
}
evbuffer_add(c->stdout_data, buf, len);
free(buf);
if (args_has(args, 'P') && len > 0)
evbuffer_add(c->stdout_data, "\n", 1);
server_client_push_stdout(c);
} else {
bufname = NULL;
if (args_has(args, 'b'))

View File

@@ -30,9 +30,9 @@ const struct cmd_entry cmd_choose_tree_entry = {
.name = "choose-tree",
.alias = NULL,
.args = { "F:Gf:NO:st:wZ", 0, 1 },
.usage = "[-GNsw] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE " [template]",
.args = { "F:f:GK:NO:rst:wZ", 0, 1 },
.usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -44,9 +44,9 @@ const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client",
.alias = NULL,
.args = { "F:f:NO:t:Z", 0, 1 },
.usage = "[-N] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE " [template]",
.args = { "F:f:K:NO:rt:Z", 0, 1 },
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -58,9 +58,22 @@ const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer",
.alias = NULL,
.args = { "F:f:NO:t:Z", 0, 1 },
.usage = "[-N] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE " [template]",
.args = { "F:f:K:NO:rt:Z", 0, 1 },
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_choose_tree_exec
};
const struct cmd_entry cmd_customize_mode_entry = {
.name = "customize-mode",
.alias = NULL,
.args = { "F:f:Nt:Z", 0, 0 },
.usage = "[-NZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
@@ -71,21 +84,24 @@ const struct cmd_entry cmd_choose_buffer_entry = {
static enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct window_pane *wp = item->target.wp;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct window_pane *wp = target->wp;
const struct window_mode *mode;
if (self->entry == &cmd_choose_buffer_entry) {
if (cmd_get_entry(self) == &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) {
} else if (cmd_get_entry(self) == &cmd_choose_client_entry) {
if (server_client_how_many() == 0)
return (CMD_RETURN_NORMAL);
mode = &window_client_mode;
} else
} else if (cmd_get_entry(self) == &cmd_customize_mode_entry)
mode = &window_customize_mode;
else
mode = &window_tree_mode;
window_pane_set_mode(wp, mode, &item->target, args);
window_pane_set_mode(wp, NULL, mode, target, args);
return (CMD_RETURN_NORMAL);
}

View File

@@ -40,11 +40,11 @@ const struct cmd_entry cmd_command_prompt_entry = {
.name = "command-prompt",
.alias = NULL,
.args = { "1iI:Np:t:", 0, 1 },
.usage = "[-1Ni] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
.args = { "1kiI:Np:Tt:W", 0, 1 },
.usage = "[-1kiNTW] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
"[template]",
.flags = 0,
.flags = CMD_CLIENT_TFLAG,
.exec = cmd_command_prompt_exec
};
@@ -64,17 +64,15 @@ struct cmd_command_prompt_cdata {
static enum cmd_retval
cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct cmd_find_state *target = cmdq_get_target(item);
const char *inputs, *prompts;
struct cmd_command_prompt_cdata *cdata;
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)
if (tc->prompt_string != NULL)
return (CMD_RETURN_NORMAL);
cdata = xcalloc(1, sizeof *cdata);
@@ -122,8 +120,15 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
cdata->flags |= PROMPT_NUMERIC;
else if (args_has(args, 'i'))
cdata->flags |= PROMPT_INCREMENTAL;
status_prompt_set(c, prompt, input, cmd_command_prompt_callback,
cmd_command_prompt_free, cdata, cdata->flags);
else if (args_has(args, 'k'))
cdata->flags |= PROMPT_KEY;
else if (args_has(args, 'W'))
cdata->flags |= PROMPT_WINDOW;
else if (args_has(args, 'T'))
cdata->flags |= PROMPT_TARGET;
status_prompt_set(tc, target, prompt, input,
cmd_command_prompt_callback, cmd_command_prompt_free, cdata,
cdata->flags);
free(prompt);
return (CMD_RETURN_NORMAL);
@@ -134,10 +139,9 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
int done)
{
struct cmd_command_prompt_cdata *cdata = data;
struct cmdq_item *new_item;
char *new_template, *prompt, *ptr;
char *new_template, *prompt, *ptr, *error;
char *input = NULL;
struct cmd_parse_result *pr;
enum cmd_parse_status status;
if (s == NULL)
return (0);
@@ -164,21 +168,10 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
return (1);
}
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;
status = cmd_parse_and_append(new_template, NULL, c, NULL, &error);
if (status == CMD_PARSE_ERROR) {
cmdq_append(c, cmdq_get_error(error));
free(error);
}
if (!done)

View File

@@ -42,7 +42,7 @@ const struct cmd_entry cmd_confirm_before_entry = {
.args = { "p:t:", 1, 1 },
.usage = "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
.flags = 0,
.flags = CMD_CLIENT_TFLAG,
.exec = cmd_confirm_before_exec
};
@@ -53,15 +53,13 @@ struct cmd_confirm_before_data {
static enum cmd_retval
cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct cmd_confirm_before_data *cdata;
struct client *c;
struct client *tc = cmdq_get_target_client(item);
struct cmd_find_state *target = cmdq_get_target(item);
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 {
@@ -74,7 +72,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(args->argv[0]);
status_prompt_set(c, new_prompt, NULL,
status_prompt_set(tc, target, new_prompt, NULL,
cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
PROMPT_SINGLE);
@@ -87,8 +85,8 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s,
__unused int done)
{
struct cmd_confirm_before_data *cdata = data;
struct cmdq_item *new_item;
struct cmd_parse_result *pr;
char *error;
enum cmd_parse_status status;
if (c->flags & CLIENT_DEAD)
return (0);
@@ -98,21 +96,10 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s,
if (tolower((u_char)s[0]) != 'y' || s[1] != '\0')
return (0);
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;
status = cmd_parse_and_append(cdata->cmd, NULL, c, NULL, &error);
if (status == CMD_PARSE_ERROR) {
cmdq_append(c, cmdq_get_error(error));
free(error);
}
return (0);

View File

@@ -30,9 +30,10 @@ const struct cmd_entry cmd_copy_mode_entry = {
.name = "copy-mode",
.alias = NULL,
.args = { "Met:u", 0, 0 },
.usage = "[-Mu] " CMD_TARGET_PANE_USAGE,
.args = { "eHMs:t:uq", 0, 0 },
.usage = "[-eHMuq] [-s src-pane] " CMD_TARGET_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
@@ -55,29 +56,40 @@ const struct cmd_entry cmd_clock_mode_entry = {
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 args *args = cmd_get_args(self);
struct key_event *event = cmdq_get_event(item);
struct cmd_find_state *source = cmdq_get_source(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct client *c = cmdq_get_client(item);
struct session *s;
struct window_pane *wp = item->target.wp;
struct window_pane *wp = target->wp, *swp;
if (args_has(args, 'q')) {
window_pane_reset_mode_all(wp);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'M')) {
if ((wp = cmd_mouse_pane(&shared->mouse, &s, NULL)) == NULL)
if ((wp = cmd_mouse_pane(&event->m, &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, NULL, NULL);
if (cmd_get_entry(self) == &cmd_clock_mode_entry) {
window_pane_set_mode(wp, NULL, &window_clock_mode, NULL, NULL);
return (CMD_RETURN_NORMAL);
}
if (!window_pane_set_mode(wp, &window_copy_mode, NULL, args)) {
if (args_has(args, 's'))
swp = source->wp;
else
swp = wp;
if (!window_pane_set_mode(wp, swp, &window_copy_mode, NULL, args)) {
if (args_has(args, 'M'))
window_copy_start_drag(c, &shared->mouse);
window_copy_start_drag(c, &event->m);
}
if (args_has(self->args, 'u'))
if (args_has(args, 'u'))
window_copy_pageup(wp, 0);
return (CMD_RETURN_NORMAL);

View File

@@ -39,7 +39,7 @@ const struct cmd_entry cmd_detach_client_entry = {
.source = { 's', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_READONLY,
.flags = CMD_READONLY|CMD_CLIENT_TFLAG,
.exec = cmd_detach_client_exec
};
@@ -50,24 +50,22 @@ const struct cmd_entry cmd_suspend_client_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE,
.flags = 0,
.flags = CMD_CLIENT_TFLAG,
.exec = cmd_detach_client_exec
};
static enum cmd_retval
cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c, *cloop;
struct session *s;
enum msgtype msgtype;
const char *cmd = args_get(args, 'E');
struct args *args = cmd_get_args(self);
struct cmd_find_state *source = cmdq_get_source(item);
struct client *tc = cmdq_get_target_client(item), *loop;
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) {
server_client_suspend(c);
if (cmd_get_entry(self) == &cmd_suspend_client_entry) {
server_client_suspend(tc);
return (CMD_RETURN_NORMAL);
}
@@ -77,35 +75,35 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
msgtype = MSG_DETACH;
if (args_has(args, 's')) {
s = item->source.s;
s = source->s;
if (s == NULL)
return (CMD_RETURN_NORMAL);
TAILQ_FOREACH(cloop, &clients, entry) {
if (cloop->session == s) {
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->session == s) {
if (cmd != NULL)
server_client_exec(cloop, cmd);
server_client_exec(loop, cmd);
else
server_client_detach(cloop, msgtype);
server_client_detach(loop, msgtype);
}
}
return (CMD_RETURN_STOP);
}
if (args_has(args, 'a')) {
TAILQ_FOREACH(cloop, &clients, entry) {
if (cloop->session != NULL && cloop != c) {
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->session != NULL && loop != tc) {
if (cmd != NULL)
server_client_exec(cloop, cmd);
server_client_exec(loop, cmd);
else
server_client_detach(cloop, msgtype);
server_client_detach(loop, msgtype);
}
}
return (CMD_RETURN_NORMAL);
}
if (cmd != NULL)
server_client_exec(c, cmd);
server_client_exec(tc, cmd);
else
server_client_detach(c, msgtype);
server_client_detach(tc, msgtype);
return (CMD_RETURN_STOP);
}

View File

@@ -29,55 +29,255 @@
static enum cmd_retval cmd_display_menu_exec(struct cmd *,
struct cmdq_item *);
static enum cmd_retval cmd_display_popup_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] "
.args = { "c:t:OT:x:y:", 1, -1 },
.usage = "[-O] [-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,
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG,
.exec = cmd_display_menu_exec
};
const struct cmd_entry cmd_display_popup_entry = {
.name = "display-popup",
.alias = "popup",
.args = { "Cc:d:Eh:t:w:x:y:", 0, -1 },
.usage = "[-CE] [-c target-client] [-d start-directory] [-h height] "
CMD_TARGET_PANE_USAGE " [-w width] "
"[-x position] [-y position] [command]",
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG,
.exec = cmd_display_popup_exec
};
static int
cmd_display_menu_get_position(struct client *tc, struct cmdq_item *item,
struct args *args, u_int *px, u_int *py, u_int w, u_int h)
{
struct tty *tty = &tc->tty;
struct cmd_find_state *target = cmdq_get_target(item);
struct key_event *event = cmdq_get_event(item);
struct session *s = tc->session;
struct winlink *wl = target->wl;
struct window_pane *wp = target->wp;
struct style_ranges *ranges = NULL;
struct style_range *sr = NULL;
const char *xp, *yp;
char *p;
int top;
u_int line, ox, oy, sx, sy, lines, position;
long n;
struct format_tree *ft;
/*
* Work out the position from the -x and -y arguments. This is the
* bottom-left position.
*/
/* If the popup is too big, stop now. */
if (w > tty->sx || h > tty->sy)
return (0);
/* Create format with mouse position if any. */
ft = format_create_from_target(item);
if (event->m.valid) {
format_add(ft, "popup_mouse_x", "%u", event->m.x);
format_add(ft, "popup_mouse_y", "%u", event->m.y);
}
/*
* If there are any status lines, add this window position and the
* status line position.
*/
top = status_at_line(tc);
if (top != -1) {
lines = status_line_size(tc);
if (top == 0)
top = lines;
else
top = 0;
position = options_get_number(s->options, "status-position");
for (line = 0; line < lines; line++) {
ranges = &tc->status.entries[line].ranges;
TAILQ_FOREACH(sr, ranges, entry) {
if (sr->type != STYLE_RANGE_WINDOW)
continue;
if (sr->argument == (u_int)wl->idx)
break;
}
if (sr != NULL)
break;
}
if (line == lines)
ranges = &tc->status.entries[0].ranges;
if (sr != NULL) {
format_add(ft, "popup_window_status_line_x", "%u",
sr->start);
if (position == 0) {
format_add(ft, "popup_window_status_line_y",
"%u", line + 1 + h);
} else {
format_add(ft, "popup_window_status_line_y",
"%u", tty->sy - lines + line);
}
}
if (position == 0)
format_add(ft, "popup_status_line_y", "%u", lines + h);
else {
format_add(ft, "popup_status_line_y", "%u",
tty->sy - lines);
}
} else
top = 0;
/* Popup width and height. */
format_add(ft, "popup_width", "%u", w);
format_add(ft, "popup_height", "%u", h);
/* Position so popup is in the centre. */
n = (long)(tty->sx - 1) / 2 - w / 2;
if (n < 0)
format_add(ft, "popup_centre_x", "%u", 0);
else
format_add(ft, "popup_centre_x", "%ld", n);
n = (tty->sy - 1) / 2 + h / 2;
if (n >= tty->sy)
format_add(ft, "popup_centre_y", "%u", tty->sy - h);
else
format_add(ft, "popup_centre_y", "%ld", n);
/* Position of popup relative to mouse. */
if (event->m.valid) {
n = (long)event->m.x - w / 2;
if (n < 0)
format_add(ft, "popup_mouse_centre_x", "%u", 0);
else
format_add(ft, "popup_mouse_centre_x", "%ld", n);
n = event->m.y - h / 2;
if (n + h >= tty->sy) {
format_add(ft, "popup_mouse_centre_y", "%u",
tty->sy - h);
} else
format_add(ft, "popup_mouse_centre_y", "%ld", n);
n = (long)event->m.y + h;
if (n + h >= tty->sy)
format_add(ft, "popup_mouse_top", "%u", tty->sy - h);
else
format_add(ft, "popup_mouse_top", "%ld", n);
n = event->m.y - h;
if (n < 0)
format_add(ft, "popup_mouse_bottom", "%u", 0);
else
format_add(ft, "popup_mouse_bottom", "%ld", n);
}
/* Position in pane. */
tty_window_offset(&tc->tty, &ox, &oy, &sx, &sy);
n = top + wp->yoff - oy + h;
if (n >= tty->sy)
format_add(ft, "popup_pane_top", "%u", tty->sy - h);
else
format_add(ft, "popup_pane_top", "%ld", n);
format_add(ft, "popup_pane_bottom", "%u", top + wp->yoff + wp->sy - oy);
format_add(ft, "popup_pane_left", "%u", wp->xoff - ox);
n = (long)wp->xoff + wp->sx - ox - w;
if (n < 0)
format_add(ft, "popup_pane_right", "%u", 0);
else
format_add(ft, "popup_pane_right", "%ld", n);
/* Expand horizontal position. */
xp = args_get(args, 'x');
if (xp == NULL || strcmp(xp, "C") == 0)
xp = "#{popup_centre_x}";
else if (strcmp(xp, "R") == 0)
xp = "#{popup_pane_right}";
else if (strcmp(xp, "P") == 0)
xp = "#{popup_pane_left}";
else if (strcmp(xp, "M") == 0)
xp = "#{popup_mouse_centre_x}";
else if (strcmp(xp, "W") == 0)
xp = "#{popup_window_status_line_x}";
p = format_expand(ft, xp);
n = strtol(p, NULL, 10);
if (n + w >= tty->sx)
n = tty->sx - w;
else if (n < 0)
n = 0;
*px = n;
log_debug("%s: -x: %s = %s = %u", __func__, xp, p, *px);
free(p);
/* Expand vertical position */
yp = args_get(args, 'y');
if (yp == NULL || strcmp(yp, "C") == 0)
yp = "#{popup_centre_y}";
else if (strcmp(yp, "P") == 0)
yp = "#{popup_pane_bottom}";
else if (strcmp(yp, "M") == 0)
yp = "#{popup_mouse_top}";
else if (strcmp(yp, "S") == 0)
yp = "#{popup_status_line_y}";
else if (strcmp(yp, "W") == 0)
yp = "#{popup_window_status_line_y}";
p = format_expand(ft, yp);
n = strtol(p, NULL, 10);
if (n < h)
n = 0;
else
n -= h;
if (n + h >= tty->sy)
n = tty->sy - h;
else if (n < 0)
n = 0;
*py = n;
log_debug("%s: -y: %s = %s = %u", __func__, yp, p, *py);
free(p);
return (1);
}
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 args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct key_event *event = cmdq_get_event(item);
struct client *tc = cmdq_get_target_client(item);
struct menu *menu = NULL;
struct style_range *sr;
struct menu_item menu_item;
const char *xp, *yp, *key;
const char *key;
char *title, *name;
int at, flags, i;
u_int px, py, ox, oy, sx, sy;
int flags = 0, i;
u_int px, py;
if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (c->overlay_draw != NULL)
if (tc->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);
title = format_single_from_target(item, args_get(args, 'T'));
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);
menu_add_item(menu, NULL, item, tc, target);
continue;
}
@@ -93,7 +293,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
menu_item.key = key_string_lookup_string(key);
menu_item.command = args->argv[i++];
menu_add_item(menu, &menu_item, item, c, fs);
menu_add_item(menu, &menu_item, item, tc, target);
}
free(title);
if (menu == NULL) {
@@ -104,75 +304,94 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
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;
if (!cmd_display_menu_get_position(tc, item, args, &px, &py,
menu->width + 4, menu->count + 2)) {
menu_free(menu);
return (CMD_RETURN_NORMAL);
}
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)
if (args_has(args, 'O'))
flags |= MENU_STAYOPEN;
if (!event->m.valid)
flags |= MENU_NOMOUSE;
if (menu_display(menu, flags, item, px, py, c, fs, NULL, NULL) != 0)
if (menu_display(menu, flags, item, px, py, tc, target, NULL,
NULL) != 0)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
static enum cmd_retval
cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct session *s = target->s;
struct client *tc = cmdq_get_target_client(item);
struct tty *tty = &tc->tty;
const char *value, *shell[] = { NULL, NULL };
const char *shellcmd = NULL;
char *cwd, *cause, **argv = args->argv;
int flags = 0, argc = args->argc;
u_int px, py, w, h;
if (args_has(args, 'C')) {
server_client_clear_overlay(tc);
return (CMD_RETURN_NORMAL);
}
if (tc->overlay_draw != NULL)
return (CMD_RETURN_NORMAL);
h = tty->sy / 2;
if (args_has(args, 'h')) {
h = args_percentage(args, 'h', 1, tty->sy, tty->sy, &cause);
if (cause != NULL) {
cmdq_error(item, "height %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
w = tty->sx / 2;
if (args_has(args, 'w')) {
w = args_percentage(args, 'w', 1, tty->sx, tty->sx, &cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
if (w > tty->sx - 1)
w = tty->sx - 1;
if (h > tty->sy - 1)
h = tty->sy - 1;
if (!cmd_display_menu_get_position(tc, item, args, &px, &py, w, h))
return (CMD_RETURN_NORMAL);
value = args_get(args, 'd');
if (value != NULL)
cwd = format_single_from_target(item, value);
else
cwd = xstrdup(server_client_get_cwd(tc, s));
if (argc == 0)
shellcmd = options_get_string(s->options, "default-command");
else if (argc == 1)
shellcmd = argv[0];
if (argc <= 1 && (shellcmd == NULL || *shellcmd == '\0')) {
shellcmd = NULL;
shell[0] = options_get_string(s->options, "default-shell");
if (!checkshell(shell[0]))
shell[0] = _PATH_BSHELL;
argc = 1;
argv = (char**)shell;
}
if (args_has(args, 'E') > 1)
flags |= POPUP_CLOSEEXITZERO;
else if (args_has(args, 'E'))
flags |= POPUP_CLOSEEXIT;
if (popup_display(flags, item, px, py, w, h, shellcmd, argc, argv, cwd,
tc, s, NULL, NULL) != 0)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}

View File

@@ -39,13 +39,13 @@ const struct cmd_entry cmd_display_message_entry = {
.name = "display-message",
.alias = "display",
.args = { "ac:Ipt:F:v", 0, 1 },
.usage = "[-aIpv] [-c target-client] [-F format] "
.args = { "acd:INpt:F:v", 0, 1 },
.usage = "[-aINpv] [-c target-client] [-d delay] [-F format] "
CMD_TARGET_PANE_USAGE " [message]",
.target = { 't', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG|CMD_CLIENT_CANFAIL,
.exec = cmd_display_message_exec
};
@@ -60,17 +60,21 @@ cmd_display_message_each(const char *key, const char *value, void *arg)
static enum cmd_retval
cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c, *target_c;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct client *tc = cmdq_get_target_client(item), *c;
struct session *s = target->s;
struct winlink *wl = target->wl;
struct window_pane *wp = target->wp;
const char *template;
char *msg, *cause;
int delay = -1;
struct format_tree *ft;
int flags;
if (args_has(args, 'I')) {
if (wp == NULL)
return (CMD_RETURN_NORMAL);
if (window_pane_start_input(wp, item, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
@@ -84,6 +88,15 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
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);
}
}
template = args_get(args, 'F');
if (args->argc != 0)
template = args->argv[0];
@@ -96,29 +109,33 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
* 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;
if (tc != NULL && tc->session == s)
c = tc;
else if (s != NULL)
c = cmd_find_best_client(s);
else
target_c = cmd_find_best_client(s);
if (args_has(self->args, 'v'))
c = NULL;
if (args_has(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);
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, flags);
format_defaults(ft, c, s, wl, wp);
if (args_has(args, 'a')) {
if (item != NULL)
format_each(ft, cmd_display_message_each, item);
format_each(ft, cmd_display_message_each, item);
return (CMD_RETURN_NORMAL);
}
msg = format_expand_time(ft, template);
if (args_has(self->args, 'p'))
if (cmdq_get_client(item) == NULL)
cmdq_error(item, "%s", msg);
else if (args_has(args, 'p'))
cmdq_print(item, "%s", msg);
else if (c != NULL)
status_message_set(c, "%s", msg);
else if (tc != NULL) {
status_message_set(tc, delay, 0, args_has(args, 'N'), "%s",
msg);
}
free(msg);
format_free(ft);

View File

@@ -34,10 +34,10 @@ const struct cmd_entry cmd_display_panes_entry = {
.name = "display-panes",
.alias = "displayp",
.args = { "bd:t:", 0, 1 },
.usage = "[-b] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
.args = { "bd:Nt:", 0, 1 },
.usage = "[-bN] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
.flags = CMD_AFTERHOOK,
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
.exec = cmd_display_panes_exec
};
@@ -55,11 +55,11 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
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;
struct grid_cell fgc, bgc;
u_int pane, idx, px, py, i, j, xoff, yoff, sx, sy;
int colour, active_colour;
char buf[16], *ptr;
size_t len;
char buf[16], lbuf[16], rbuf[16], *ptr;
size_t len, llen, rlen;
if (wp->xoff + wp->sx <= ctx->ox ||
wp->xoff >= ctx->ox + ctx->sx ||
@@ -109,31 +109,50 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
px = sx / 2;
py = sy / 2;
if (window_pane_index(wp, &idx) != 0)
if (window_pane_index(wp, &pane) != 0)
fatalx("index not found");
len = xsnprintf(buf, sizeof buf, "%u", idx);
len = xsnprintf(buf, sizeof buf, "%u", pane);
if (sx < len)
return;
colour = options_get_number(oo, "display-panes-colour");
active_colour = options_get_number(oo, "display-panes-active-colour");
memcpy(&fgc, &grid_default_cell, sizeof fgc);
memcpy(&bgc, &grid_default_cell, sizeof bgc);
if (w->active == wp) {
fgc.fg = active_colour;
bgc.bg = active_colour;
} else {
fgc.fg = colour;
bgc.bg = colour;
}
rlen = xsnprintf(rbuf, sizeof rbuf, "%ux%u", wp->sx, wp->sy);
if (pane > 9 && pane < 35)
llen = xsnprintf(lbuf, sizeof lbuf, "%c", 'a' + (pane - 10));
else
llen = 0;
if (sx < len * 6 || sy < 5) {
tty_cursor(tty, xoff + px - len / 2, yoff + py);
goto draw_text;
tty_attributes(tty, &fgc, &grid_default_cell, NULL);
if (sx >= len + llen + 1) {
len += llen + 1;
tty_cursor(tty, xoff + px - len / 2, yoff + py);
tty_putn(tty, buf, len, len);
tty_putn(tty, " ", 1, 1);
tty_putn(tty, lbuf, llen, llen);
} else {
tty_cursor(tty, xoff + px - len / 2, yoff + py);
tty_putn(tty, buf, len, len);
}
goto out;
}
px -= len * 3;
py -= 2;
memcpy(&gc, &grid_default_cell, sizeof gc);
if (w->active == wp)
gc.bg = active_colour;
else
gc.bg = colour;
gc.flags |= GRID_FLAG_NOPALETTE;
tty_attributes(tty, &gc, wp);
tty_attributes(tty, &bgc, &grid_default_cell, NULL);
for (ptr = buf; *ptr != '\0'; ptr++) {
if (*ptr < '0' || *ptr > '9')
continue;
@@ -149,22 +168,20 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
px += 6;
}
len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy);
if (sx < len || sy < 6)
return;
tty_cursor(tty, xoff + sx - len, yoff);
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;
tty_attributes(tty, &gc, wp);
tty_puts(tty, buf);
if (sy <= 6)
goto out;
tty_attributes(tty, &fgc, &grid_default_cell, NULL);
if (rlen != 0 && sx >= rlen) {
tty_cursor(tty, xoff + sx - rlen, yoff);
tty_putn(tty, rbuf, rlen, rlen);
}
if (llen != 0) {
tty_cursor(tty, xoff + sx / 2 + len * 3 - llen - 1,
yoff + py + 5);
tty_putn(tty, lbuf, llen, llen);
}
out:
tty_cursor(tty, 0, 0);
}
@@ -188,7 +205,7 @@ 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;
cmdq_continue(cdata->item);
free(cdata->command);
free(cdata);
}
@@ -197,16 +214,25 @@ 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;
char *cmd, *expanded, *error;
struct window *w = c->session->curw->window;
struct window_pane *wp;
struct cmd_parse_result *pr;
enum cmd_parse_status status;
u_int index;
key_code key;
if (event->key < '0' || event->key > '9')
return (1);
if (event->key >= '0' && event->key <= '9')
index = event->key - '0';
else if ((event->key & KEYC_MASK_MODIFIERS) == 0) {
key = (event->key & KEYC_MASK_KEY);
if (key >= 'a' && key <= 'z')
index = 10 + (key - 'a');
else
return (-1);
} else
return (-1);
wp = window_pane_at_index(w, event->key - '0');
wp = window_pane_at_index(w, index);
if (wp == NULL)
return (1);
window_unzoom(w);
@@ -214,21 +240,10 @@ cmd_display_panes_key(struct client *c, struct key_event *event)
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;
status = cmd_parse_and_append(cmd, NULL, c, NULL, &error);
if (status == CMD_PARSE_ERROR) {
cmdq_append(c, cmdq_get_error(error));
free(error);
}
free(cmd);
@@ -239,18 +254,14 @@ cmd_display_panes_key(struct client *c, struct key_event *event)
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;
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct session *s = tc->session;
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)
if (tc->overlay_draw != NULL)
return (CMD_RETURN_NORMAL);
if (args_has(args, 'd')) {
@@ -273,8 +284,15 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
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, 'N')) {
server_client_set_overlay(tc, delay, NULL, NULL,
cmd_display_panes_draw, NULL, cmd_display_panes_free,
cdata);
} else {
server_client_set_overlay(tc, delay, NULL, NULL,
cmd_display_panes_draw, cmd_display_panes_key,
cmd_display_panes_free, cdata);
}
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);

View File

@@ -32,8 +32,8 @@ const struct cmd_entry cmd_find_window_entry = {
.name = "find-window",
.alias = "findw",
.args = { "CNt:TZ", 1, 1 },
.usage = "[-CNTZ] " CMD_TARGET_PANE_USAGE " match-string",
.args = { "CiNrt:TZ", 1, 1 },
.usage = "[-CiNrTZ] " CMD_TARGET_PANE_USAGE " match-string",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -44,9 +44,10 @@ const struct cmd_entry cmd_find_window_entry = {
static enum cmd_retval
cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args, *new_args;
struct window_pane *wp = item->target.wp;
const char *s = args->argv[0];
struct args *args = cmd_get_args(self), *new_args;
struct cmd_find_state *target = cmdq_get_target(item);
struct window_pane *wp = target->wp;
const char *s = args->argv[0], *suffix = "";
char *filter, *argv = { NULL };
int C, N, T;
@@ -54,40 +55,48 @@ cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
N = args_has(args, 'N');
T = args_has(args, 'T');
if (args_has(args, 'r') && args_has(args, 'i'))
suffix = "/ri";
else if (args_has(args, 'r'))
suffix = "/r";
else if (args_has(args, 'i'))
suffix = "/i";
if (!C && !N && !T)
C = N = T = 1;
if (C && N && T) {
xasprintf(&filter,
"#{||:"
"#{C:%s},#{||:#{m:*%s*,#{window_name}},"
"#{m:*%s*,#{pane_title}}}}",
s, s, s);
"#{C%s:%s},#{||:#{m%s:*%s*,#{window_name}},"
"#{m%s:*%s*,#{pane_title}}}}",
suffix, s, suffix, s, suffix, s);
} else if (C && N) {
xasprintf(&filter,
"#{||:#{C:%s},#{m:*%s*,#{window_name}}}",
s, s);
"#{||:#{C%s:%s},#{m%s:*%s*,#{window_name}}}",
suffix, s, suffix, s);
} else if (C && T) {
xasprintf(&filter,
"#{||:#{C:%s},#{m:*%s*,#{pane_title}}}",
s, s);
"#{||:#{C%s:%s},#{m%s:*%s*,#{pane_title}}}",
suffix, s, suffix, s);
} else if (N && T) {
xasprintf(&filter,
"#{||:#{m:*%s*,#{window_name}},#{m:*%s*,#{pane_title}}}",
s, s);
"#{||:#{m%s:*%s*,#{window_name}},"
"#{m%s:*%s*,#{pane_title}}}",
suffix, s, suffix, s);
} else if (C)
xasprintf(&filter, "#{C:%s}", s);
xasprintf(&filter, "#{C%s:%s}", suffix, s);
else if (N)
xasprintf(&filter, "#{m:*%s*,#{window_name}}", s);
xasprintf(&filter, "#{m%s:*%s*,#{window_name}}", suffix, s);
else
xasprintf(&filter, "#{m:*%s*,#{pane_title}}", s);
xasprintf(&filter, "#{m%s:*%s*,#{pane_title}}", suffix, s);
new_args = args_parse("", 1, &argv);
if (args_has(args, 'Z'))
args_set(new_args, 'Z', NULL);
args_set(new_args, 'f', filter);
window_pane_set_mode(wp, &window_tree_mode, &item->target, new_args);
window_pane_set_mode(wp, NULL, &window_tree_mode, target, new_args);
args_free(new_args);
free(filter);

View File

@@ -75,38 +75,12 @@ static const char *cmd_find_pane_table[][2] = {
{ NULL, NULL }
};
/* Get session from TMUX if present. */
static struct session *
cmd_find_try_TMUX(struct client *c)
{
struct environ_entry *envent;
char tmp[256];
long long pid;
u_int session;
struct session *s;
envent = environ_find(c->environ, "TMUX");
if (envent == NULL)
return (NULL);
if (sscanf(envent->value, "%255[^,],%lld,%d", tmp, &pid, &session) != 3)
return (NULL);
if (pid != getpid())
return (NULL);
log_debug("%s: client %p TMUX %s (session $%u)", __func__, c,
envent->value, session);
s = session_find_by_id(session);
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;
struct environ_entry *envent;
if (c == NULL)
return (NULL);
@@ -115,6 +89,11 @@ cmd_find_inside_pane(struct client *c)
if (wp->fd != -1 && strcmp(wp->tty, c->ttyname) == 0)
break;
}
if (wp == NULL) {
envent = environ_find(c->environ, "TMUX_PANE");
if (envent != NULL)
wp = window_pane_find_by_id_str(envent->value);
}
if (wp != NULL)
log_debug("%s: got pane %%%u (%s)", __func__, wp->id, wp->tty);
return (wp);
@@ -608,22 +587,22 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
return (-1);
return (0);
} else if (strcmp(pane, "{up-of}") == 0) {
fs->wp = window_pane_find_up(fs->w->active);
fs->wp = window_pane_find_up(fs->current->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);
fs->wp = window_pane_find_down(fs->current->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);
fs->wp = window_pane_find_left(fs->current->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);
fs->wp = window_pane_find_right(fs->current->wp);
if (fs->wp == NULL)
return (-1);
return (0);
@@ -635,7 +614,7 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
n = strtonum(pane + 1, 1, INT_MAX, NULL);
else
n = 1;
wp = fs->w->active;
wp = fs->current->wp;
if (pane[0] == '+')
fs->wp = window_pane_next_by_number(fs->w, wp, n);
else
@@ -879,8 +858,6 @@ cmd_find_from_mouse(struct cmd_find_state *fs, struct mouse_event *m, int flags)
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. */
@@ -889,7 +866,18 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
/* If this is an attached client, all done. */
if (c->session != NULL) {
cmd_find_from_session(fs, c->session, flags);
cmd_find_clear_state(fs, flags);
fs->wp = server_client_get_pane(c);
if (fs->wp == NULL) {
cmd_find_from_session(fs, c->session, flags);
return (0);
}
fs->s = c->session;
fs->wl = fs->s->curw;
fs->w = fs->wl->window;
cmd_find_log_state(__func__, fs);
return (0);
}
cmd_find_clear_state(fs, flags);
@@ -902,30 +890,6 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
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.
@@ -947,17 +911,7 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
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. */
/* We can't find the pane so need to guess. */
return (cmd_find_from_nothing(fs, flags));
}
@@ -1005,6 +959,8 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
strlcat(tmp, "CANFAIL,", sizeof tmp);
if (*tmp != '\0')
tmp[strlen(tmp) - 1] = '\0';
else
strlcat(tmp, "NONE", sizeof tmp);
log_debug("%s: target %s, type %s, item %p, flags %s", __func__,
target == NULL ? "none" : target, s, item, tmp);
@@ -1015,10 +971,11 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
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->shared->current)) {
fs->current = &item->shared->current;
} else if (cmd_find_valid_state(cmdq_get_current(item))) {
fs->current = cmdq_get_current(item);
log_debug("%s: current is from queue", __func__);
} else if (cmd_find_from_client(&current, item->client, flags) == 0) {
} else if (cmd_find_from_client(&current, cmdq_get_client(item),
flags) == 0) {
fs->current = &current;
log_debug("%s: current is from client", __func__);
} else {
@@ -1035,7 +992,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
/* Mouse target is a plain = or {mouse}. */
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
m = &item->shared->mouse;
m = &cmdq_get_event(item)->m;
switch (type) {
case CMD_FIND_PANE:
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
@@ -1285,29 +1242,31 @@ no_pane:
static struct client *
cmd_find_current_client(struct cmdq_item *item, int quiet)
{
struct client *c;
struct client *c = NULL, *found;
struct session *s;
struct window_pane *wp;
struct cmd_find_state fs;
if (item->client != NULL && item->client->session != NULL)
return (item->client);
if (item != NULL)
c = cmdq_get_client(item);
if (c != NULL && c->session != NULL)
return (c);
c = NULL;
if ((wp = cmd_find_inside_pane(item->client)) != NULL) {
found = NULL;
if (c != NULL && (wp = cmd_find_inside_pane(c)) != 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);
found = 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);
found = cmd_find_best_client(s);
}
if (c == NULL && !quiet)
if (found == NULL && item != NULL && !quiet)
cmdq_error(item, "no current client");
log_debug("%s: no target, return %p", __func__, c);
return (c);
log_debug("%s: no target, return %p", __func__, found);
return (found);
}
/* Find the target client or report an error and return NULL. */

View File

@@ -56,25 +56,23 @@ struct cmd_if_shell_data {
struct client *client;
struct cmdq_item *item;
struct mouse_event mouse;
};
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 args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct cmdq_state *state = cmdq_get_state(item);
struct cmd_if_shell_data *cdata;
char *shellcmd, *cmd;
struct cmdq_item *new_item;
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;
char *shellcmd, *cmd, *error;
const char *file;
struct client *tc = cmdq_get_target_client(item);
struct session *s = target->s;
struct cmd_parse_input pi;
struct cmd_parse_result *pr;
enum cmd_parse_status status;
shellcmd = format_single(item, args->argv[0], c, s, wl, wp);
shellcmd = format_single_from_target(item, args->argv[0]);
if (args_has(args, 'F')) {
if (*shellcmd != '0' && *shellcmd != '\0')
cmd = args->argv[1];
@@ -87,26 +85,16 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
memset(&pi, 0, sizeof pi);
if (self->file != NULL)
pi.file = self->file;
pi.line = self->line;
cmd_get_source(self, &pi.file, &pi.line);
pi.item = item;
pi.c = c;
cmd_find_copy_state(&pi.fs, &item->target);
pi.c = tc;
cmd_find_copy_state(&pi.fs, 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);
status = cmd_parse_and_insert(cmd, &pi, item, state, &error);
if (status == CMD_PARSE_ERROR) {
cmdq_error(item, "%s", error);
free(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;
}
return (CMD_RETURN_NORMAL);
}
@@ -118,9 +106,11 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->cmd_else = xstrdup(args->argv[2]);
else
cdata->cmd_else = NULL;
memcpy(&cdata->mouse, m, sizeof cdata->mouse);
cdata->client = item->client;
if (!args_has(args, 'b'))
cdata->client = cmdq_get_client(item);
else
cdata->client = tc;
if (cdata->client != NULL)
cdata->client->references++;
@@ -130,17 +120,18 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->item = NULL;
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;
cmd_get_source(self, &file, &cdata->input.line);
if (file != NULL)
cdata->input.file = xstrdup(file);
cdata->input.c = tc;
if (cdata->input.c != NULL)
cdata->input.c->references++;
cmd_find_copy_state(&cdata->input.fs, &item->target);
cmd_find_copy_state(&cdata->input.fs, 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) {
if (job_run(shellcmd, 0, NULL, s,
server_client_get_cwd(cmdq_get_client(item), s), NULL,
cmd_if_shell_callback, cmd_if_shell_free, cdata, 0, -1,
-1) == NULL) {
cmdq_error(item, "failed to run command: %s", shellcmd);
free(shellcmd);
free(cdata);
@@ -158,8 +149,8 @@ cmd_if_shell_callback(struct job *job)
{
struct cmd_if_shell_data *cdata = job_get_data(job);
struct client *c = cdata->client;
struct mouse_event *m = &cdata->mouse;
struct cmdq_item *new_item = NULL;
struct cmdq_state *new_state = NULL;
char *cmd;
int status;
struct cmd_parse_result *pr;
@@ -182,7 +173,13 @@ cmd_if_shell_callback(struct job *job)
free(pr->error);
break;
case CMD_PARSE_SUCCESS:
new_item = cmdq_get_command(pr->cmdlist, NULL, m, 0);
if (cdata->item == NULL)
new_state = cmdq_new_state(NULL, NULL, 0);
else
new_state = cmdq_get_state(cdata->item);
new_item = cmdq_get_command(pr->cmdlist, new_state);
if (cdata->item == NULL)
cmdq_free_state(new_state);
cmd_list_free(pr->cmdlist);
break;
}
@@ -195,7 +192,7 @@ cmd_if_shell_callback(struct job *job)
out:
if (cdata->item != NULL)
cdata->item->flags &= ~CMDQ_WAITING;
cmdq_continue(cdata->item);
}
static void

View File

@@ -20,6 +20,7 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
@@ -34,8 +35,8 @@ const struct cmd_entry cmd_join_pane_entry = {
.name = "join-pane",
.alias = "joinp",
.args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.args = { "bdfhvp:l:s:t:", 0, 0 },
.usage = "[-bdfhv] [-l size] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 },
@@ -48,10 +49,10 @@ const struct cmd_entry cmd_move_pane_entry = {
.name = "move-pane",
.alias = "movep",
.args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.args = { "bdfhvp:l:s:t:", 0, 0 },
.usage = "[-bdfhv] [-l size] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, 0 },
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
@@ -61,40 +62,33 @@ const struct cmd_entry cmd_move_pane_entry = {
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 args *args = cmd_get_args(self);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct cmd_find_state *source = cmdq_get_source(item);
struct session *dst_s;
struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w;
struct window_pane *src_wp, *dst_wp;
char *cause;
char *cause = NULL;
int size, percentage, dst_idx;
int flags;
enum layout_type type;
struct layout_cell *lc;
int not_same_window, flags;
if (self->entry == &cmd_join_pane_entry)
not_same_window = 1;
else
not_same_window = 0;
dst_s = item->target.s;
dst_wl = item->target.wl;
dst_wp = item->target.wp;
dst_s = target->s;
dst_wl = target->wl;
dst_wp = target->wp;
dst_w = dst_wl->window;
dst_idx = dst_wl->idx;
server_unzoom_window(dst_w);
src_wl = item->source.wl;
src_wp = item->source.wp;
src_wl = source->wl;
src_wp = source->wp;
src_w = src_wl->window;
server_unzoom_window(src_w);
if (not_same_window && src_w == dst_w) {
cmdq_error(item, "can't join a pane to its own window");
return (CMD_RETURN_ERROR);
}
if (!not_same_window && src_wp == dst_wp) {
if (src_wp == dst_wp) {
cmdq_error(item, "source and target panes must be different");
return (CMD_RETURN_ERROR);
}
@@ -105,28 +99,34 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
size = -1;
if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "size %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
if (type == LAYOUT_TOPBOTTOM) {
size = args_percentage(args, 'l', 0, INT_MAX,
dst_wp->sy, &cause);
} else {
size = args_percentage(args, 'l', 0, INT_MAX,
dst_wp->sx, &cause);
}
} else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, 100, &cause);
if (cause != NULL) {
cmdq_error(item, "percentage %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
if (cause == NULL) {
if (type == LAYOUT_TOPBOTTOM)
size = (dst_wp->sy * percentage) / 100;
else
size = (dst_wp->sx * percentage) / 100;
}
if (type == LAYOUT_TOPBOTTOM)
size = (dst_wp->sy * percentage) / 100;
else
size = (dst_wp->sx * percentage) / 100;
}
if (cause != NULL) {
cmdq_error(item, "size %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
flags = 0;
if (args_has(args, 'b'))
flags = SPAWN_BEFORE;
else
flags = 0;
flags |= SPAWN_BEFORE;
if (args_has(args, 'f'))
flags |= SPAWN_FULLSIZE;
lc = layout_split_pane(dst_wp, type, size, flags);
if (lc == NULL) {
cmdq_error(item, "create pane failed: pane too small");
@@ -135,12 +135,18 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
layout_close_pane(src_wp);
server_client_remove_pane(src_wp);
window_lost_pane(src_w, src_wp);
TAILQ_REMOVE(&src_w->panes, src_wp, entry);
src_wp->window = dst_w;
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
layout_assign_pane(lc, src_wp);
options_set_parent(src_wp->options, dst_w->options);
src_wp->flags |= PANE_STYLECHANGED;
if (flags & SPAWN_BEFORE)
TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry);
else
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
layout_assign_pane(lc, src_wp, 0);
recalculate_sizes();
@@ -156,7 +162,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
server_status_session(dst_s);
if (window_count_panes(src_w) == 0)
server_kill_window(src_w);
server_kill_window(src_w, 1);
else
notify_window("window-layout-changed", src_w);
notify_window("window-layout-changed", dst_w);

View File

@@ -37,21 +37,24 @@ const struct cmd_entry cmd_kill_pane_entry = {
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.flags = CMD_AFTERHOOK,
.exec = cmd_kill_pane_exec
};
static enum cmd_retval
cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct winlink *wl = item->target.wl;
struct window_pane *loopwp, *tmpwp, *wp = item->target.wp;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl;
struct window_pane *loopwp, *tmpwp, *wp = target->wp;
if (args_has(self->args, 'a')) {
if (args_has(args, 'a')) {
server_unzoom_window(wl->window);
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
if (loopwp == wp)
continue;
server_client_remove_pane(loopwp);
layout_close_pane(loopwp);
window_remove_pane(wl->window, loopwp);
}

View File

@@ -54,7 +54,7 @@ const struct cmd_entry cmd_start_server_entry = {
static enum cmd_retval
cmd_kill_server_exec(struct cmd *self, __unused struct cmdq_item *item)
{
if (self->entry == &cmd_kill_server_entry)
if (cmd_get_entry(self) == &cmd_kill_server_entry)
kill(getpid(), SIGTERM);
return (CMD_RETURN_NORMAL);

View File

@@ -45,11 +45,10 @@ const struct cmd_entry cmd_kill_session_entry = {
static enum cmd_retval
cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct session *s, *sloop, *stmp;
struct winlink *wl;
s = item->target.s;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct session *s = target->s, *sloop, *stmp;
struct winlink *wl;
if (args_has(args, 'C')) {
RB_FOREACH(wl, winlinks, &s->windows) {

View File

@@ -55,27 +55,56 @@ const struct cmd_entry cmd_unlink_window_entry = {
static enum cmd_retval
cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct winlink *wl = item->target.wl, *wl2, *wl3;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl, *loop;
struct window *w = wl->window;
struct session *s = item->target.s;
struct session *s = target->s;
u_int found;
if (self->entry == &cmd_unlink_window_entry) {
if (!args_has(self->args, 'k') && !session_is_linked(s, w)) {
if (cmd_get_entry(self) == &cmd_unlink_window_entry) {
if (!args_has(args, 'k') && !session_is_linked(s, w)) {
cmdq_error(item, "window only linked to one session");
return (CMD_RETURN_ERROR);
}
server_unlink_window(s, wl);
} else {
if (args_has(args, 'a')) {
RB_FOREACH_SAFE(wl2, winlinks, &s->windows, wl3) {
if (wl != wl2)
server_kill_window(wl2->window);
}
} else
server_kill_window(wl->window);
recalculate_sizes();
return (CMD_RETURN_NORMAL);
}
recalculate_sizes();
if (args_has(args, 'a')) {
if (RB_PREV(winlinks, &s->windows, wl) == NULL &&
RB_NEXT(winlinks, &s->windows, wl) == NULL)
return (CMD_RETURN_NORMAL);
/* Kill all windows except the current one. */
do {
found = 0;
RB_FOREACH(loop, winlinks, &s->windows) {
if (loop->window != wl->window) {
server_kill_window(loop->window, 0);
found++;
break;
}
}
} while (found != 0);
/*
* If the current window appears in the session more than once,
* kill it as well.
*/
found = 0;
RB_FOREACH(loop, winlinks, &s->windows) {
if (loop->window == wl->window)
found++;
}
if (found > 1)
server_kill_window(wl->window, 0);
server_renumber_all();
return (CMD_RETURN_NORMAL);
}
server_kill_window(wl->window, 1);
return (CMD_RETURN_NORMAL);
}

View File

@@ -36,8 +36,8 @@ const struct cmd_entry cmd_list_buffers_entry = {
.name = "list-buffers",
.alias = "lsb",
.args = { "F:", 0, 0 },
.usage = "[-F format]",
.args = { "F:f:", 0, 0 },
.usage = "[-F format] [-f filter]",
.flags = CMD_AFTERHOOK,
.exec = cmd_list_buffers_exec
@@ -46,23 +46,33 @@ const struct cmd_entry cmd_list_buffers_entry = {
static enum cmd_retval
cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct paste_buffer *pb;
struct format_tree *ft;
char *line;
const char *template;
const char *template, *filter;
char *line, *expanded;
int flag;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_BUFFERS_TEMPLATE;
filter = args_get(args, 'f');
pb = NULL;
while ((pb = paste_walk(pb)) != NULL) {
ft = format_create(item->client, item, FORMAT_NONE, 0);
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_defaults_paste_buffer(ft, pb);
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
if (filter != NULL) {
expanded = format_expand(ft, filter);
flag = format_true(expanded);
free(expanded);
} else
flag = 1;
if (flag) {
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
}
format_free(ft);
}

View File

@@ -28,10 +28,10 @@
* List all clients.
*/
#define LIST_CLIENTS_TEMPLATE \
"#{client_name}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}]" \
"#{?client_utf8, (utf8),} #{?client_readonly, (ro),}"
#define LIST_CLIENTS_TEMPLATE \
"#{client_name}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}] " \
"#{?client_flags,(,}#{client_flags}#{?client_flags,),}"
static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *);
@@ -51,7 +51,8 @@ const struct cmd_entry cmd_list_clients_entry = {
static enum cmd_retval
cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct client *c;
struct session *s;
struct format_tree *ft;
@@ -60,7 +61,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
char *line;
if (args_has(args, 't'))
s = item->target.s;
s = target->s;
else
s = NULL;
@@ -72,7 +73,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->client, item, FORMAT_NONE, 0);
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", idx);
format_defaults(ft, c, NULL, NULL, NULL);

View File

@@ -36,8 +36,8 @@ const struct cmd_entry cmd_list_keys_entry = {
.name = "list-keys",
.alias = "lsk",
.args = { "T:", 0, 0 },
.usage = "[-T key-table]",
.args = { "1aNP:T:", 0, 1 },
.usage = "[-1aN] [-P prefix-string] [-T key-table] [key]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_keys_exec
@@ -47,32 +47,168 @@ const struct cmd_entry cmd_list_commands_entry = {
.name = "list-commands",
.alias = "lscm",
.args = { "F:", 0, 0 },
.usage = "[-F format]",
.args = { "F:", 0, 1 },
.usage = "[-F format] [command]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_keys_exec
};
static u_int
cmd_list_keys_get_width(const char *tablename, key_code only)
{
struct key_table *table;
struct key_binding *bd;
u_int width, keywidth = 0;
table = key_bindings_get_table(tablename, 0);
if (table == NULL)
return (0);
bd = key_bindings_first(table);
while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) ||
bd->note == NULL ||
*bd->note == '\0') {
bd = key_bindings_next(table, bd);
continue;
}
width = utf8_cstrwidth(key_string_lookup_key(bd->key, 0));
if (width > keywidth)
keywidth = width;
bd = key_bindings_next(table, bd);
}
return (keywidth);
}
static int
cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
const char *tablename, u_int keywidth, key_code only, const char *prefix)
{
struct client *tc = cmdq_get_target_client(item);
struct key_table *table;
struct key_binding *bd;
const char *key;
char *tmp, *note;
int found = 0;
table = key_bindings_get_table(tablename, 0);
if (table == NULL)
return (0);
bd = key_bindings_first(table);
while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) ||
((bd->note == NULL || *bd->note == '\0') &&
!args_has(args, 'a'))) {
bd = key_bindings_next(table, bd);
continue;
}
found = 1;
key = key_string_lookup_key(bd->key, 0);
if (bd->note == NULL || *bd->note == '\0')
note = cmd_list_print(bd->cmdlist, 1);
else
note = xstrdup(bd->note);
tmp = utf8_padcstr(key, keywidth + 1);
if (args_has(args, '1') && tc != NULL) {
status_message_set(tc, -1, 1, 0, "%s%s%s", prefix, tmp,
note);
} else
cmdq_print(item, "%s%s%s", prefix, tmp, note);
free(tmp);
free(note);
if (args_has(args, '1'))
break;
bd = key_bindings_next(table, bd);
}
return (found);
}
static char *
cmd_list_keys_get_prefix(struct args *args, key_code *prefix)
{
char *s;
*prefix = options_get_number(global_s_options, "prefix");
if (!args_has(args, 'P')) {
if (*prefix != KEYC_NONE)
xasprintf(&s, "%s ", key_string_lookup_key(*prefix, 0));
else
s = xstrdup("");
} else
s = xstrdup(args_get(args, 'P'));
return (s);
}
static enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct key_table *table;
struct key_binding *bd;
const char *tablename, *r;
char *key, *cp, tmp[BUFSIZ];
int repeat, width, tablewidth, keywidth;
char *key, *cp, *tmp, *start, *empty;
key_code prefix, only = KEYC_UNKNOWN;
int repeat, width, tablewidth, keywidth, found = 0;
size_t tmpsize, tmpused, cplen;
if (self->entry == &cmd_list_commands_entry)
if (cmd_get_entry(self) == &cmd_list_commands_entry)
return (cmd_list_keys_commands(self, item));
if (args->argc != 0) {
only = key_string_lookup_string(args->argv[0]);
if (only == KEYC_UNKNOWN) {
cmdq_error(item, "invalid key: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
only &= (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS);
}
tablename = args_get(args, 'T');
if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(item, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'N')) {
if (tablename == NULL) {
start = cmd_list_keys_get_prefix(args, &prefix);
keywidth = cmd_list_keys_get_width("root", only);
if (prefix != KEYC_NONE) {
width = cmd_list_keys_get_width("prefix", only);
if (width == 0)
prefix = KEYC_NONE;
else if (width > keywidth)
keywidth = width;
}
empty = utf8_padcstr("", utf8_cstrwidth(start));
found = cmd_list_keys_print_notes(item, args, "root",
keywidth, only, empty);
if (prefix != KEYC_NONE) {
if (cmd_list_keys_print_notes(item, args,
"prefix", keywidth, only, start))
found = 1;
}
free(empty);
} else {
if (args_has(args, 'P'))
start = xstrdup(args_get(args, 'P'));
else
start = xstrdup("");
keywidth = cmd_list_keys_get_width(tablename, only);
found = cmd_list_keys_print_notes(item, args, tablename,
keywidth, only, start);
}
free(start);
goto out;
}
repeat = 0;
tablewidth = keywidth = 0;
table = key_bindings_first_table ();
@@ -83,7 +219,11 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
}
bd = key_bindings_first(table);
while (bd != NULL) {
key = args_escape(key_string_lookup_key(bd->key));
if (only != KEYC_UNKNOWN && bd->key != only) {
bd = key_bindings_next(table, bd);
continue;
}
key = args_escape(key_string_lookup_key(bd->key, 0));
if (bd->flags & KEY_BINDING_REPEAT)
repeat = 1;
@@ -101,6 +241,9 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
table = key_bindings_next_table(table);
}
tmpsize = 256;
tmp = xmalloc(tmpsize);
table = key_bindings_first_table ();
while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
@@ -109,7 +252,12 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
}
bd = key_bindings_first(table);
while (bd != NULL) {
key = args_escape(key_string_lookup_key(bd->key));
if (only != KEYC_UNKNOWN && bd->key != only) {
bd = key_bindings_next(table, bd);
continue;
}
found = 1;
key = args_escape(key_string_lookup_key(bd->key, 0));
if (!repeat)
r = "";
@@ -117,20 +265,35 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
r = "-r ";
else
r = " ";
xsnprintf(tmp, sizeof tmp, "%s-T ", r);
tmpused = xsnprintf(tmp, tmpsize, "%s-T ", r);
cp = utf8_padcstr(table->name, tablewidth);
strlcat(tmp, cp, sizeof tmp);
strlcat(tmp, " ", sizeof tmp);
cplen = strlen(cp) + 1;
while (tmpused + cplen + 1 >= tmpsize) {
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize);
free(cp);
cp = utf8_padcstr(key, keywidth);
strlcat(tmp, cp, sizeof tmp);
strlcat(tmp, " ", sizeof tmp);
cplen = strlen(cp) + 1;
while (tmpused + cplen + 1 >= tmpsize) {
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize);
free(cp);
cp = cmd_list_print(bd->cmdlist, 1);
strlcat(tmp, cp, sizeof tmp);
cplen = strlen(cp);
while (tmpused + cplen + 1 >= tmpsize) {
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
strlcat(tmp, cp, tmpsize);
free(cp);
cmdq_print(item, "bind-key %s", tmp);
@@ -141,30 +304,45 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
table = key_bindings_next_table(table);
}
free(tmp);
out:
if (only != KEYC_UNKNOWN && !found) {
cmdq_error(item, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
const struct cmd_entry **entryp;
const struct cmd_entry *entry;
struct format_tree *ft;
const char *template, *s;
const char *template, *s, *command = NULL;
char *line;
if (args->argc != 0)
command = args->argv[0];
if ((template = args_get(args, 'F')) == NULL) {
template = "#{command_list_name}"
"#{?command_list_alias, (#{command_list_alias}),} "
"#{command_list_usage}";
}
ft = format_create(item->client, item, FORMAT_NONE, 0);
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_defaults(ft, NULL, NULL, NULL, NULL);
for (entryp = cmd_table; *entryp != NULL; entryp++) {
entry = *entryp;
if (command != NULL &&
(strcmp(entry->name, command) != 0 &&
(entry->alias == NULL ||
strcmp(entry->alias, command) != 0)))
continue;
format_add(ft, "command_list_name", "%s", entry->name);
if (entry->alias != NULL)

View File

@@ -38,8 +38,8 @@ const struct cmd_entry cmd_list_panes_entry = {
.name = "list-panes",
.alias = "lsp",
.args = { "asF:t:", 0, 0 },
.usage = "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE,
.args = { "asF:f:t:", 0, 0 },
.usage = "[-as] [-F format] [-f filter] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
@@ -50,9 +50,10 @@ const struct cmd_entry cmd_list_panes_entry = {
static enum cmd_retval
cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct session *s = target->s;
struct winlink *wl = target->wl;
if (args_has(args, 'a'))
cmd_list_panes_server(self, item);
@@ -87,12 +88,13 @@ static void
cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
struct cmdq_item *item, int type)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct window_pane *wp;
u_int n;
struct format_tree *ft;
const char *template;
char *line;
const char *template, *filter;
char *line, *expanded;
int flag;
template = args_get(args, 'F');
if (template == NULL) {
@@ -120,16 +122,25 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
break;
}
}
filter = args_get(args, 'f');
n = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
ft = format_create(item->client, item, FORMAT_NONE, 0);
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, wp);
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
if (filter != NULL) {
expanded = format_expand(ft, filter);
flag = format_true(expanded);
free(expanded);
} else
flag = 1;
if (flag) {
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
}
format_free(ft);
n++;

View File

@@ -42,8 +42,8 @@ const struct cmd_entry cmd_list_sessions_entry = {
.name = "list-sessions",
.alias = "ls",
.args = { "F:", 0, 0 },
.usage = "[-F format]",
.args = { "F:f:", 0, 0 },
.usage = "[-F format] [-f filter]",
.flags = CMD_AFTERHOOK,
.exec = cmd_list_sessions_exec
@@ -52,25 +52,35 @@ const struct cmd_entry cmd_list_sessions_entry = {
static enum cmd_retval
cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct session *s;
u_int n;
struct format_tree *ft;
const char *template;
char *line;
const char *template, *filter;
char *line, *expanded;
int flag;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_SESSIONS_TEMPLATE;
filter = args_get(args, 'f');
n = 0;
RB_FOREACH(s, sessions, &sessions) {
ft = format_create(item->client, item, FORMAT_NONE, 0);
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, NULL, NULL);
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
if (filter != NULL) {
expanded = format_expand(ft, filter);
flag = format_true(expanded);
free(expanded);
} else
flag = 1;
if (flag) {
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
}
format_free(ft);
n++;

View File

@@ -28,14 +28,14 @@
*/
#define LIST_WINDOWS_TEMPLATE \
"#{window_index}: #{window_name}#{window_flags} " \
"#{window_index}: #{window_name}#{window_raw_flags} " \
"(#{window_panes} panes) " \
"[#{window_width}x#{window_height}] " \
"[layout #{window_layout}] #{window_id}" \
"#{?window_active, (active),}";
#define LIST_WINDOWS_WITH_SESSION_TEMPLATE \
"#{session_name}:" \
"#{window_index}: #{window_name}#{window_flags} " \
"#{window_index}: #{window_name}#{window_raw_flags} " \
"(#{window_panes} panes) " \
"[#{window_width}x#{window_height}] "
@@ -49,8 +49,8 @@ const struct cmd_entry cmd_list_windows_entry = {
.name = "list-windows",
.alias = "lsw",
.args = { "F:at:", 0, 0 },
.usage = "[-a] [-F format] " CMD_TARGET_SESSION_USAGE,
.args = { "F:f:at:", 0, 0 },
.usage = "[-a] [-F format] [-f filter] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
@@ -61,12 +61,13 @@ const struct cmd_entry cmd_list_windows_entry = {
static enum cmd_retval
cmd_list_windows_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
if (args_has(args, 'a'))
cmd_list_windows_server(self, item);
else
cmd_list_windows_session(self, item->target.s, item, 0);
cmd_list_windows_session(self, target->s, item, 0);
return (CMD_RETURN_NORMAL);
}
@@ -84,12 +85,13 @@ static void
cmd_list_windows_session(struct cmd *self, struct session *s,
struct cmdq_item *item, int type)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct winlink *wl;
u_int n;
struct format_tree *ft;
const char *template;
char *line;
const char *template, *filter;
char *line, *expanded;
int flag;
template = args_get(args, 'F');
if (template == NULL) {
@@ -102,16 +104,25 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
break;
}
}
filter = args_get(args, 'f');
n = 0;
RB_FOREACH(wl, winlinks, &s->windows) {
ft = format_create(item->client, item, FORMAT_NONE, 0);
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, NULL);
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
if (filter != NULL) {
expanded = format_expand(ft, filter);
flag = format_true(expanded);
free(expanded);
} else
flag = 1;
if (flag) {
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
}
format_free(ft);
n++;

View File

@@ -1,103 +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 <stdlib.h>
#include <string.h>
#include "tmux.h"
static u_int cmd_list_next_group = 1;
struct cmd_list *
cmd_list_new(void)
{
struct cmd_list *cmdlist;
cmdlist = xcalloc(1, sizeof *cmdlist);
cmdlist->references = 1;
cmdlist->group = cmd_list_next_group++;
TAILQ_INIT(&cmdlist->list);
return (cmdlist);
}
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
cmd_list_free(struct cmd_list *cmdlist)
{
struct cmd *cmd, *cmd1;
if (--cmdlist->references != 0)
return;
TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) {
TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
cmd_free(cmd);
}
free(cmdlist);
}
char *
cmd_list_print(struct cmd_list *cmdlist, int escaped)
{
struct cmd *cmd;
char *buf, *this;
size_t len;
len = 1;
buf = xcalloc(1, len);
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
this = cmd_print(cmd);
len += strlen(this) + 4;
buf = xrealloc(buf, len);
strlcat(buf, this, len);
if (TAILQ_NEXT(cmd, qentry) != NULL) {
if (escaped)
strlcat(buf, " \\; ", len);
else
strlcat(buf, " ; ", len);
}
free(this);
}
return (buf);
}

View File

@@ -33,151 +33,81 @@
static enum cmd_retval cmd_load_buffer_exec(struct cmd *, struct cmdq_item *);
static void cmd_load_buffer_callback(struct client *, int, void *);
const struct cmd_entry cmd_load_buffer_entry = {
.name = "load-buffer",
.alias = "loadb",
.args = { "b:", 1, 1 },
.usage = CMD_BUFFER_USAGE " path",
.args = { "b:t:w", 1, 1 },
.usage = CMD_BUFFER_USAGE " " CMD_TARGET_CLIENT_USAGE " path",
.flags = CMD_AFTERHOOK,
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL,
.exec = cmd_load_buffer_exec
};
struct cmd_load_buffer_data {
struct client *client;
struct cmdq_item *item;
char *bufname;
char *name;
};
static void
cmd_load_buffer_done(__unused struct client *c, const char *path, int error,
int closed, struct evbuffer *buffer, void *data)
{
struct cmd_load_buffer_data *cdata = data;
struct client *tc = cdata->client;
struct cmdq_item *item = cdata->item;
void *bdata = EVBUFFER_DATA(buffer);
size_t bsize = EVBUFFER_LENGTH(buffer);
void *copy;
char *cause;
if (!closed)
return;
if (error != 0)
cmdq_error(item, "%s: %s", path, strerror(error));
else if (bsize != 0) {
copy = xmalloc(bsize);
memcpy(copy, bdata, bsize);
if (paste_set(copy, bsize, cdata->name, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
free(copy);
} else if (tc != NULL &&
tc->session != NULL &&
(~tc->flags & CLIENT_DEAD))
tty_set_selection(&tc->tty, copy, bsize);
if (tc != NULL)
server_client_unref(tc);
}
cmdq_continue(item);
free(cdata->name);
free(cdata);
}
static enum cmd_retval
cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct cmd_load_buffer_data *cdata;
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 *bufname;
char *pdata = NULL, *new_pdata, *cause;
char *path, *file;
size_t psize;
int ch, error;
const char *bufname = args_get(args, 'b');
char *path;
bufname = NULL;
if (args_has(args, 'b'))
bufname = args_get(args, 'b');
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;
if (bufname != NULL)
cdata->bufname = xstrdup(bufname);
error = server_set_stdin_callback(c, cmd_load_buffer_callback,
cdata, &cause);
if (error != 0) {
cmdq_error(item, "-: %s", cause);
free(cause);
free(cdata);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_WAIT);
cdata = xcalloc(1, sizeof *cdata);
cdata->item = item;
if (bufname != NULL)
cdata->name = xstrdup(bufname);
if (args_has(args, 'w') && tc != NULL) {
cdata->client = tc;
cdata->client->references++;
}
file = server_client_get_path(item->client, path);
path = format_single_from_target(item, args->argv[0]);
file_read(cmdq_get_client(item), path, cmd_load_buffer_done, cdata);
free(path);
f = fopen(file, "rb");
if (f == NULL) {
cmdq_error(item, "%s: %s", file, strerror(errno));
goto error;
}
pdata = NULL;
psize = 0;
while ((ch = getc(f)) != EOF) {
/* Do not let the server die due to memory exhaustion. */
if ((new_pdata = realloc(pdata, psize + 2)) == NULL) {
cmdq_error(item, "realloc error: %s", strerror(errno));
goto error;
}
pdata = new_pdata;
pdata[psize++] = ch;
}
if (ferror(f)) {
cmdq_error(item, "%s: read error", file);
goto error;
}
if (pdata != NULL)
pdata[psize] = '\0';
fclose(f);
free(file);
if (paste_set(pdata, psize, bufname, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(pdata);
free(cause);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
error:
free(pdata);
if (f != NULL)
fclose(f);
free(file);
return (CMD_RETURN_ERROR);
}
static void
cmd_load_buffer_callback(struct client *c, int closed, void *data)
{
struct cmd_load_buffer_data *cdata = data;
char *pdata, *cause, *saved;
size_t psize;
if (!closed)
return;
c->stdin_callback = NULL;
server_client_unref(c);
if (c->flags & CLIENT_DEAD)
goto out;
psize = EVBUFFER_LENGTH(c->stdin_data);
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL)
goto out;
memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize);
pdata[psize] = '\0';
evbuffer_drain(c->stdin_data, psize);
if (paste_set(pdata, psize, cdata->bufname, &cause) != 0) {
/* No context so can't use server_client_msg_error. */
if (~c->flags & CLIENT_UTF8) {
saved = cause;
cause = utf8_sanitize(saved);
free(saved);
}
evbuffer_add_printf(c->stderr_data, "%s", cause);
server_client_push_stderr(c);
free(pdata);
free(cause);
}
out:
cdata->item->flags &= ~CMDQ_WAITING;
free(cdata->bufname);
free(cdata);
return (CMD_RETURN_WAIT);
}

View File

@@ -57,25 +57,22 @@ const struct cmd_entry cmd_lock_client_entry = {
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE,
.flags = CMD_AFTERHOOK,
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
.exec = cmd_lock_server_exec
};
static enum cmd_retval
cmd_lock_server_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c;
struct cmd_find_state *target = cmdq_get_target(item);
struct client *tc = cmdq_get_target_client(item);
if (self->entry == &cmd_lock_server_entry)
if (cmd_get_entry(self) == &cmd_lock_server_entry)
server_lock();
else if (self->entry == &cmd_lock_session_entry)
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);
}
else if (cmd_get_entry(self) == &cmd_lock_session_entry)
server_lock_session(target->s);
else
server_lock_client(tc);
recalculate_sizes();
return (CMD_RETURN_NORMAL);

View File

@@ -32,8 +32,8 @@ const struct cmd_entry cmd_move_window_entry = {
.name = "move-window",
.alias = "movew",
.args = { "adkrs:t:", 0, 0 },
.usage = "[-dkr] " CMD_SRCDST_WINDOW_USAGE,
.args = { "abdkrs:t:", 0, 0 },
.usage = "[-abdkr] " CMD_SRCDST_WINDOW_USAGE,
.source = { 's', CMD_FIND_WINDOW, 0 },
/* -t is special */
@@ -46,8 +46,8 @@ const struct cmd_entry cmd_link_window_entry = {
.name = "link-window",
.alias = "linkw",
.args = { "adks:t:", 0, 0 },
.usage = "[-dk] " CMD_SRCDST_WINDOW_USAGE,
.args = { "abdks:t:", 0, 0 },
.usage = "[-abdk] " CMD_SRCDST_WINDOW_USAGE,
.source = { 's', CMD_FIND_WINDOW, 0 },
/* -t is special */
@@ -59,49 +59,53 @@ const struct cmd_entry cmd_link_window_entry = {
static enum cmd_retval
cmd_move_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
const char *tflag = args_get(args, 't');
struct session *src;
struct session *dst;
struct winlink *wl;
char *cause;
int idx, kflag, dflag, sflag;
struct args *args = cmd_get_args(self);
struct cmd_find_state *source = cmdq_get_source(item);
struct cmd_find_state target;
const char *tflag = args_get(args, 't');
struct session *src = source->s;
struct session *dst;
struct winlink *wl = source->wl;
char *cause;
int idx, kflag, dflag, sflag, before;
if (args_has(args, 'r')) {
if (cmd_find_target(&item->target, item, tflag,
CMD_FIND_SESSION, CMD_FIND_QUIET) != 0)
if (cmd_find_target(&target, item, tflag, CMD_FIND_SESSION,
CMD_FIND_QUIET) != 0)
return (CMD_RETURN_ERROR);
session_renumber_windows(item->target.s);
session_renumber_windows(target.s);
recalculate_sizes();
server_status_session(item->target.s);
server_status_session(target.s);
return (CMD_RETURN_NORMAL);
}
if (cmd_find_target(&item->target, item, tflag, CMD_FIND_WINDOW,
if (cmd_find_target(&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;
dst = target.s;
idx = target.idx;
kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd');
sflag = args_has(self->args, 's');
kflag = args_has(args, 'k');
dflag = args_has(args, 'd');
sflag = args_has(args, 's');
if (args_has(self->args, 'a')) {
if ((idx = winlink_shuffle_up(dst, dst->curw)) == -1)
before = args_has(args, 'b');
if (args_has(args, 'a') || before) {
if (target.wl != NULL)
idx = winlink_shuffle_up(dst, target.wl, before);
else
idx = winlink_shuffle_up(dst, dst->curw, before);
if (idx == -1)
return (CMD_RETURN_ERROR);
}
if (server_link_window(src, wl, dst, idx, kflag, !dflag,
&cause) != 0) {
cmdq_error(item, "can't link window: %s", cause);
if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (self->entry == &cmd_move_window_entry)
if (cmd_get_entry(self) == &cmd_move_window_entry)
server_unlink_window(src, wl);
/*

View File

@@ -39,10 +39,10 @@ const struct cmd_entry cmd_new_session_entry = {
.name = "new-session",
.alias = "new",
.args = { "Ac:dDEF:n:Ps:t:x:y:", 0, -1 },
.usage = "[-AdDEP] [-c start-directory] [-F format] [-n window-name] "
"[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
"[-y height] [command]",
.args = { "Ac:dDe:EF:f:n:Ps:t:x:Xy:", 0, -1 },
.usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] "
"[-f flags] [-n window-name] [-s session-name] "
CMD_TARGET_SESSION_USAGE " [-x width] [-y height] [command]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@@ -66,22 +66,26 @@ const struct cmd_entry cmd_has_session_entry = {
static enum cmd_retval
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 args *args = cmd_get_args(self);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct client *c = cmdq_get_client(item);
struct session *s, *as, *groupwith = NULL;
struct environ *env;
struct options *oo;
struct termios tio, *tiop;
struct session_group *sg;
const char *errstr, *template, *group, *prefix, *tmp;
struct session_group *sg = NULL;
const char *errstr, *template, *group, *tmp, *add;
char *cause, *cwd = NULL, *cp, *newname = NULL;
char *name, *prefix = 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;
struct args_value *value;
if (self->entry == &cmd_has_session_entry) {
if (cmd_get_entry(self) == &cmd_has_session_entry) {
/*
* cmd_find_target() will fail if the session cannot be found,
* so always return success here.
@@ -94,48 +98,44 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
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);
goto fail;
}
if ((as = session_find(newname)) != NULL) {
if (args_has(args, 'A')) {
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);
goto fail;
tmp = args_get(args, 's');
if (tmp != NULL) {
name = format_single(item, tmp, c, NULL, NULL, NULL);
newname = session_check_name(name);
free(name);
}
if (args_has(args, 'A')) {
if (newname != NULL)
as = session_find(newname);
else
as = target->s;
if (as != NULL) {
retval = cmd_attach_session(item, as->name,
args_has(args, 'D'), args_has(args, 'X'), 0, NULL,
args_has(args, 'E'), args_get(args, 'f'));
free(newname);
return (retval);
}
}
if (newname != NULL && session_find(newname) != NULL) {
cmdq_error(item, "duplicate session: %s", newname);
goto fail;
}
/* Is this going to be part of a session group? */
group = args_get(args, 't');
if (group != NULL) {
groupwith = item->target.s;
if (groupwith == NULL) {
if (!session_check_name(group)) {
cmdq_error(item, "bad group name: %s", group);
goto fail;
}
groupwith = target->s;
if (groupwith == NULL)
sg = session_group_find(group);
} else
else
sg = session_group_contains(groupwith);
if (sg != NULL)
prefix = sg->name;
prefix = xstrdup(sg->name);
else if (groupwith != NULL)
prefix = groupwith->name;
prefix = xstrdup(groupwith->name);
else
prefix = group;
} else {
groupwith = NULL;
sg = NULL;
prefix = NULL;
prefix = session_check_name(group);
}
/* Set -d if no client. */
@@ -165,13 +165,16 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
* the terminal as that calls tcsetattr() to prepare for tmux taking
* over.
*/
if (!detached && !already_attached && c->tty.fd != -1) {
if (server_client_check_nested(item->client)) {
if (!detached &&
!already_attached &&
c->fd != -1 &&
(~c->flags & CLIENT_CONTROL)) {
if (server_client_check_nested(cmdq_get_client(item))) {
cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force");
goto fail;
}
if (tcgetattr(c->tty.fd, &tio) != 0)
if (tcgetattr(c->fd, &tio) != 0)
fatal("tcgetattr failed");
tiop = &tio;
} else
@@ -201,7 +204,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
goto fail;
}
}
}
} else
dsx = 80;
if (args_has(args, 'y')) {
tmp = args_get(args, 'y');
if (strcmp(tmp, "-") == 0) {
@@ -216,7 +220,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
goto fail;
}
}
}
} else
dsy = 24;
/* Find new session size. */
if (!detached && !is_control) {
@@ -227,13 +232,14 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
} else {
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;
} else {
if (args_has(args, 'x'))
sx = dsx;
if (args_has(args, 'y'))
sy = dsy;
}
}
if (sx == 0)
sx = 1;
@@ -252,12 +258,18 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
env = environ_create();
if (c != NULL && !args_has(args, 'E'))
environ_update(global_s_options, c->environ, env);
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(env, add, 0);
add = args_next_value(&value);
}
s = session_create(prefix, newname, cwd, env, oo, tiop);
/* Spawn the initial window. */
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
sc.tc = c;
sc.name = args_get(args, 'n');
sc.argc = args->argc;
@@ -298,13 +310,15 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
* taking this session and needs to get MSG_READY and stay around.
*/
if (!detached) {
if (args_has(args, 'f'))
server_client_set_flags(c, args_get(args, 'f'));
if (!already_attached) {
if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0);
} else if (c->session != NULL)
c->last_session = c->session;
c->session = s;
if (~item->shared->flags & CMDQ_SHARED_REPEAT)
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
@@ -327,25 +341,27 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = NEW_SESSION_TEMPLATE;
cp = format_single(item, template, c, s, NULL, NULL);
cp = format_single(item, template, c, s, s->curw, NULL);
cmdq_print(item, "%s", cp);
free(cp);
}
if (!detached) {
if (!detached)
c->flags |= CLIENT_ATTACHED;
cmd_find_from_session(&item->shared->current, s, 0);
}
if (!args_has(args, 'd'))
cmd_find_from_session(current, s, 0);
cmd_find_from_session(&fs, s, 0);
cmdq_insert_hook(s, item, &fs, "after-new-session");
free(cwd);
free(newname);
free(prefix);
return (CMD_RETURN_NORMAL);
fail:
free(cwd);
free(newname);
free(prefix);
return (CMD_RETURN_ERROR);
}

View File

@@ -38,8 +38,8 @@ const struct cmd_entry cmd_new_window_entry = {
.name = "new-window",
.alias = "neww",
.args = { "ac:de:F:kn:Pt:", 0, -1 },
.usage = "[-adkP] [-c start-directory] [-e environment] [-F format] "
.args = { "abc:de:F:kn:PSt:", 0, -1 },
.usage = "[-abdkPS] [-c start-directory] [-e environment] [-F format] "
"[-n window-name] " CMD_TARGET_WINDOW_USAGE " [command]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
@@ -51,27 +51,61 @@ const struct cmd_entry cmd_new_window_entry = {
static enum cmd_retval
cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
struct args *args = cmd_get_args(self);
struct client *c = cmdq_get_client(item);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
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;
struct client *tc = cmdq_get_target_client(item);
struct session *s = target->s;
struct winlink *wl = target->wl;
int idx = target->idx, before;
struct winlink *new_wl = NULL;
char *cause = NULL, *cp;
const char *template, *add;
const char *template, *add, *name;
struct cmd_find_state fs;
struct args_value *value;
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);
/*
* If -S and -n are given and -t is not and a single window with this
* name already exists, select it.
*/
name = args_get(args, 'n');
if (args_has(args, 'S') && name != NULL && target->idx == -1) {
RB_FOREACH(wl, winlinks, &s->windows) {
if (strcmp(wl->window->name, name) != 0)
continue;
if (new_wl == NULL) {
new_wl = wl;
continue;
}
cmdq_error(item, "multiple windows named %s", name);
return (CMD_RETURN_ERROR);
}
if (new_wl != NULL) {
if (args_has(args, 'd'))
return (CMD_RETURN_NORMAL);
if (session_set_current(s, new_wl) == 0)
server_redraw_session(s);
if (c != NULL && c->session != NULL)
s->curw->window->latest = c;
recalculate_sizes();
return (CMD_RETURN_NORMAL);
}
}
before = args_has(args, 'b');
if (args_has(args, 'a') || before) {
idx = winlink_shuffle_up(s, wl, before);
if (idx == -1)
idx = target->idx;
}
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
sc.tc = tc;
sc.name = args_get(args, 'n');
sc.argc = args->argc;
@@ -80,7 +114,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
environ_put(sc.environ, add, 0);
add = args_next_value(&value);
}
@@ -107,7 +141,8 @@ 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, new_wl, NULL);
cp = format_single(item, template, tc, s, new_wl,
new_wl->window->active);
cmdq_print(item, "%s", cp);
free(cp);
}

View File

@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wchar.h>
#include "tmux.h"
@@ -42,7 +43,6 @@ struct cmd_parse_scope {
};
struct cmd_parse_command {
char *name;
u_int line;
int argc;
@@ -77,6 +77,9 @@ static char *cmd_parse_get_error(const char *, u_int, const char *);
static void cmd_parse_free_command(struct cmd_parse_command *);
static struct cmd_parse_commands *cmd_parse_new_commands(void);
static void cmd_parse_free_commands(struct cmd_parse_commands *);
static char *cmd_parse_commands_to_string(struct cmd_parse_commands *);
static void cmd_parse_print_commands(struct cmd_parse_input *, u_int,
struct cmd_list *);
%}
@@ -97,6 +100,7 @@ static void cmd_parse_free_commands(struct cmd_parse_commands *);
}
%token ERROR
%token HIDDEN
%token IF
%token ELSE
%token ELIF
@@ -107,7 +111,8 @@ static void cmd_parse_free_commands(struct cmd_parse_commands *);
%type <arguments> arguments
%type <flag> if_open if_elif
%type <elif> elif elif1
%type <commands> statements statement commands condition condition1
%type <commands> argument_statements statements statement
%type <commands> commands condition condition1
%type <command> command
%%
@@ -131,7 +136,17 @@ statements : statement '\n'
free($2);
}
statement : condition
statement : /* empty */
{
$$ = xmalloc (sizeof *$$);
TAILQ_INIT($$);
}
| hidden_assignment
{
$$ = xmalloc (sizeof *$$);
TAILQ_INIT($$);
}
| condition
{
struct cmd_parse_state *ps = &parse_state;
@@ -142,11 +157,6 @@ statement : condition
cmd_parse_free_commands($1);
}
}
| assignment
{
$$ = xmalloc (sizeof *$$);
TAILQ_INIT($$);
}
| commands
{
struct cmd_parse_state *ps = &parse_state;
@@ -174,36 +184,49 @@ expanded : format
struct cmd_parse_input *pi = ps->input;
struct format_tree *ft;
struct client *c = pi->c;
struct cmd_find_state *fs;
struct cmd_find_state *fsp;
struct cmd_find_state fs;
int flags = FORMAT_NOJOBS;
if (cmd_find_valid_state(&pi->fs))
fs = &pi->fs;
else
fs = NULL;
fsp = &pi->fs;
else {
cmd_find_from_client(&fs, c, 0);
fsp = &fs;
}
ft = format_create(NULL, pi->item, FORMAT_NONE, flags);
if (fs != NULL)
format_defaults(ft, c, fs->s, fs->wl, fs->wp);
else
format_defaults(ft, c, NULL, NULL, NULL);
format_defaults(ft, c, fsp->s, fsp->wl, fsp->wp);
$$ = format_expand(ft, $1);
format_free(ft);
free($1);
}
assignment : /* empty */
| EQUALS
optional_assignment : /* empty */
| assignment
assignment : EQUALS
{
struct cmd_parse_state *ps = &parse_state;
int flags = ps->input->flags;
if ((~flags & CMD_PARSE_PARSEONLY) &&
(ps->scope == NULL || ps->scope->flag))
environ_put(global_environ, $1);
environ_put(global_environ, $1, 0);
free($1);
}
hidden_assignment : HIDDEN EQUALS
{
struct cmd_parse_state *ps = &parse_state;
int flags = ps->input->flags;
if ((~flags & CMD_PARSE_PARSEONLY) &&
(ps->scope == NULL || ps->scope->flag))
environ_put(global_environ, $2, ENVIRON_HIDDEN);
free($2);
}
if_open : IF expanded
{
struct cmd_parse_state *ps = &parse_state;
@@ -337,7 +360,8 @@ commands : command
struct cmd_parse_state *ps = &parse_state;
$$ = cmd_parse_new_commands();
if (ps->scope == NULL || ps->scope->flag)
if ($1->argc != 0 &&
(ps->scope == NULL || ps->scope->flag))
TAILQ_INSERT_TAIL($$, $1, entry);
else
cmd_parse_free_command($1);
@@ -356,7 +380,8 @@ commands : command
{
struct cmd_parse_state *ps = &parse_state;
if (ps->scope == NULL || ps->scope->flag) {
if ($3->argc != 0 &&
(ps->scope == NULL || ps->scope->flag)) {
$$ = $1;
TAILQ_INSERT_TAIL($$, $3, entry);
} else {
@@ -370,25 +395,33 @@ commands : command
$$ = $1;
}
command : assignment TOKEN
command : assignment
{
struct cmd_parse_state *ps = &parse_state;
$$ = xcalloc(1, sizeof *$$);
$$->line = ps->input->line;
}
| optional_assignment TOKEN
{
struct cmd_parse_state *ps = &parse_state;
$$ = xcalloc(1, sizeof *$$);
$$->name = $2;
$$->line = ps->input->line;
cmd_prepend_argv(&$$->argc, &$$->argv, $2);
}
| assignment TOKEN arguments
| optional_assignment TOKEN arguments
{
struct cmd_parse_state *ps = &parse_state;
$$ = xcalloc(1, sizeof *$$);
$$->name = $2;
$$->line = ps->input->line;
$$->argc = $3.argc;
$$->argv = $3.argv;
cmd_prepend_argv(&$$->argc, &$$->argv, $2);
}
condition1 : if_open commands if_close
@@ -492,6 +525,22 @@ argument : TOKEN
{
$$ = $1;
}
| '{' argument_statements
{
$$ = cmd_parse_commands_to_string($2);
cmd_parse_free_commands($2);
}
argument_statements : statement '}'
{
$$ = $1;
}
| statements statement '}'
{
$$ = $1;
TAILQ_CONCAT($$, $2, entry);
free($2);
}
%%
@@ -507,10 +556,25 @@ cmd_parse_get_error(const char *file, u_int line, const char *error)
return (s);
}
static void
cmd_parse_print_commands(struct cmd_parse_input *pi, u_int line,
struct cmd_list *cmdlist)
{
char *s;
if (pi->item != NULL && (pi->flags & CMD_PARSE_VERBOSE)) {
s = cmd_list_print(cmdlist, 0);
if (pi->file != NULL)
cmdq_print(pi->item, "%s:%u: %s", pi->file, line, s);
else
cmdq_print(pi->item, "%u: %s", line, s);
free(s);
}
}
static void
cmd_parse_free_command(struct cmd_parse_command *cmd)
{
free(cmd->name);
cmd_free_argv(cmd->argc, cmd->argv);
free(cmd);
}
@@ -537,6 +601,30 @@ cmd_parse_free_commands(struct cmd_parse_commands *cmds)
free(cmds);
}
static char *
cmd_parse_commands_to_string(struct cmd_parse_commands *cmds)
{
struct cmd_parse_command *cmd;
char *string = NULL, *s, *line;
TAILQ_FOREACH(cmd, cmds, entry) {
line = cmd_stringify_argv(cmd->argc, cmd->argv);
if (string == NULL)
s = line;
else {
xasprintf(&s, "%s ; %s", s, line);
free(line);
}
free(string);
string = s;
}
if (string == NULL)
string = xstrdup("");
log_debug("%s: %s", __func__, string);
return (string);
}
static struct cmd_parse_commands *
cmd_parse_run_parser(char **cause)
{
@@ -597,7 +685,7 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds,
int i;
struct cmd_list *cmdlist = NULL, *result;
struct cmd *add;
char *alias, *cause, *s;
char *name, *alias, *cause, *s;
/* Check for an empty list. */
if (TAILQ_EMPTY(cmds)) {
@@ -613,12 +701,14 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds,
* command list.
*/
TAILQ_FOREACH_SAFE(cmd, cmds, entry, next) {
alias = cmd_get_alias(cmd->name);
name = cmd->argv[0];
alias = cmd_get_alias(name);
if (alias == NULL)
continue;
line = cmd->line;
log_debug("%s: %u %s = %s", __func__, line, cmd->name, alias);
log_debug("%s: %u %s = %s", __func__, line, name, alias);
pi->line = line;
cmds2 = cmd_parse_do_buffer(alias, strlen(alias), pi, &cause);
@@ -635,7 +725,7 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds,
cmd_parse_free_command(cmd);
continue;
}
for (i = 0; i < cmd->argc; i++)
for (i = 1; i < cmd->argc; i++)
cmd_append_argv(&cmd2->argc, &cmd2->argv, cmd->argv[i]);
after = cmd;
@@ -653,16 +743,20 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds,
/*
* Parse each command into a command list. Create a new command list
* for each line so they get a new group (so the queue knows which ones
* to remove if a command fails when executed).
* for each line (unless the flag is set) so they get a new group (so
* the queue knows which ones to remove if a command fails when
* executed).
*/
result = cmd_list_new();
TAILQ_FOREACH(cmd, cmds, entry) {
log_debug("%s: %u %s", __func__, cmd->line, cmd->name);
name = cmd->argv[0];
log_debug("%s: %u %s", __func__, cmd->line, name);
cmd_log_argv(cmd->argc, cmd->argv, __func__);
if (cmdlist == NULL || cmd->line != line) {
if (cmdlist == NULL ||
((~pi->flags & CMD_PARSE_ONEGROUP) && cmd->line != line)) {
if (cmdlist != NULL) {
cmd_parse_print_commands(pi, line, cmdlist);
cmd_list_move(result, cmdlist);
cmd_list_free(cmdlist);
}
@@ -670,18 +764,19 @@ cmd_parse_build_commands(struct cmd_parse_commands *cmds,
}
line = cmd->line;
cmd_prepend_argv(&cmd->argc, &cmd->argv, cmd->name);
add = cmd_parse(cmd->argc, cmd->argv, pi->file, line, &cause);
if (add == NULL) {
cmd_list_free(result);
pr.status = CMD_PARSE_ERROR;
pr.error = cmd_parse_get_error(pi->file, line, cause);
free(cause);
cmd_list_free(cmdlist);
goto out;
}
cmd_list_append(cmdlist, add);
}
if (cmdlist != NULL) {
cmd_parse_print_commands(pi, line, cmdlist);
cmd_list_move(result, cmdlist);
cmd_list_free(cmdlist);
}
@@ -724,6 +819,77 @@ cmd_parse_from_file(FILE *f, struct cmd_parse_input *pi)
struct cmd_parse_result *
cmd_parse_from_string(const char *s, struct cmd_parse_input *pi)
{
struct cmd_parse_input input;
if (pi == NULL) {
memset(&input, 0, sizeof input);
pi = &input;
}
/*
* When parsing a string, put commands in one group even if there are
* multiple lines. This means { a \n b } is identical to "a ; b" when
* given as an argument to another command.
*/
pi->flags |= CMD_PARSE_ONEGROUP;
return (cmd_parse_from_buffer(s, strlen(s), pi));
}
enum cmd_parse_status
cmd_parse_and_insert(const char *s, struct cmd_parse_input *pi,
struct cmdq_item *after, struct cmdq_state *state, char **error)
{
struct cmd_parse_result *pr;
struct cmdq_item *item;
pr = cmd_parse_from_string(s, pi);
switch (pr->status) {
case CMD_PARSE_EMPTY:
break;
case CMD_PARSE_ERROR:
if (error != NULL)
*error = pr->error;
else
free(pr->error);
break;
case CMD_PARSE_SUCCESS:
item = cmdq_get_command(pr->cmdlist, state);
cmdq_insert_after(after, item);
cmd_list_free(pr->cmdlist);
break;
}
return (pr->status);
}
enum cmd_parse_status
cmd_parse_and_append(const char *s, struct cmd_parse_input *pi,
struct client *c, struct cmdq_state *state, char **error)
{
struct cmd_parse_result *pr;
struct cmdq_item *item;
pr = cmd_parse_from_string(s, pi);
switch (pr->status) {
case CMD_PARSE_EMPTY:
break;
case CMD_PARSE_ERROR:
if (error != NULL)
*error = pr->error;
else
free(pr->error);
break;
case CMD_PARSE_SUCCESS:
item = cmdq_get_command(pr->cmdlist, state);
cmdq_append(c, item);
cmd_list_free(pr->cmdlist);
break;
}
return (pr->status);
}
struct cmd_parse_result *
cmd_parse_from_buffer(const void *buf, size_t len, struct cmd_parse_input *pi)
{
static struct cmd_parse_result pr;
struct cmd_parse_input input;
@@ -736,14 +902,14 @@ cmd_parse_from_string(const char *s, struct cmd_parse_input *pi)
}
memset(&pr, 0, sizeof pr);
if (*s == '\0') {
if (len == 0) {
pr.status = CMD_PARSE_EMPTY;
pr.cmdlist = NULL;
pr.error = NULL;
return (&pr);
}
cmds = cmd_parse_do_buffer(s, strlen(s), pi, &cause);
cmds = cmd_parse_do_buffer(buf, len, pi, &cause);
if (cmds == NULL) {
pr.status = CMD_PARSE_ERROR;
pr.error = cause;
@@ -797,11 +963,10 @@ cmd_parse_from_arguments(int argc, char **argv, struct cmd_parse_input *pi)
i);
cmd = xcalloc(1, sizeof *cmd);
cmd->name = xstrdup(new_argv[0]);
cmd->line = pi->line;
cmd->argc = new_argc - 1;
cmd->argv = cmd_copy_argv(new_argc - 1, new_argv + 1);
cmd->argc = new_argc;
cmd->argv = cmd_copy_argv(new_argc, new_argv);
TAILQ_INSERT_TAIL(cmds, cmd, entry);
}
@@ -817,11 +982,10 @@ cmd_parse_from_arguments(int argc, char **argv, struct cmd_parse_input *pi)
last);
cmd = xcalloc(1, sizeof *cmd);
cmd->name = xstrdup(new_argv[0]);
cmd->line = pi->line;
cmd->argc = new_argc - 1;
cmd->argv = cmd_copy_argv(new_argc - 1, new_argv + 1);
cmd->argc = new_argc;
cmd->argv = cmd_copy_argv(new_argc, new_argv);
TAILQ_INSERT_TAIL(cmds, cmd, entry);
}
@@ -999,11 +1163,11 @@ yylex(void)
return ('\n');
}
if (ch == ';') {
if (ch == ';' || ch == '{' || ch == '}') {
/*
* A semicolon is itself.
* A semicolon or { or } is itself.
*/
return (';');
return (ch);
}
if (ch == '#') {
@@ -1040,6 +1204,10 @@ yylex(void)
if (*cp == '\0')
return (TOKEN);
ps->condition = 1;
if (strcmp(yylval.token, "%hidden") == 0) {
free(yylval.token);
return (HIDDEN);
}
if (strcmp(yylval.token, "%if") == 0) {
free(yylval.token);
return (IF);
@@ -1124,17 +1292,53 @@ error:
static int
yylex_token_escape(char **buf, size_t *len)
{
int ch, type;
u_int size, i, tmp;
char s[9];
struct utf8_data ud;
int ch, type, o2, o3, mlen;
u_int size, i, tmp;
char s[9], m[MB_LEN_MAX];
switch (ch = yylex_getc()) {
ch = yylex_getc();
if (ch >= '4' && ch <= '7') {
yyerror("invalid octal escape");
return (0);
}
if (ch >= '0' && ch <= '3') {
o2 = yylex_getc();
if (o2 >= '0' && o2 <= '7') {
o3 = yylex_getc();
if (o3 >= '0' && o3 <= '7') {
ch = 64 * (ch - '0') +
8 * (o2 - '0') +
(o3 - '0');
yylex_append1(buf, len, ch);
return (1);
}
}
yyerror("invalid octal escape");
return (0);
}
switch (ch) {
case EOF:
return (0);
case 'a':
ch = '\a';
break;
case 'b':
ch = '\b';
break;
case 'e':
ch = '\033';
break;
case 'f':
ch = '\f';
break;
case 's':
ch = ' ';
break;
case 'v':
ch = '\v';
break;
case 'r':
ch = '\r';
break;
@@ -1175,11 +1379,12 @@ unicode:
yyerror("invalid \\%c argument", type);
return (0);
}
if (utf8_split(tmp, &ud) != UTF8_DONE) {
mlen = wctomb(m, tmp);
if (mlen <= 0 || mlen > (int)sizeof m) {
yyerror("invalid \\%c argument", type);
return (0);
}
yylex_append(buf, len, ud.data, ud.size);
yylex_append(buf, len, m, mlen);
return (1);
}
@@ -1188,7 +1393,7 @@ yylex_token_variable(char **buf, size_t *len)
{
struct environ_entry *envent;
int ch, brackets = 0;
char name[BUFSIZ];
char name[1024];
size_t namelen = 0;
const char *value;
@@ -1227,7 +1432,7 @@ yylex_token_variable(char **buf, size_t *len)
name[namelen] = '\0';
envent = environ_find(global_environ, name);
if (envent != NULL) {
if (envent != NULL && envent->value != NULL) {
value = envent->value;
log_debug("%s: %s -> %s", __func__, name, value);
yylex_append(buf, len, value, strlen(value));
@@ -1240,7 +1445,7 @@ yylex_token_tilde(char **buf, size_t *len)
{
struct environ_entry *envent;
int ch;
char name[BUFSIZ];
char name[1024];
size_t namelen = 0;
struct passwd *pw;
const char *home = NULL;
@@ -1277,99 +1482,6 @@ yylex_token_tilde(char **buf, size_t *len)
return (1);
}
static int
yylex_token_brace(char **buf, size_t *len)
{
struct cmd_parse_state *ps = &parse_state;
int ch, nesting = 1, escape = 0, quote = '\0';
int lines = 0;
/*
* Extract a string up to the matching unquoted '}', including newlines
* and handling nested braces.
*
* To detect the final and intermediate braces which affect the nesting
* depth, we scan the input as if it was a tmux config file, and ignore
* braces which would be considered quoted, escaped, or in a comment.
*
* The result is verbatim copy of the input excluding the final brace.
*/
for (ch = yylex_getc1(); ch != EOF; ch = yylex_getc1()) {
yylex_append1(buf, len, ch);
if (ch == '\n')
lines++;
/*
* If the previous character was a backslash (escape is set),
* escape anything if unquoted or in double quotes, otherwise
* escape only '\n' and '\\'.
*/
if (escape &&
(quote == '\0' ||
quote == '"' ||
ch == '\n' ||
ch == '\\')) {
escape = 0;
continue;
}
/*
* The character is not escaped. If it is a backslash, set the
* escape flag.
*/
if (ch == '\\') {
escape = 1;
continue;
}
escape = 0;
/* A newline always resets to unquoted. */
if (ch == '\n') {
quote = 0;
continue;
}
if (quote) {
/*
* Inside quotes or comment. Check if this is the
* closing quote.
*/
if (ch == quote && quote != '#')
quote = 0;
} else {
/* Not inside quotes or comment. */
switch (ch) {
case '"':
case '\'':
case '#':
/* Beginning of quote or comment. */
quote = ch;
break;
case '{':
nesting++;
break;
case '}':
nesting--;
if (nesting == 0) {
(*len)--; /* remove closing } */
ps->input->line += lines;
return (1);
}
break;
}
}
}
/*
* Update line count after error as reporting the opening line
* is more useful than EOF.
*/
yyerror("unterminated brace string");
ps->input->line += lines;
return (0);
}
static char *
yylex_token(int ch)
{
@@ -1384,23 +1496,37 @@ yylex_token(int ch)
buf = xmalloc(1);
for (;;) {
/*
* EOF or \n are always the end of the token. If inside quotes
* they are an error.
*/
if (ch == EOF || ch == '\n') {
if (state != NONE)
goto error;
/* EOF or \n are always the end of the token. */
if (ch == EOF || (state == NONE && ch == '\n'))
break;
/* Whitespace or ; or } ends a token unless inside quotes. */
if ((ch == ' ' || ch == '\t' || ch == ';' || ch == '}') &&
state == NONE)
break;
/*
* Spaces and comments inside quotes after \n are removed but
* the \n is left.
*/
if (ch == '\n' && state != NONE) {
yylex_append1(&buf, &len, '\n');
while ((ch = yylex_getc()) == ' ' || ch == '\t')
/* nothing */;
if (ch != '#')
continue;
ch = yylex_getc();
if (strchr(",#{}:", ch) != NULL) {
yylex_ungetc(ch);
ch = '#';
} else {
while ((ch = yylex_getc()) != '\n' && ch != EOF)
/* nothing */;
}
continue;
}
/* Whitespace or ; ends a token unless inside quotes. */
if ((ch == ' ' || ch == '\t' || ch == ';') && state == NONE)
break;
/*
* \ ~ and $ are expanded except in single quotes.
*/
/* \ ~ and $ are expanded except in single quotes. */
if (ch == '\\' && state != SINGLE_QUOTES) {
if (!yylex_token_escape(&buf, &len))
goto error;
@@ -1416,17 +1542,10 @@ yylex_token(int ch)
goto error;
goto skip;
}
if (ch == '{' && state == NONE) {
if (!yylex_token_brace(&buf, &len))
goto error;
goto skip;
}
if (ch == '}' && state == NONE)
goto error; /* unmatched (matched ones were handled) */
/*
* ' and " starts or end quotes (and is consumed).
*/
/* ' and " starts or end quotes (and is consumed). */
if (ch == '\'') {
if (state == NONE) {
state = SINGLE_QUOTES;
@@ -1448,9 +1567,7 @@ yylex_token(int ch)
}
}
/*
* Otherwise add the character to the buffer.
*/
/* Otherwise add the character to the buffer. */
yylex_append1(&buf, &len, ch);
skip:

View File

@@ -46,8 +46,9 @@ const struct cmd_entry cmd_paste_buffer_entry = {
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->target.wp;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct window_pane *wp = target->wp;
struct paste_buffer *pb;
const char *sepstr, *bufname, *bufdata, *bufend, *line;
size_t seplen, bufsize;

View File

@@ -55,15 +55,17 @@ const struct cmd_entry cmd_pipe_pane_entry = {
static enum cmd_retval
cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
{
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;
char *cmd;
int old_fd, pipe_fd[2], null_fd, in, out;
struct format_tree *ft;
sigset_t set, oldset;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct client *tc = cmdq_get_target_client(item);
struct window_pane *wp = target->wp;
struct session *s = target->s;
struct winlink *wl = target->wl;
struct window_pane_offset *wpo = &wp->pipe_offset;
char *cmd;
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;
@@ -88,13 +90,13 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
*
* bind ^p pipep -o 'cat >>~/output'
*/
if (args_has(self->args, 'o') && old_fd != -1)
if (args_has(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')) {
if (args_has(args, 'I')) {
in = 1;
out = args_has(self->args, 'O');
out = args_has(args, 'O');
} else {
in = 0;
out = 1;
@@ -107,8 +109,8 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
}
/* Expand the command. */
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, c, s, wl, wp);
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_defaults(ft, tc, s, wl, wp);
cmd = format_expand_time(ft, args->argv[0]);
format_free(ft);
@@ -157,10 +159,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
close(pipe_fd[1]);
wp->pipe_fd = pipe_fd[0];
if (wp->fd != -1)
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
else
wp->pipe_off = 0;
memcpy(wpo, &wp->offset, sizeof *wpo);
setblocking(wp->pipe_fd, 0);
wp->pipe_event = bufferevent_new(wp->pipe_fd,

View File

@@ -25,8 +25,69 @@
#include "tmux.h"
/* Global command queue. */
static struct cmdq_list global_queue = TAILQ_HEAD_INITIALIZER(global_queue);
/* Command queue flags. */
#define CMDQ_FIRED 0x1
#define CMDQ_WAITING 0x2
/* Command queue item type. */
enum cmdq_type {
CMDQ_COMMAND,
CMDQ_CALLBACK,
};
/* Command queue item. */
struct cmdq_item {
char *name;
struct cmdq_list *queue;
struct cmdq_item *next;
struct client *client;
struct client *target_client;
enum cmdq_type type;
u_int group;
u_int number;
time_t time;
int flags;
struct cmdq_state *state;
struct cmd_find_state source;
struct cmd_find_state target;
struct cmd_list *cmdlist;
struct cmd *cmd;
cmdq_cb cb;
void *data;
TAILQ_ENTRY(cmdq_item) entry;
};
TAILQ_HEAD(cmdq_item_list, cmdq_item);
/*
* Command queue state. This is the context for commands on the command queue.
* It holds information about how the commands were fired (the key and flags),
* any additional formats for the commands, and the current default target.
* Multiple commands can share the same state and a command may update the
* default target.
*/
struct cmdq_state {
int references;
int flags;
struct format_tree *formats;
struct key_event event;
struct cmd_find_state current;
};
/* Command queue. */
struct cmdq_list {
struct cmdq_item *item;
struct cmdq_item_list list;
};
/* Get command queue name. */
static const char *
@@ -47,13 +108,183 @@ cmdq_name(struct client *c)
static struct cmdq_list *
cmdq_get(struct client *c)
{
if (c == NULL)
return (&global_queue);
return (&c->queue);
static struct cmdq_list *global_queue;
if (c == NULL) {
if (global_queue == NULL)
global_queue = cmdq_new();
return (global_queue);
}
return (c->queue);
}
/* Create a queue. */
struct cmdq_list *
cmdq_new(void)
{
struct cmdq_list *queue;
queue = xcalloc (1, sizeof *queue);
TAILQ_INIT (&queue->list);
return (queue);
}
/* Free a queue. */
void
cmdq_free(struct cmdq_list *queue)
{
if (!TAILQ_EMPTY(&queue->list))
fatalx("queue not empty");
free(queue);
}
/* Get item name. */
const char *
cmdq_get_name(struct cmdq_item *item)
{
return (item->name);
}
/* Get item client. */
struct client *
cmdq_get_client(struct cmdq_item *item)
{
return (item->client);
}
/* Get item target client. */
struct client *
cmdq_get_target_client(struct cmdq_item *item)
{
return (item->target_client);
}
/* Get item state. */
struct cmdq_state *
cmdq_get_state(struct cmdq_item *item)
{
return (item->state);
}
/* Get item target. */
struct cmd_find_state *
cmdq_get_target(struct cmdq_item *item)
{
return (&item->target);
}
/* Get item source. */
struct cmd_find_state *
cmdq_get_source(struct cmdq_item *item)
{
return (&item->source);
}
/* Get state event. */
struct key_event *
cmdq_get_event(struct cmdq_item *item)
{
return (&item->state->event);
}
/* Get state current target. */
struct cmd_find_state *
cmdq_get_current(struct cmdq_item *item)
{
return (&item->state->current);
}
/* Get state flags. */
int
cmdq_get_flags(struct cmdq_item *item)
{
return (item->state->flags);
}
/* Create a new state. */
struct cmdq_state *
cmdq_new_state(struct cmd_find_state *current, struct key_event *event,
int flags)
{
struct cmdq_state *state;
state = xcalloc(1, sizeof *state);
state->references = 1;
state->flags = flags;
if (event != NULL)
memcpy(&state->event, event, sizeof state->event);
else
state->event.key = KEYC_NONE;
if (current != NULL && cmd_find_valid_state(current))
cmd_find_copy_state(&state->current, current);
else
cmd_find_clear_state(&state->current, 0);
return (state);
}
/* Add a reference to a state. */
struct cmdq_state *
cmdq_link_state(struct cmdq_state *state)
{
state->references++;
return (state);
}
/* Make a copy of a state. */
struct cmdq_state *
cmdq_copy_state(struct cmdq_state *state)
{
return (cmdq_new_state(&state->current, &state->event, state->flags));
}
/* Free a state. */
void
cmdq_free_state(struct cmdq_state *state)
{
if (--state->references != 0)
return;
if (state->formats != NULL)
format_free(state->formats);
free(state);
}
/* Add a format to command queue. */
void
cmdq_add_format(struct cmdq_state *state, const char *key, const char *fmt, ...)
{
va_list ap;
char *value;
va_start(ap, fmt);
xvasprintf(&value, fmt, ap);
va_end(ap);
if (state->formats == NULL)
state->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
format_add(state->formats, key, "%s", value);
free(value);
}
/* Merge formats from item. */
void
cmdq_merge_formats(struct cmdq_item *item, struct format_tree *ft)
{
const struct cmd_entry *entry;
if (item->cmd != NULL) {
entry = cmd_get_entry(item->cmd);
format_add(ft, "command", "%s", entry->name);
}
if (item->state->formats != NULL)
format_merge(ft, item->state->formats);
}
/* Append an item. */
void
struct cmdq_item *
cmdq_append(struct client *c, struct cmdq_item *item)
{
struct cmdq_list *queue = cmdq_get(c);
@@ -68,15 +299,16 @@ cmdq_append(struct client *c, struct cmdq_item *item)
item->client = c;
item->queue = queue;
TAILQ_INSERT_TAIL(queue, item, entry);
TAILQ_INSERT_TAIL(&queue->list, item, entry);
log_debug("%s %s: %s", __func__, cmdq_name(c), item->name);
item = next;
} while (item != NULL);
return (TAILQ_LAST(&queue->list, cmdq_item_list));
}
/* Insert an item. */
void
struct cmdq_item *
cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
{
struct client *c = after->client;
@@ -93,30 +325,38 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
item->client = c;
item->queue = queue;
TAILQ_INSERT_AFTER(queue, after, item, entry);
TAILQ_INSERT_AFTER(&queue->list, 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);
return (after);
}
/* Insert a hook. */
void
cmdq_insert_hook(struct session *s, struct cmdq_item *item,
struct cmd_find_state *fs, const char *fmt, ...)
struct cmd_find_state *current, const char *fmt, ...)
{
struct cmdq_state *state = item->state;
struct cmd *cmd = item->cmd;
struct args *args = cmd_get_args(cmd);
struct args_entry *entryp;
struct args_value *valuep;
struct options *oo;
va_list ap;
char *name;
char *name, tmp[32], flag, *arguments;
int i;
const char *value;
struct cmdq_item *new_item;
struct cmdq_state *new_state;
struct options_entry *o;
struct options_array_item *a;
struct cmd_list *cmdlist;
if (item->flags & CMDQ_NOHOOKS)
if (item->state->flags & CMDQ_STATE_NOHOOKS)
return;
if (s == NULL)
oo = global_s_options;
@@ -134,45 +374,79 @@ cmdq_insert_hook(struct session *s, struct cmdq_item *item,
}
log_debug("running hook %s (parent %p)", name, item);
/*
* The hooks get a new state because they should not update the current
* target or formats for any subsequent commands.
*/
new_state = cmdq_new_state(current, &state->event, CMDQ_STATE_NOHOOKS);
cmdq_add_format(new_state, "hook", "%s", name);
arguments = args_print(args);
cmdq_add_format(new_state, "hook_arguments", "%s", arguments);
free(arguments);
for (i = 0; i < args->argc; i++) {
xsnprintf(tmp, sizeof tmp, "hook_argument_%d", i);
cmdq_add_format(new_state, tmp, "%s", args->argv[i]);
}
flag = args_first(args, &entryp);
while (flag != 0) {
value = args_get(args, flag);
if (value == NULL) {
xsnprintf(tmp, sizeof tmp, "hook_flag_%c", flag);
cmdq_add_format(new_state, tmp, "1");
} else {
xsnprintf(tmp, sizeof tmp, "hook_flag_%c", flag);
cmdq_add_format(new_state, tmp, "%s", value);
}
i = 0;
value = args_first_value(args, flag, &valuep);
while (value != NULL) {
xsnprintf(tmp, sizeof tmp, "hook_flag_%c_%d", flag, i);
cmdq_add_format(new_state, tmp, "%s", value);
i++;
value = args_next_value(&valuep);
}
flag = args_next(&entryp);
}
a = options_array_first(o);
while (a != NULL) {
cmdlist = options_array_item_value(a)->cmdlist;
if (cmdlist == NULL) {
a = options_array_next(a);
continue;
if (cmdlist != NULL) {
new_item = cmdq_get_command(cmdlist, new_state);
if (item != NULL)
item = cmdq_insert_after(item, new_item);
else
item = cmdq_append(NULL, new_item);
}
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);
}
cmdq_free_state(new_state);
free(name);
}
/* Continue processing command queue. */
void
cmdq_continue(struct cmdq_item *item)
{
item->flags &= ~CMDQ_WAITING;
}
/* Remove an item. */
static void
cmdq_remove(struct cmdq_item *item)
{
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->cmdlist != NULL)
cmd_list_free(item->cmdlist);
cmdq_free_state(item->state);
TAILQ_REMOVE(item->queue, item, entry);
TAILQ_REMOVE(&item->queue->list, item, entry);
free(item->name);
free(item);
@@ -197,48 +471,46 @@ cmdq_remove_group(struct cmdq_item *item)
/* Get a command for the command queue. */
struct cmdq_item *
cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
struct mouse_event *m, int flags)
cmdq_get_command(struct cmd_list *cmdlist, struct cmdq_state *state)
{
struct cmdq_item *item, *first = NULL, *last = NULL;
struct cmd *cmd;
struct cmdq_shared *shared = NULL;
u_int group = 0;
const struct cmd_entry *entry;
int created = 0;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
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;
}
if (state == NULL) {
state = cmdq_new_state(NULL, NULL, 0);
created = 1;
}
cmd = cmd_list_first(cmdlist);
while (cmd != NULL) {
entry = cmd_get_entry(cmd);
item = xcalloc(1, sizeof *item);
xasprintf(&item->name, "[%s/%p]", cmd->entry->name, item);
xasprintf(&item->name, "[%s/%p]", entry->name, item);
item->type = CMDQ_COMMAND;
item->group = cmd->group;
item->flags = flags;
item->group = cmd_get_group(cmd);
item->state = cmdq_link_state(state);
item->shared = shared;
item->cmdlist = cmdlist;
item->cmd = cmd;
log_debug("%s: %s group %u", __func__, item->name, item->group);
shared->references++;
cmdlist->references++;
log_debug("%s: %s group %u", __func__, item->name, item->group);
if (first == NULL)
first = item;
if (last != NULL)
last->next = item;
last = item;
cmd = cmd_list_next(cmd);
}
if (created)
cmdq_free_state(state);
return (first);
}
@@ -250,11 +522,11 @@ cmdq_find_flag(struct cmdq_item *item, struct cmd_find_state *fs,
const char *value;
if (flag->flag == 0) {
cmd_find_clear_state(fs, 0);
cmd_find_from_client(fs, item->target_client, 0);
return (CMD_RETURN_NORMAL);
}
value = args_get(item->cmd->args, flag->flag);
value = args_get(cmd_get_args(item->cmd), flag->flag);
if (cmd_find_target(fs, item, value, flag->type, flag->flags) != 0) {
cmd_find_clear_state(fs, 0);
return (CMD_RETURN_ERROR);
@@ -262,31 +534,75 @@ cmdq_find_flag(struct cmdq_item *item, struct cmd_find_state *fs,
return (CMD_RETURN_NORMAL);
}
/* Add message with command. */
static void
cmdq_add_message(struct cmdq_item *item)
{
struct client *c = item->client;
struct cmdq_state *state = item->state;
const char *name, *key;
char *tmp;
tmp = cmd_print(item->cmd);
if (c != NULL) {
name = c->name;
if (c->session != NULL && state->event.key != KEYC_NONE) {
key = key_string_lookup_key(state->event.key, 0);
server_add_message("%s key %s: %s", name, key, tmp);
} else
server_add_message("%s command: %s", name, tmp);
} else
server_add_message("command: %s", tmp);
free(tmp);
}
/* 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;
const char *name = cmdq_name(item->client);
struct cmdq_state *state = item->state;
struct cmd *cmd = item->cmd;
const struct cmd_entry *entry = cmd->entry;
struct args *args = cmd_get_args(cmd);
const struct cmd_entry *entry = cmd_get_entry(cmd);
struct client *tc, *saved = item->client;
enum cmd_retval retval;
struct cmd_find_state *fsp, fs;
int flags;
int flags, quiet = 0;
char *tmp;
if (cfg_finished)
cmdq_add_message(item);
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);
flags = !!(state->flags & CMDQ_STATE_CONTROL);
cmdq_guard(item, "begin", flags);
if (item->client == NULL)
item->client = cmd_find_client(item, NULL, 1);
if (entry->flags & CMD_CLIENT_CANFAIL)
quiet = 1;
if (entry->flags & CMD_CLIENT_CFLAG) {
tc = cmd_find_client(item, args_get(args, 'c'), quiet);
if (tc == NULL && !quiet) {
retval = CMD_RETURN_ERROR;
goto out;
}
} else if (entry->flags & CMD_CLIENT_TFLAG) {
tc = cmd_find_client(item, args_get(args, 't'), quiet);
if (tc == NULL && !quiet) {
retval = CMD_RETURN_ERROR;
goto out;
}
} else
tc = cmd_find_client(item, NULL, 1);
item->target_client = tc;
retval = cmdq_find_flag(item, &item->source, &entry->source);
if (retval == CMD_RETURN_ERROR)
goto out;
@@ -301,8 +617,8 @@ cmdq_fire_command(struct cmdq_item *item)
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_valid_state(&item->state->current))
fsp = &item->state->current;
else if (cmd_find_from_client(&fs, item->client, 0) == 0)
fsp = &fs;
else
@@ -311,7 +627,7 @@ cmdq_fire_command(struct cmdq_item *item)
}
out:
item->client = c;
item->client = saved;
if (retval == CMD_RETURN_ERROR)
cmdq_guard(item, "error", flags);
else
@@ -330,7 +646,7 @@ cmdq_get_callback1(const char *name, cmdq_cb cb, void *data)
item->type = CMDQ_CALLBACK;
item->group = 0;
item->flags = 0;
item->state = cmdq_new_state(NULL, NULL, 0);
item->cb = cb;
item->data = data;
@@ -364,25 +680,6 @@ cmdq_fire_callback(struct cmdq_item *item)
return (item->cb(item, item->data));
}
/* Add a format to command queue. */
void
cmdq_format(struct cmdq_item *item, const char *key, const char *fmt, ...)
{
struct cmdq_shared *shared = item->shared;
va_list ap;
char *value;
va_start(ap, fmt);
xvasprintf(&value, fmt, ap);
va_end(ap);
if (shared->formats == NULL)
shared->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
format_add(shared->formats, key, "%s", value);
free(value);
}
/* Process next item on command queue. */
u_int
cmdq_next(struct client *c)
@@ -394,18 +691,18 @@ cmdq_next(struct client *c)
u_int items = 0;
static u_int number;
if (TAILQ_EMPTY(queue)) {
if (TAILQ_EMPTY(&queue->list)) {
log_debug("%s %s: empty", __func__, name);
return (0);
}
if (TAILQ_FIRST(queue)->flags & CMDQ_WAITING) {
if (TAILQ_FIRST(&queue->list)->flags & CMDQ_WAITING) {
log_debug("%s %s: waiting", __func__, name);
return (0);
}
log_debug("%s %s: enter", __func__, name);
for (;;) {
item = TAILQ_FIRST(queue);
item = queue->item = TAILQ_FIRST(&queue->list);
if (item == NULL)
break;
log_debug("%s %s: %s (%d), flags %x", __func__, name,
@@ -455,6 +752,7 @@ cmdq_next(struct client *c)
}
cmdq_remove(item);
}
queue->item = NULL;
log_debug("%s %s: exit (empty)", __func__, name);
return (items);
@@ -464,18 +762,29 @@ waiting:
return (items);
}
/* Get running item if any. */
struct cmdq_item *
cmdq_running(struct client *c)
{
struct cmdq_list *queue = cmdq_get(c);
if (queue->item == NULL)
return (NULL);
if (queue->item->flags & CMDQ_WAITING)
return (NULL);
return (queue->item);
}
/* Print a guard line. */
void
cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
{
struct client *c = item->client;
long t = item->time;
u_int number = item->number;
if (c == NULL || !(c->flags & CLIENT_CONTROL))
return;
evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
(long)item->time, item->number, flags);
server_client_push_stdout(c);
if (c != NULL && (c->flags & CLIENT_CONTROL))
control_write(c, "%%%s %ld %u %d", guard, t, number, flags);
}
/* Show message from command. */
@@ -489,29 +798,34 @@ cmdq_print(struct cmdq_item *item, const char *fmt, ...)
char *tmp, *msg;
va_start(ap, fmt);
xvasprintf(&msg, fmt, ap);
va_end(ap);
log_debug("%s: %s", __func__, msg);
if (c == NULL)
/* nothing */;
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
if (~c->flags & CLIENT_UTF8) {
xvasprintf(&tmp, fmt, ap);
tmp = msg;
msg = utf8_sanitize(tmp);
free(tmp);
evbuffer_add(c->stdout_data, msg, strlen(msg));
free(msg);
} else
evbuffer_add_vprintf(c->stdout_data, fmt, ap);
evbuffer_add(c->stdout_data, "\n", 1);
server_client_push_stdout(c);
}
if (c->flags & CLIENT_CONTROL)
control_write(c, "%s", msg);
else
file_print(c, "%s\n", msg);
} else {
wp = c->session->curw->window->active;
wp = server_client_get_pane(c);
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);
if (wme == NULL || wme->mode != &window_view_mode) {
window_pane_set_mode(wp, NULL, &window_view_mode, NULL,
NULL);
}
window_copy_add(wp, "%s", msg);
}
va_end(ap);
free(msg);
}
/* Show error from command. */
@@ -521,32 +835,34 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
struct client *c = item->client;
struct cmd *cmd = item->cmd;
va_list ap;
char *msg;
size_t msglen;
char *tmp;
char *msg, *tmp;
const char *file;
u_int line;
va_start(ap, fmt);
msglen = xvasprintf(&msg, fmt, ap);
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)) {
if (c == NULL) {
cmd_get_source(cmd, &file, &line);
cfg_add_cause("%s:%u: %s", file, line, msg);
} else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
server_add_message("%s message: %s", c->name, msg);
if (~c->flags & CLIENT_UTF8) {
tmp = msg;
msg = utf8_sanitize(tmp);
free(tmp);
msglen = strlen(msg);
}
evbuffer_add(c->stderr_data, msg, msglen);
evbuffer_add(c->stderr_data, "\n", 1);
server_client_push_stderr(c);
if (c->flags & CLIENT_CONTROL)
control_write(c, "%s", msg);
else
file_error(c, "%s\n", msg);
c->retval = 1;
} else {
*msg = toupper((u_char) *msg);
status_message_set(c, "%s", msg);
status_message_set(c, -1, 1, 0, "%s", msg);
}
free(msg);

View File

@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -33,26 +34,92 @@ const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client",
.alias = "refresh",
.args = { "cC:DlLRSt:U", 0, 1 },
.usage = "[-cDlLRSU] [-C size] " CMD_TARGET_CLIENT_USAGE " [adjustment]",
.args = { "A:B:cC:Df:F:lLRSt:U", 0, 1 },
.usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] "
"[-C XxY] [-f flags] " CMD_TARGET_CLIENT_USAGE " [adjustment]",
.flags = CMD_AFTERHOOK,
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
.exec = cmd_refresh_client_exec
};
static void
cmd_refresh_client_update_subscription(struct client *tc, const char *value)
{
char *copy, *split, *name, *what;
enum control_sub_type subtype;
int subid = -1;
copy = name = xstrdup(value);
if ((split = strchr(copy, ':')) == NULL) {
control_remove_sub(tc, copy);
goto out;
}
*split++ = '\0';
what = split;
if ((split = strchr(what, ':')) == NULL)
goto out;
*split++ = '\0';
if (strcmp(what, "%*") == 0)
subtype = CONTROL_SUB_ALL_PANES;
else if (sscanf(what, "%%%d", &subid) == 1 && subid >= 0)
subtype = CONTROL_SUB_PANE;
else if (strcmp(what, "@*") == 0)
subtype = CONTROL_SUB_ALL_WINDOWS;
else if (sscanf(what, "@%d", &subid) == 1 && subid >= 0)
subtype = CONTROL_SUB_WINDOW;
else
subtype = CONTROL_SUB_SESSION;
control_add_sub(tc, name, subtype, subid, split);
out:
free(copy);
}
static void
cmd_refresh_client_update_offset(struct client *tc, const char *value)
{
struct window_pane *wp;
char *copy, *split;
u_int pane;
if (*value != '%')
return;
copy = xstrdup(value);
if ((split = strchr(copy, ':')) == NULL)
goto out;
*split++ = '\0';
if (sscanf(copy, "%%%u", &pane) != 1)
goto out;
wp = window_pane_find_by_id(pane);
if (wp == NULL)
goto out;
if (strcmp(split, "on") == 0)
control_set_pane_on(tc, wp);
else if (strcmp(split, "off") == 0)
control_set_pane_off(tc, wp);
else if (strcmp(split, "continue") == 0)
control_continue_pane(tc, wp);
else if (strcmp(split, "pause") == 0)
control_pause_pane(tc, wp);
out:
free(copy);
}
static enum cmd_retval
cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c;
struct tty *tty;
struct window *w;
const char *size, *errstr;
u_int x, y, adjust;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
tty = &c->tty;
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct tty *tty = &tc->tty;
struct window *w;
const char *size, *errstr, *value;
u_int x, y, adjust;
struct args_value *av;
if (args_has(args, 'c') ||
args_has(args, 'L') ||
@@ -71,49 +138,75 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
}
if (args_has(args, 'c'))
c->pan_window = NULL;
tc->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;
w = tc->session->curw->window;
if (tc->pan_window != w) {
tc->pan_window = w;
tc->pan_ox = tty->oox;
tc->pan_oy = tty->ooy;
}
if (args_has(args, 'L')) {
if (c->pan_ox > adjust)
c->pan_ox -= adjust;
if (tc->pan_ox > adjust)
tc->pan_ox -= adjust;
else
c->pan_ox = 0;
tc->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;
tc->pan_ox += adjust;
if (tc->pan_ox > w->sx - tty->osx)
tc->pan_ox = w->sx - tty->osx;
} else if (args_has(args, 'U')) {
if (c->pan_oy > adjust)
c->pan_oy -= adjust;
if (tc->pan_oy > adjust)
tc->pan_oy -= adjust;
else
c->pan_oy = 0;
tc->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;
tc->pan_oy += adjust;
if (tc->pan_oy > w->sy - tty->osy)
tc->pan_oy = w->sy - tty->osy;
}
}
tty_update_client_offset(c);
server_redraw_client(c);
tty_update_client_offset(tc);
server_redraw_client(tc);
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);
tty_putcode_ptr2(&tc->tty, TTYC_MS, "", "?");
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'F')) /* -F is an alias for -f */
server_client_set_flags(tc, args_get(args, 'F'));
if (args_has(args, 'f'))
server_client_set_flags(tc, args_get(args, 'f'));
if (args_has(args, 'A')) {
if (~tc->flags & CLIENT_CONTROL)
goto not_control_client;
value = args_first_value(args, 'A', &av);
while (value != NULL) {
cmd_refresh_client_update_offset(tc, value);
value = args_next_value(&av);
}
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'B')) {
if (~tc->flags & CLIENT_CONTROL)
goto not_control_client;
value = args_first_value(args, 'B', &av);
while (value != NULL) {
cmd_refresh_client_update_subscription(tc, value);
value = args_next_value(&av);
}
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'C')) {
if (~tc->flags & CLIENT_CONTROL)
goto not_control_client;
size = args_get(args, 'C');
if (sscanf(size, "%u,%u", &x, &y) != 2 &&
sscanf(size, "%ux%u", &x, &y)) {
sscanf(size, "%ux%u", &x, &y) != 2) {
cmdq_error(item, "bad size argument");
return (CMD_RETURN_ERROR);
}
@@ -122,22 +215,22 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "size too small or too big");
return (CMD_RETURN_ERROR);
}
if (!(c->flags & CLIENT_CONTROL)) {
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}
tty_set_size(&c->tty, x, y);
c->flags |= CLIENT_SIZECHANGED;
recalculate_sizes();
tty_set_size(&tc->tty, x, y, 0, 0);
tc->flags |= CLIENT_SIZECHANGED;
recalculate_sizes_now(1);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'S')) {
c->flags |= CLIENT_STATUSFORCE;
server_status_client(c);
tc->flags |= CLIENT_STATUSFORCE;
server_status_client(tc);
} else {
c->flags |= CLIENT_STATUSFORCE;
server_redraw_client(c);
tc->flags |= CLIENT_STATUSFORCE;
server_redraw_client(tc);
}
return (CMD_RETURN_NORMAL);
not_control_client:
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}

View File

@@ -46,22 +46,18 @@ 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 client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
char *newname;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct session *s = target->s;
char *newname, *tmp;
newname = format_single(item, args->argv[0], c, s, NULL, NULL);
tmp = format_single_from_target(item, args->argv[0]);
newname = session_check_name(tmp);
free(tmp);
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);

View File

@@ -45,16 +45,16 @@ const struct cmd_entry cmd_rename_window_entry = {
static enum cmd_retval
cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
char *newname;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl;
char *newname;
newname = format_single(item, args->argv[0], c, s, wl, NULL);
newname = format_single_from_target(item, args->argv[0]);
window_set_name(wl->window, newname);
options_set_number(wl->window->options, "automatic-rename", 0);
server_redraw_window_borders(wl->window);
server_status_window(wl->window);
free(newname);

View File

@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -35,8 +36,8 @@ const struct cmd_entry cmd_resize_pane_entry = {
.name = "resize-pane",
.alias = "resizep",
.args = { "DLMRt:Ux:y:Z", 0, 1 },
.usage = "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
.args = { "DLMRTt:Ux:y:Z", 0, 1 },
.usage = "[-DLMRTUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
"[adjustment]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -48,25 +49,39 @@ const struct cmd_entry cmd_resize_pane_entry = {
static enum cmd_retval
cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmdq_shared *shared = item->shared;
struct window_pane *wp = item->target.wp;
struct winlink *wl = item->target.wl;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct key_event *event = cmdq_get_event(item);
struct window_pane *wp = target->wp;
struct winlink *wl = target->wl;
struct window *w = wl->window;
struct client *c = item->client;
struct session *s = item->target.s;
struct client *c = cmdq_get_client(item);
struct session *s = target->s;
const char *errstr;
char *cause;
u_int adjust;
int x, y;
struct grid *gd = wp->base.grid;
if (args_has(args, 'T')) {
if (!TAILQ_EMPTY(&wp->modes))
return (CMD_RETURN_NORMAL);
adjust = screen_size_y(&wp->base) - 1 - wp->base.cy;
if (adjust > gd->hsize)
adjust = gd->hsize;
grid_remove_history(gd, adjust);
wp->base.cy += adjust;
wp->flags |= PANE_REDRAW;
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'M')) {
if (cmd_mouse_window(&shared->mouse, &s) == NULL)
if (!event->m.valid || cmd_mouse_window(&event->m, &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, &shared->mouse);
cmd_resize_pane_mouse_update(c, &event->m);
return (CMD_RETURN_NORMAL);
}
@@ -76,7 +91,6 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
else
window_zoom(wp);
server_redraw_window(w);
server_status_window(w);
return (CMD_RETURN_NORMAL);
}
server_unzoom_window(w);
@@ -92,7 +106,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
}
if (args_has(args, 'x')) {
x = args_strtonum(args, 'x', PANE_MINIMUM, INT_MAX, &cause);
x = args_percentage(args, 'x', 0, INT_MAX, w->sx, &cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
@@ -101,7 +115,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
}
if (args_has(args, 'y')) {
y = args_strtonum(args, 'y', PANE_MINIMUM, INT_MAX, &cause);
y = args_percentage(args, 'y', 0, INT_MAX, w->sy, &cause);
if (cause != NULL) {
cmdq_error(item, "height %s", cause);
free(cause);
@@ -144,13 +158,13 @@ cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m)
w = wl->window;
y = m->y + m->oy; x = m->x + m->ox;
if (m->statusat == 0 && y > 0)
y--;
if (m->statusat == 0 && y >= m->statuslines)
y -= m->statuslines;
else if (m->statusat > 0 && y >= (u_int)m->statusat)
y = m->statusat - 1;
ly = m->ly + m->oy; lx = m->lx + m->ox;
if (m->statusat == 0 && ly > 0)
ly--;
if (m->statusat == 0 && ly >= m->statuslines)
ly -= m->statuslines;
else if (m->statusat > 0 && ly >= (u_int)m->statusat)
ly = m->statusat - 1;

View File

@@ -46,13 +46,15 @@ const struct cmd_entry cmd_resize_window_entry = {
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 args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl;
struct window *w = wl->window;
struct session *s = item->target.s;
struct session *s = target->s;
const char *errstr;
char *cause;
u_int adjust, sx, sy;
int xpixel = -1, ypixel = -1;
if (args->argc == 0)
adjust = 1;
@@ -97,13 +99,16 @@ cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item)
} 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);
if (args_has(args, 'A')) {
default_window_size(NULL, s, w, &sx, &sy, &xpixel, &ypixel,
WINDOW_SIZE_LARGEST);
} else if (args_has(args, 'a')) {
default_window_size(NULL, s, w, &sx, &sy, &xpixel, &ypixel,
WINDOW_SIZE_SMALLEST);
}
options_set_number(w->options, "window-size", WINDOW_SIZE_MANUAL);
resize_window(w, sx, sy);
resize_window(w, sx, sy, xpixel, ypixel);
return (CMD_RETURN_NORMAL);
}

View File

@@ -47,11 +47,12 @@ const struct cmd_entry cmd_respawn_pane_entry = {
static enum cmd_retval
cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct spawn_context sc;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
struct session *s = target->s;
struct winlink *wl = target->wl;
struct window_pane *wp = target->wp;
char *cause = NULL;
const char *add;
struct args_value *value;
@@ -71,7 +72,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
environ_put(sc.environ, add, 0);
add = args_next_value(&value);
}
@@ -89,6 +90,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
}
wp->flags |= PANE_REDRAW;
server_redraw_window_borders(wp->window);
server_status_window(wp->window);
environ_free(sc.environ);

View File

@@ -47,10 +47,12 @@ const struct cmd_entry cmd_respawn_window_entry = {
static enum cmd_retval
cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct spawn_context sc;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct client *tc = cmdq_get_target_client(item);
struct session *s = target->s;
struct winlink *wl = target->wl;
char *cause = NULL;
const char *add;
struct args_value *value;
@@ -59,6 +61,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
sc.item = item;
sc.s = s;
sc.wl = wl;
sc.tc = tc;
sc.name = NULL;
sc.argc = args->argc;
@@ -67,7 +70,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
environ_put(sc.environ, add, 0);
add = args_next_value(&value);
}

View File

@@ -31,8 +31,8 @@ const struct cmd_entry cmd_rotate_window_entry = {
.name = "rotate-window",
.alias = "rotatew",
.args = { "Dt:U", 0, 0 },
.usage = "[-DU] " CMD_TARGET_WINDOW_USAGE,
.args = { "Dt:UZ", 0, 0 },
.usage = "[-DUZ] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
@@ -43,16 +43,18 @@ const struct cmd_entry cmd_rotate_window_entry = {
static enum cmd_retval
cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->target.wl;
struct args *args = cmd_get_args(self);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl;
struct window *w = wl->window;
struct window_pane *wp, *wp2;
struct layout_cell *lc;
u_int sx, sy, xoff, yoff;
server_unzoom_window(w);
window_push_zoom(w, 0, args_has(args, 'Z'));
if (args_has(self->args, 'D')) {
if (args_has(args, 'D')) {
wp = TAILQ_LAST(&w->panes, window_panes);
TAILQ_REMOVE(&w->panes, wp, entry);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
@@ -77,9 +79,6 @@ 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, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
} else {
wp = TAILQ_FIRST(&w->panes);
TAILQ_REMOVE(&w->panes, wp, entry);
@@ -105,10 +104,12 @@ 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, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
}
window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
window_pop_zoom(w);
server_redraw_window(w);
return (CMD_RETURN_NORMAL);
}

View File

@@ -20,6 +20,7 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
@@ -31,6 +32,7 @@
static enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmdq_item *);
static void cmd_run_shell_timer(int, short, void *);
static void cmd_run_shell_callback(struct job *);
static void cmd_run_shell_free(void *);
static void cmd_run_shell_print(struct job *, const char *);
@@ -39,8 +41,8 @@ const struct cmd_entry cmd_run_shell_entry = {
.name = "run-shell",
.alias = "run",
.args = { "bt:", 1, 1 },
.usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
.args = { "bd:Ct:", 0, 1 },
.usage = "[-bC] [-d delay] " CMD_TARGET_PANE_USAGE " [shell-command]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@@ -49,9 +51,16 @@ const struct cmd_entry cmd_run_shell_entry = {
};
struct cmd_run_shell_data {
struct client *client;
char *cmd;
int shell;
char *cwd;
struct cmdq_item *item;
struct session *s;
int wp_id;
struct event timer;
int flags;
struct cmd_parse_input pi;
};
static void
@@ -78,48 +87,130 @@ cmd_run_shell_print(struct job *job, const char *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_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL);
window_copy_add(wp, "%s", msg);
}
static enum cmd_retval
cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct cmd_run_shell_data *cdata;
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 client *tc = cmdq_get_target_client(item);
struct session *s = target->s;
struct window_pane *wp = target->wp;
const char *delay;
double d;
struct timeval tv;
char *end;
int wait = !args_has(args, 'b');
if ((delay = args_get(args, 'd')) != NULL) {
d = strtod(delay, &end);
if (*end != '\0') {
cmdq_error(item, "invalid delay time: %s", delay);
return (CMD_RETURN_ERROR);
}
} else if (args->argc == 0)
return (CMD_RETURN_NORMAL);
cdata = xcalloc(1, sizeof *cdata);
cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp);
if (args->argc != 0)
cdata->cmd = format_single_from_target(item, args->argv[0]);
cdata->shell = !args_has(args, 'C');
if (!cdata->shell) {
memset(&cdata->pi, 0, sizeof cdata->pi);
cmd_get_source(self, &cdata->pi.file, &cdata->pi.line);
if (wait)
cdata->pi.item = item;
cdata->pi.c = tc;
cmd_find_copy_state(&cdata->pi.fs, target);
}
if (args_has(args, 't') && wp != NULL)
cdata->wp_id = wp->id;
else
cdata->wp_id = -1;
if (!args_has(args, 'b'))
if (wait) {
cdata->client = cmdq_get_client(item);
cdata->item = item;
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);
} else {
cdata->client = tc;
cdata->flags |= JOB_NOWAIT;
}
if (cdata->client != NULL)
cdata->client->references++;
if (args_has(args, 'b'))
cdata->cwd = xstrdup(server_client_get_cwd(cmdq_get_client(item), s));
cdata->s = s;
if (s != NULL)
session_add_ref(s, __func__);
evtimer_set(&cdata->timer, cmd_run_shell_timer, cdata);
if (delay != NULL) {
timerclear(&tv);
tv.tv_sec = (time_t)d;
tv.tv_usec = (d - (double)tv.tv_sec) * 1000000U;
evtimer_add(&cdata->timer, &tv);
} else
event_active(&cdata->timer, EV_TIMEOUT, 1);
if (!wait)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
static void
cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
{
struct cmd_run_shell_data *cdata = arg;
struct client *c = cdata->client;
const char *cmd = cdata->cmd;
char *error;
struct cmdq_item *item = cdata->item;
enum cmd_parse_status status;
if (cmd != NULL && cdata->shell) {
if (job_run(cmd, 0, NULL, cdata->s, cdata->cwd, NULL,
cmd_run_shell_callback, cmd_run_shell_free, cdata,
cdata->flags, -1, -1) == NULL)
cmd_run_shell_free(cdata);
return;
}
if (cmd != NULL) {
if (item != NULL) {
status = cmd_parse_and_insert(cmd, &cdata->pi, item,
cmdq_get_state(item), &error);
} else {
status = cmd_parse_and_append(cmd, &cdata->pi, c, NULL,
&error);
}
if (status == CMD_PARSE_ERROR) {
if (cdata->item == NULL) {
*error = toupper((u_char)*error);
status_message_set(c, -1, 1, 0, "%s", error);
} else
cmdq_error(cdata->item, "%s", error);
free(error);
}
}
if (cdata->item != NULL)
cmdq_continue(cdata->item);
cmd_run_shell_free(cdata);
}
static void
cmd_run_shell_callback(struct job *job)
{
struct cmd_run_shell_data *cdata = job_get_data(job);
struct bufferevent *event = job_get_event(job);
struct cmdq_item *item = cdata->item;
char *cmd = cdata->cmd, *msg = NULL, *line;
size_t size;
int retcode, status;
@@ -149,13 +240,19 @@ cmd_run_shell_callback(struct job *job)
} else if (WIFSIGNALED(status)) {
retcode = WTERMSIG(status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
}
retcode += 128;
} else
retcode = 0;
if (msg != NULL)
cmd_run_shell_print(job, msg);
free(msg);
if (cdata->item != NULL)
cdata->item->flags &= ~CMDQ_WAITING;
if (item != NULL) {
if (cmdq_get_client(item) != NULL &&
cmdq_get_client(item)->session == NULL)
cmdq_get_client(item)->retval = retcode;
cmdq_continue(item);
}
}
static void
@@ -163,6 +260,12 @@ cmd_run_shell_free(void *data)
{
struct cmd_run_shell_data *cdata = data;
evtimer_del(&cdata->timer);
if (cdata->s != NULL)
session_remove_ref(cdata->s, __func__);
if (cdata->client != NULL)
server_client_unref(cdata->client);
free(cdata->cwd);
free(cdata->cmd);
free(cdata);
}

View File

@@ -55,27 +55,37 @@ const struct cmd_entry cmd_show_buffer_entry = {
.exec = cmd_save_buffer_exec
};
static void
cmd_save_buffer_done(__unused struct client *c, const char *path, int error,
__unused int closed, __unused struct evbuffer *buffer, void *data)
{
struct cmdq_item *item = data;
if (!closed)
return;
if (error != 0)
cmdq_error(item, "%s: %s", path, strerror(error));
cmdq_continue(item);
}
static enum cmd_retval
cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
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 args *args = cmd_get_args(self);
struct client *c = cmdq_get_client(item);
struct paste_buffer *pb;
const char *bufname, *bufdata, *start, *end, *flags;
char *msg, *path, *file;
size_t size, used, msglen, bufsize;
FILE *f;
int flags;
const char *bufname = args_get(args, 'b'), *bufdata;
size_t bufsize;
char *path, *tmp;
if (!args_has(args, 'b')) {
if (bufname == NULL) {
if ((pb = paste_get_top(NULL)) == NULL) {
cmdq_error(item, "no buffers");
return (CMD_RETURN_ERROR);
}
} else {
bufname = args_get(args, 'b');
pb = paste_get_name(bufname);
if (pb == NULL) {
cmdq_error(item, "no buffer %s", bufname);
@@ -84,78 +94,24 @@ 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 = xstrdup("-");
else
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);
if (cmd_get_entry(self) == &cmd_show_buffer_entry) {
if (c->session != NULL || (c->flags & CLIENT_CONTROL)) {
utf8_stravisx(&tmp, bufdata, bufsize,
VIS_OCTAL|VIS_CSTYLE|VIS_TAB);
cmdq_print(item, "%s", tmp);
free(tmp);
return (CMD_RETURN_NORMAL);
}
if (c->session == NULL || (c->flags & CLIENT_CONTROL))
goto do_stdout;
goto do_print;
}
flags = "wb";
if (args_has(self->args, 'a'))
flags = "ab";
file = server_client_get_path(item->client, path);
path = xstrdup("-");
} else
path = format_single_from_target(item, args->argv[0]);
if (args_has(args, 'a'))
flags = O_APPEND;
else
flags = O_TRUNC;
file_write(cmdq_get_client(item), path, flags, bufdata, bufsize,
cmd_save_buffer_done, item);
free(path);
f = fopen(file, flags);
if (f == NULL) {
cmdq_error(item, "%s: %s", file, strerror(errno));
free(file);
return (CMD_RETURN_ERROR);
}
if (fwrite(bufdata, 1, bufsize, f) != bufsize) {
cmdq_error(item, "%s: write error", file);
fclose(f);
free(file);
return (CMD_RETURN_ERROR);
}
fclose(f);
free(file);
return (CMD_RETURN_NORMAL);
do_stdout:
evbuffer_add(c->stdout_data, bufdata, bufsize);
server_client_push_stdout(c);
return (CMD_RETURN_NORMAL);
do_print:
if (bufsize > (INT_MAX / 4) - 1) {
cmdq_error(item, "buffer too big");
return (CMD_RETURN_ERROR);
}
msg = NULL;
used = 0;
while (used != bufsize) {
start = bufdata + used;
end = memchr(start, '\n', bufsize - used);
if (end != NULL)
size = end - start;
else
size = bufsize - used;
msglen = size * 4 + 1;
msg = xrealloc(msg, msglen);
strvisx(msg, start, size, VIS_OCTAL|VIS_TAB);
cmdq_print(item, "%s", msg);
used += size + (end != NULL);
}
free(msg);
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}

View File

@@ -71,20 +71,21 @@ 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->target.wl;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl;
struct window *w = wl->window;
struct window_pane *wp = item->target.wp;
struct window_pane *wp = target->wp;
const char *layoutname;
char *oldlayout;
int next, previous, layout;
server_unzoom_window(w);
next = self->entry == &cmd_next_layout_entry;
next = (cmd_get_entry(self) == &cmd_next_layout_entry);
if (args_has(args, 'n'))
next = 1;
previous = self->entry == &cmd_previous_layout_entry;
previous = (cmd_get_entry(self) == &cmd_previous_layout_entry);
if (args_has(args, 'p'))
previous = 1;

View File

@@ -33,8 +33,8 @@ const struct cmd_entry cmd_select_pane_entry = {
.name = "select-pane",
.alias = "selectp",
.args = { "DdegLlMmP:RT:t:U", 0, 0 },
.usage = "[-DdegLlMmRU] [-P style] [-T title] " CMD_TARGET_PANE_USAGE,
.args = { "DdegLlMmP:RT:t:UZ", 0, 0 }, /* -P and -g deprecated */
.usage = "[-DdeLlMmRUZ] [-T title] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
@@ -46,8 +46,8 @@ const struct cmd_entry cmd_last_pane_entry = {
.name = "last-pane",
.alias = "lastp",
.args = { "det:", 0, 0 },
.usage = "[-de] " CMD_TARGET_WINDOW_USAGE,
.args = { "det:Z", 0, 0 },
.usage = "[-deZ] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
@@ -83,18 +83,21 @@ cmd_select_pane_redraw(struct window *w)
static enum cmd_retval
cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
struct client *c = cmd_find_client(item, NULL, 1);
struct winlink *wl = item->target.wl;
struct args *args = cmd_get_args(self);
const struct cmd_entry *entry = cmd_get_entry(self);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct client *c = cmdq_get_client(item);
struct winlink *wl = target->wl;
struct window *w = wl->window;
struct session *s = item->target.s;
struct window_pane *wp = item->target.wp, *lastwp, *markedwp;
struct style *sy = &wp->style;
char *pane_title;
struct session *s = target->s;
struct window_pane *wp = target->wp, *activewp, *lastwp, *markedwp;
struct options *oo = wp->options;
char *title;
const char *style;
struct options_entry *o;
if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
if (entry == &cmd_last_pane_entry || args_has(args, 'l')) {
lastwp = w->last;
if (lastwp == NULL && window_count_panes(w) == 2) {
lastwp = TAILQ_PREV(w->active, window_panes, entry);
@@ -105,17 +108,24 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no last pane");
return (CMD_RETURN_ERROR);
}
if (args_has(self->args, 'e'))
if (args_has(args, 'e')) {
lastwp->flags &= ~PANE_INPUTOFF;
else if (args_has(self->args, 'd'))
server_redraw_window_borders(lastwp->window);
server_status_window(lastwp->window);
} else if (args_has(args, 'd')) {
lastwp->flags |= PANE_INPUTOFF;
else {
server_unzoom_window(w);
server_redraw_window_borders(lastwp->window);
server_status_window(lastwp->window);
} else {
if (window_push_zoom(w, 0, args_has(args, 'Z')))
server_redraw_window(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);
}
if (window_pop_zoom(w))
server_redraw_window(w);
}
return (CMD_RETURN_NORMAL);
}
@@ -123,7 +133,10 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'm') || args_has(args, 'M')) {
if (args_has(args, 'm') && !window_pane_visible(wp))
return (CMD_RETURN_NORMAL);
lastwp = marked_pane.wp;
if (server_check_marked())
lastwp = marked_pane.wp;
else
lastwp = NULL;
if (args_has(args, 'M') || server_is_marked(s, wl, wp))
server_clear_marked();
@@ -142,63 +155,82 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
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;
style = args_get(args, 'P');
if (style != NULL) {
o = options_set_string(oo, "window-style", 0, "%s", style);
if (o == NULL) {
cmdq_error(item, "bad style: %s", style);
return (CMD_RETURN_ERROR);
}
if (args_has(self->args, 'g'))
cmdq_print(item, "%s", style_tostring(sy));
options_set_string(oo, "window-active-style", 0, "%s", style);
wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
}
if (args_has(args, 'g')) {
cmdq_print(item, "%s", options_get_string(oo, "window-style"));
return (CMD_RETURN_NORMAL);
}
if (args_has(self->args, 'L')) {
server_unzoom_window(wp->window);
if (args_has(args, 'L')) {
window_push_zoom(w, 0, 1);
wp = window_pane_find_left(wp);
} else if (args_has(self->args, 'R')) {
server_unzoom_window(wp->window);
window_pop_zoom(w);
} else if (args_has(args, 'R')) {
window_push_zoom(w, 0, 1);
wp = window_pane_find_right(wp);
} else if (args_has(self->args, 'U')) {
server_unzoom_window(wp->window);
window_pop_zoom(w);
} else if (args_has(args, 'U')) {
window_push_zoom(w, 0, 1);
wp = window_pane_find_up(wp);
} else if (args_has(self->args, 'D')) {
server_unzoom_window(wp->window);
window_pop_zoom(w);
} else if (args_has(args, 'D')) {
window_push_zoom(w, 0, 1);
wp = window_pane_find_down(wp);
window_pop_zoom(w);
}
if (wp == NULL)
return (CMD_RETURN_NORMAL);
if (args_has(self->args, 'e')) {
if (args_has(args, 'e')) {
wp->flags &= ~PANE_INPUTOFF;
return (CMD_RETURN_NORMAL);
}
if (args_has(self->args, 'd')) {
wp->flags |= PANE_INPUTOFF;
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_redraw_window_borders(wp->window);
server_status_window(wp->window);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'd')) {
wp->flags |= PANE_INPUTOFF;
server_redraw_window_borders(wp->window);
server_status_window(wp->window);
free(pane_title);
return (CMD_RETURN_NORMAL);
}
if (wp == w->active)
if (args_has(args, 'T')) {
title = format_single_from_target(item, args_get(args, 'T'));
if (screen_set_title(&wp->base, title)) {
notify_pane("pane-title-changed", wp);
server_redraw_window_borders(wp->window);
server_status_window(wp->window);
}
free(title);
return (CMD_RETURN_NORMAL);
server_unzoom_window(wp->window);
window_redraw_active_switch(w, wp);
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);
}
if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE))
activewp = server_client_get_pane(c);
else
activewp = w->active;
if (wp == activewp)
return (CMD_RETURN_NORMAL);
if (window_push_zoom(w, 0, args_has(args, 'Z')))
server_redraw_window(w);
window_redraw_active_switch(w, wp);
if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE))
server_client_set_pane(c, wp);
else 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);
if (window_pop_zoom(w))
server_redraw_window(w);
return (CMD_RETURN_NORMAL);
}

View File

@@ -84,23 +84,26 @@ const struct cmd_entry cmd_last_window_entry = {
static enum cmd_retval
cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->target.wl;
struct session *s = item->target.s;
struct args *args = cmd_get_args(self);
struct client *c = cmdq_get_client(item);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl;
struct session *s = target->s;
int next, previous, last, activity;
next = self->entry == &cmd_next_window_entry;
if (args_has(self->args, 'n'))
next = (cmd_get_entry(self) == &cmd_next_window_entry);
if (args_has(args, 'n'))
next = 1;
previous = self->entry == &cmd_previous_window_entry;
if (args_has(self->args, 'p'))
previous = (cmd_get_entry(self) == &cmd_previous_window_entry);
if (args_has(args, 'p'))
previous = 1;
last = self->entry == &cmd_last_window_entry;
if (args_has(self->args, 'l'))
last = (cmd_get_entry(self) == &cmd_last_window_entry);
if (args_has(args, 'l'))
last = 1;
if (next || previous || last) {
activity = args_has(self->args, 'a');
activity = args_has(args, 'a');
if (next) {
if (session_next(s, activity) != 0) {
cmdq_error(item, "no next window");
@@ -125,7 +128,7 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
* If -T and select-window is invoked on same window as
* current, switch to previous window.
*/
if (args_has(self->args, 'T') && wl == s->curw) {
if (args_has(args, 'T') && wl == s->curw) {
if (session_last(s) != 0) {
cmdq_error(item, "no last window");
return (-1);
@@ -139,6 +142,8 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
}
cmdq_insert_hook(s, item, current, "after-select-window");
}
if (c != NULL && c->session != NULL)
s->curw->window->latest = c;
recalculate_sizes();
return (CMD_RETURN_NORMAL);

View File

@@ -33,8 +33,9 @@ const struct cmd_entry cmd_send_keys_entry = {
.name = "send-keys",
.alias = "send",
.args = { "lXRMN:t:", 0, -1 },
.usage = "[-lXRM] [-N repeat-count] " CMD_TARGET_PANE_USAGE " key ...",
.args = { "FHlMN:Rt:X", 0, -1 },
.usage = "[-FHlMRX] [-N repeat-count] " CMD_TARGET_PANE_USAGE
" key ...",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -56,45 +57,95 @@ const struct cmd_entry cmd_send_prefix_entry = {
};
static struct cmdq_item *
cmd_send_keys_inject(struct client *c, struct cmd_find_state *fs,
struct cmdq_item *item, key_code key)
cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after,
key_code key)
{
struct cmd_find_state *target = cmdq_get_target(item);
struct client *tc = cmdq_get_target_client(item);
struct session *s = target->s;
struct winlink *wl = target->wl;
struct window_pane *wp = target->wp;
struct window_mode_entry *wme;
struct key_table *table;
struct key_binding *bd;
wme = TAILQ_FIRST(&fs->wp->modes);
wme = TAILQ_FIRST(&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);
if (window_pane_key(wp, tc, s, wl, key, NULL) != 0)
return (NULL);
return (item);
}
table = key_bindings_get_table(wme->mode->key_table(wme), 1);
bd = key_bindings_get(table, key & ~KEYC_XTERM);
bd = key_bindings_get(table, key & ~KEYC_MASK_FLAGS);
if (bd != NULL) {
table->references++;
item = key_bindings_dispatch(bd, item, c, NULL, &item->target);
after = key_bindings_dispatch(bd, after, tc, NULL, target);
key_bindings_unref_table(table);
}
return (item);
return (after);
}
static struct cmdq_item *
cmd_send_keys_inject_string(struct cmdq_item *item, struct cmdq_item *after,
struct args *args, int i)
{
const char *s = args->argv[i];
struct utf8_data *ud, *loop;
utf8_char uc;
key_code key;
char *endptr;
long n;
int literal;
if (args_has(args, 'H')) {
n = strtol(s, &endptr, 16);
if (*s =='\0' || n < 0 || n > 0xff || *endptr != '\0')
return (item);
return (cmd_send_keys_inject_key(item, after, KEYC_LITERAL|n));
}
literal = args_has(args, 'l');
if (!literal) {
key = key_string_lookup_string(s);
if (key != KEYC_NONE && key != KEYC_UNKNOWN) {
after = cmd_send_keys_inject_key(item, after, key);
if (after != NULL)
return (after);
}
literal = 1;
}
if (literal) {
ud = utf8_fromcstr(s);
for (loop = ud; loop->size != 0; loop++) {
if (loop->size == 1 && loop->data[0] <= 0x7f)
key = loop->data[0];
else {
if (utf8_from_data(loop, &uc) != UTF8_DONE)
continue;
key = uc;
}
after = cmd_send_keys_inject_key(item, after, key);
}
free(ud);
}
return (after);
}
static enum cmd_retval
cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
{
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 args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct client *tc = cmdq_get_target_client(item);
struct session *s = target->s;
struct winlink *wl = target->wl;
struct window_pane *wp = target->wp;
struct key_event *event = cmdq_get_event(item);
struct mouse_event *m = &event->m;
struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
struct utf8_data *ud, *uc;
wchar_t wc;
int i, literal;
struct cmdq_item *after = item;
int i;
key_code key;
u_int np = 1;
char *cause = NULL;
@@ -107,7 +158,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
if (wme != NULL && (args_has(args, 'X') || args->argc == 0)) {
if (wme == NULL || wme->mode->command == NULL) {
if (wme->mode->command == NULL) {
cmdq_error(item, "not in a mode");
return (CMD_RETURN_ERROR);
}
@@ -122,7 +173,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
}
if (!m->valid)
m = NULL;
wme->mode->command(wme, c, s, wl, args, m);
wme->mode->command(wme, tc, s, wl, args, m);
return (CMD_RETURN_NORMAL);
}
@@ -132,47 +183,29 @@ 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, item->client, s, wl, m->key, m);
window_pane_key(wp, tc, s, wl, m->key, m);
return (CMD_RETURN_NORMAL);
}
if (self->entry == &cmd_send_prefix_entry) {
if (cmd_get_entry(self) == &cmd_send_prefix_entry) {
if (args_has(args, '2'))
key = options_get_number(s->options, "prefix2");
else
key = options_get_number(s->options, "prefix");
cmd_send_keys_inject(c, fs, item, key);
cmd_send_keys_inject_key(item, item, key);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'R')) {
window_pane_reset_palette(wp);
input_reset(wp, 1);
input_reset(wp->ictx, 1);
}
for (; np != 0; np--) {
for (i = 0; i < args->argc; i++) {
literal = args_has(args, 'l');
if (!literal) {
key = key_string_lookup_string(args->argv[i]);
if (key != KEYC_NONE && key != KEYC_UNKNOWN) {
item = cmd_send_keys_inject(c, fs, item,
key);
} else
literal = 1;
}
if (literal) {
ud = utf8_fromcstr(args->argv[i]);
for (uc = ud; uc->size != 0; uc++) {
if (utf8_combine(uc, &wc) != UTF8_DONE)
continue;
item = cmd_send_keys_inject(c, fs, item,
wc);
}
free(ud);
}
after = cmd_send_keys_inject_string(item, after, args,
i);
}
}
return (CMD_RETURN_NORMAL);

View File

@@ -33,10 +33,11 @@ const struct cmd_entry cmd_set_buffer_entry = {
.name = "set-buffer",
.alias = "setb",
.args = { "ab:n:", 0, 1 },
.usage = "[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data",
.args = { "ab:t:n:w", 0, 1 },
.usage = "[-aw] " CMD_BUFFER_USAGE " [-n new-buffer-name] "
CMD_TARGET_CLIENT_USAGE " data",
.flags = CMD_AFTERHOOK,
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL,
.exec = cmd_set_buffer_exec
};
@@ -54,7 +55,8 @@ const struct cmd_entry cmd_delete_buffer_entry = {
static enum cmd_retval
cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct paste_buffer *pb;
char *bufdata, *cause;
const char *bufname, *olddata;
@@ -66,7 +68,7 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
else
pb = paste_get_name(bufname);
if (self->entry == &cmd_delete_buffer_entry) {
if (cmd_get_entry(self) == &cmd_delete_buffer_entry) {
if (pb == NULL)
pb = paste_get_top(&bufname);
if (pb == NULL) {
@@ -118,6 +120,8 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
free(cause);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'w') && tc != NULL)
tty_set_selection(&tc->tty, bufdata, bufsize);
return (CMD_RETURN_NORMAL);
}

View File

@@ -34,8 +34,8 @@ const struct cmd_entry cmd_set_environment_entry = {
.name = "set-environment",
.alias = "setenv",
.args = { "grt:u", 1, 2 },
.usage = "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
.args = { "Fhgrt:u", 1, 2 },
.usage = "[-Fhgru] " CMD_TARGET_SESSION_USAGE " name [value]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@@ -46,9 +46,12 @@ const struct cmd_entry cmd_set_environment_entry = {
static enum cmd_retval
cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct environ *env;
const char *name, *value, *target;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct environ *env;
const char *name, *value, *tflag;
char *expand = NULL;
enum cmd_retval retval = CMD_RETURN_NORMAL;
name = args->argv[0];
if (*name == '\0') {
@@ -62,42 +65,54 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
if (args->argc < 2)
value = NULL;
else if (args_has(args, 'F'))
value = expand = format_single_from_target(item, args->argv[1]);
else
value = args->argv[1];
if (args_has(self->args, 'g'))
if (args_has(args, 'g'))
env = global_environ;
else {
if (item->target.s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(item, "no such session: %s", target);
if (target->s == NULL) {
tflag = args_get(args, 't');
if (tflag != NULL)
cmdq_error(item, "no such session: %s", tflag);
else
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
retval = CMD_RETURN_ERROR;
goto out;
}
env = item->target.s->environ;
env = target->s->environ;
}
if (args_has(self->args, 'u')) {
if (args_has(args, 'u')) {
if (value != NULL) {
cmdq_error(item, "can't specify a value with -u");
return (CMD_RETURN_ERROR);
retval = CMD_RETURN_ERROR;
goto out;
}
environ_unset(env, name);
} else if (args_has(self->args, 'r')) {
} else if (args_has(args, 'r')) {
if (value != NULL) {
cmdq_error(item, "can't specify a value with -r");
return (CMD_RETURN_ERROR);
retval = CMD_RETURN_ERROR;
goto out;
}
environ_clear(env, name);
} else {
if (value == NULL) {
cmdq_error(item, "no value specified");
return (CMD_RETURN_ERROR);
retval = CMD_RETURN_ERROR;
goto out;
}
environ_set(env, name, "%s", value);
if (args_has(args, 'h'))
environ_set(env, name, ENVIRON_HIDDEN, "%s", value);
else
environ_set(env, name, 0, "%s", value);
}
return (CMD_RETURN_NORMAL);
out:
free(expand);
return (retval);
}

View File

@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h>
#include <string.h>
@@ -30,23 +29,14 @@
static enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmdq_item *);
static int cmd_set_option_set(struct cmd *, struct cmdq_item *,
struct options *, struct options_entry *, const char *);
static int cmd_set_option_flag(struct cmdq_item *,
const struct options_table_entry *, struct options *,
const char *);
static int cmd_set_option_choice(struct cmdq_item *,
const struct options_table_entry *, struct options *,
const char *);
const struct cmd_entry cmd_set_option_entry = {
.name = "set-option",
.alias = "set",
.args = { "aFgoqst:uw", 1, 2 },
.usage = "[-aFgosquw] [-t target-window] option [value]",
.args = { "aFgopqst:uUw", 1, 2 },
.usage = "[-aFgopqsuUw] " CMD_TARGET_PANE_USAGE " option [value]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec
@@ -69,10 +59,10 @@ 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]",
.args = { "agpRt:uw", 1, 2 },
.usage = "[-agpRuw] " CMD_TARGET_PANE_USAGE " hook [command]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec
@@ -81,27 +71,25 @@ const struct cmd_entry cmd_set_hook_entry = {
static enum cmd_retval
cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
int append = args_has(args, 'a');
struct cmd_find_state *fs = &item->target;
struct client *c, *loop;
struct session *s = fs->s;
struct winlink *wl = fs->wl;
struct window *w;
enum options_table_scope scope;
struct cmd_find_state *target = cmdq_get_target(item);
struct window_pane *loop;
struct options *oo;
struct options_entry *parent, *o;
struct options_entry *parent, *o, *po;
char *name, *argument, *value = NULL, *cause;
const char *target;
int window, idx, already, error, ambiguous;
struct style *sy;
int scope;
window = (cmd_get_entry(self) == &cmd_set_window_option_entry);
/* Expand argument. */
c = cmd_find_client(item, NULL, 1);
argument = format_single(item, args->argv[0], c, s, wl, NULL);
argument = format_single_from_target(item, args->argv[0]);
if (self->entry == &cmd_set_hook_entry && args_has(args, 'R')) {
/* If set-hook -R, fire the hook straight away. */
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'R')) {
notify_hook(item, argument);
free(argument);
return (CMD_RETURN_NORMAL);
}
@@ -119,29 +107,13 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
if (args->argc < 2)
value = NULL;
else if (args_has(args, 'F'))
value = format_single(item, args->argv[1], c, s, wl, NULL);
value = format_single_from_target(item, args->argv[1]);
else
value = xstrdup(args->argv[1]);
/*
* Figure out the scope: for user options it comes from the arguments,
* otherwise from the option name.
*/
if (*name == '@') {
window = (self->entry == &cmd_set_window_option_entry);
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);
}
}
/* Get the scope and table for the option .*/
scope = options_scope_from_name(args, window, name, target, &oo,
&cause);
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
goto out;
@@ -149,40 +121,11 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
free(cause);
goto fail;
}
/* Which table should this option go into? */
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;
}
o = options_get_only(oo, name);
parent = options_get(oo, name);
/* Check that array options and indexes match up. */
if (idx != -1 && (*name == '@' || !options_isarray(parent))) {
if (idx != -1 && (*name == '@' || !options_is_array(parent))) {
cmdq_error(item, "not an array: %s", argument);
goto fail;
}
@@ -206,19 +149,22 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
}
/* Change the option. */
if (args_has(args, 'u')) {
if (args_has(args, 'U') && scope == OPTIONS_TABLE_WINDOW) {
TAILQ_FOREACH(loop, &target->w->panes, entry) {
po = options_get_only(loop->options, name);
if (po == NULL)
continue;
if (options_remove_or_default(po, idx, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
goto fail;
}
}
}
if (args_has(args, 'u') || args_has(args, 'U')) {
if (o == NULL)
goto out;
if (idx == -1) {
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 if (options_array_set(o, idx, NULL, 0, &cause) != 0) {
if (options_remove_or_default(o, idx, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
goto fail;
@@ -229,10 +175,15 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
goto fail;
}
options_set_string(oo, name, append, "%s", value);
} else if (idx == -1 && !options_isarray(parent)) {
error = cmd_set_option_set(self, item, oo, parent, value);
if (error != 0)
} else if (idx == -1 && !options_is_array(parent)) {
error = options_from_string(oo, options_table_entry(parent),
options_table_entry(parent)->name, value,
args_has(args, 'a'), &cause);
if (error != 0) {
cmdq_error(item, "%s", cause);
free(cause);
goto fail;
}
} else {
if (value == NULL) {
cmdq_error(item, "empty value");
@@ -256,61 +207,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
}
}
/* Update timers and so on for various options. */
if (strcmp(name, "automatic-rename") == 0) {
RB_FOREACH(w, windows, &windows) {
if (w->active == NULL)
continue;
if (options_get_number(w->options, "automatic-rename"))
w->active->flags |= PANE_CHANGED;
}
}
if (strcmp(name, "key-table") == 0) {
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)
status_timer_start_all();
if (strcmp(name, "monitor-silence") == 0)
alerts_reset_all();
if (strcmp(name, "window-style") == 0 ||
strcmp(name, "window-active-style") == 0) {
RB_FOREACH(w, windows, &windows)
w->flags |= WINDOW_STYLECHANGED;
}
if (strcmp(name, "pane-border-status") == 0) {
RB_FOREACH(w, windows, &windows)
layout_fix_panes(w);
}
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(loop, &clients, entry) {
if (loop->session != NULL)
server_redraw_client(loop);
}
options_push_changes(name);
out:
free(argument);
@@ -324,130 +221,3 @@ fail:
free(name);
return (CMD_RETURN_ERROR);
}
static int
cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
struct options_entry *parent, const char *value)
{
const struct options_table_entry *oe;
struct args *args = self->args;
int append = args_has(args, 'a');
struct options_entry *o;
long long number;
const char *errstr, *new;
char *old;
key_code key;
oe = options_table_entry(parent);
if (value == NULL &&
oe->type != OPTIONS_TABLE_FLAG &&
oe->type != OPTIONS_TABLE_CHOICE) {
cmdq_error(item, "empty value");
return (-1);
}
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);
if (errstr != NULL) {
cmdq_error(item, "value is %s: %s", errstr, value);
return (-1);
}
options_set_number(oo, oe->name, number);
return (0);
case OPTIONS_TABLE_KEY:
key = key_string_lookup_string(value);
if (key == KEYC_UNKNOWN) {
cmdq_error(item, "bad key: %s", value);
return (-1);
}
options_set_number(oo, oe->name, key);
return (0);
case OPTIONS_TABLE_COLOUR:
if ((number = colour_fromstring(value)) == -1) {
cmdq_error(item, "bad colour: %s", value);
return (-1);
}
options_set_number(oo, oe->name, number);
return (0);
case OPTIONS_TABLE_FLAG:
return (cmd_set_option_flag(item, oe, oo, value));
case OPTIONS_TABLE_CHOICE:
return (cmd_set_option_choice(item, oe, oo, value));
case OPTIONS_TABLE_STYLE:
o = options_set_style(oo, oe->name, append, value);
if (o == NULL) {
cmdq_error(item, "bad style: %s", value);
return (-1);
}
return (0);
case OPTIONS_TABLE_COMMAND:
break;
}
return (-1);
}
static int
cmd_set_option_flag(struct cmdq_item *item,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
int flag;
if (value == NULL || *value == '\0')
flag = !options_get_number(oo, oe->name);
else if (strcmp(value, "1") == 0 ||
strcasecmp(value, "on") == 0 ||
strcasecmp(value, "yes") == 0)
flag = 1;
else if (strcmp(value, "0") == 0 ||
strcasecmp(value, "off") == 0 ||
strcasecmp(value, "no") == 0)
flag = 0;
else {
cmdq_error(item, "bad value: %s", value);
return (-1);
}
options_set_number(oo, oe->name, flag);
return (0);
}
static int
cmd_set_option_choice(struct cmdq_item *item,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
const char **cp;
int n, choice = -1;
if (value == NULL) {
choice = options_get_number(oo, oe->name);
if (choice < 2)
choice = !choice;
} else {
n = 0;
for (cp = oe->choices; *cp != NULL; cp++) {
if (strcmp(*cp, value) == 0)
choice = n;
n++;
}
if (choice == -1) {
cmdq_error(item, "unknown value: %s", value);
return (-1);
}
}
options_set_number(oo, oe->name, choice);
return (0);
}

View File

@@ -38,8 +38,8 @@ const struct cmd_entry cmd_show_environment_entry = {
.name = "show-environment",
.alias = "showenv",
.args = { "gst:", 0, 1 },
.usage = "[-gs] " CMD_TARGET_SESSION_USAGE " [name]",
.args = { "hgst:", 0, 1 },
.usage = "[-hgs] " CMD_TARGET_SESSION_USAGE " [name]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@@ -69,9 +69,15 @@ static void
cmd_show_environment_print(struct cmd *self, struct cmdq_item *item,
struct environ_entry *envent)
{
char *escaped;
struct args *args = cmd_get_args(self);
char *escaped;
if (!args_has(self->args, 's')) {
if (!args_has(args, 'h') && (envent->flags & ENVIRON_HIDDEN))
return;
if (args_has(args, 'h') && (~envent->flags & ENVIRON_HIDDEN))
return;
if (!args_has(args, 's')) {
if (envent->value != NULL)
cmdq_print(item, "%s=%s", envent->name, envent->value);
else
@@ -91,30 +97,31 @@ cmd_show_environment_print(struct cmd *self, struct cmdq_item *item,
static enum cmd_retval
cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct environ *env;
struct environ_entry *envent;
const char *target;
const char *tflag;
if ((target = args_get(args, 't')) != NULL) {
if (item->target.s == NULL) {
cmdq_error(item, "no such session: %s", target);
if ((tflag = args_get(args, 't')) != NULL) {
if (target->s == NULL) {
cmdq_error(item, "no such session: %s", tflag);
return (CMD_RETURN_ERROR);
}
}
if (args_has(self->args, 'g'))
if (args_has(args, 'g'))
env = global_environ;
else {
if (item->target.s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(item, "no such session: %s", target);
if (target->s == NULL) {
tflag = args_get(args, 't');
if (tflag != NULL)
cmdq_error(item, "no such session: %s", tflag);
else
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
}
env = item->target.s->environ;
env = target->s->environ;
}
if (args->argc != 0) {

View File

@@ -18,16 +18,19 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "tmux.h"
/*
* Show client message log.
* Show message log.
*/
#define SHOW_MESSAGES_TEMPLATE \
"#{t/p:message_time}: #{message_text}"
static enum cmd_retval cmd_show_messages_exec(struct cmd *,
struct cmdq_item *);
@@ -38,26 +41,28 @@ const struct cmd_entry cmd_show_messages_entry = {
.args = { "JTt:", 0, 0 },
.usage = "[-JT] " CMD_TARGET_CLIENT_USAGE,
.flags = CMD_AFTERHOOK,
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
.exec = cmd_show_messages_exec
};
static int cmd_show_messages_terminals(struct cmdq_item *, int);
static int
cmd_show_messages_terminals(struct cmdq_item *item, int blank)
cmd_show_messages_terminals(struct cmd *self, struct cmdq_item *item, int blank)
{
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct tty_term *term;
u_int i, n;
n = 0;
LIST_FOREACH(term, &tty_terms, entry) {
if (args_has(args, 't') && term != tc->tty.term)
continue;
if (blank) {
cmdq_print(item, "%s", "");
blank = 0;
}
cmdq_print(item, "Terminal %u: %s [references=%u, flags=0x%x]:",
n, term->name, term->references, term->flags);
cmdq_print(item, "Terminal %u: %s for %s, flags=0x%x:", n,
term->name, term->tty->client->name, term->flags);
n++;
for (i = 0; i < tty_term_ncodes(); i++)
cmdq_print(item, "%s", tty_term_describe(term, i));
@@ -68,18 +73,15 @@ cmd_show_messages_terminals(struct cmdq_item *item, int blank)
static enum cmd_retval
cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c;
struct args *args = cmd_get_args(self);
struct message_entry *msg;
char *tim;
char *s;
int done, blank;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
struct format_tree *ft;
done = blank = 0;
if (args_has(args, 'T')) {
blank = cmd_show_messages_terminals(item, blank);
blank = cmd_show_messages_terminals(self, item, blank);
done = 1;
}
if (args_has(args, 'J')) {
@@ -89,12 +91,17 @@ cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
if (done)
return (CMD_RETURN_NORMAL);
TAILQ_FOREACH(msg, &c->message_log, entry) {
tim = ctime(&msg->msg_time);
*strchr(tim, '\n') = '\0';
ft = format_create_from_target(item);
TAILQ_FOREACH_REVERSE(msg, &message_log, message_list, entry) {
format_add(ft, "message_text", "%s", msg->msg);
format_add(ft, "message_number", "%u", msg->msg_num);
format_add_tv(ft, "message_time", &msg->msg_time);
cmdq_print(item, "%s %s", tim, msg->msg);
s = format_expand(ft, SHOW_MESSAGES_TEMPLATE);
cmdq_print(item, "%s", s);
free(s);
}
format_free(ft);
return (CMD_RETURN_NORMAL);
}

View File

@@ -30,18 +30,18 @@
static enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmdq_item *);
static void cmd_show_options_print(struct cmd *, struct cmdq_item *,
struct options_entry *, int);
struct options_entry *, int, int);
static enum cmd_retval cmd_show_options_all(struct cmd *, struct cmdq_item *,
struct options *);
int, struct options *);
const struct cmd_entry cmd_show_options_entry = {
.name = "show-options",
.alias = "show",
.args = { "gHqst:vw", 0, 1 },
.usage = "[-gHqsvw] [-t target-session|target-window] [option]",
.args = { "AgHpqst:vw", 0, 1 },
.usage = "[-AgHpqsvw] " CMD_TARGET_PANE_USAGE " [option]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec
@@ -64,10 +64,10 @@ const struct cmd_entry cmd_show_hooks_entry = {
.name = "show-hooks",
.alias = NULL,
.args = { "gt:", 0, 1 },
.usage = "[-g] " CMD_TARGET_SESSION_USAGE,
.args = { "gpt:w", 0, 1 },
.usage = "[-gpw] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec
@@ -76,21 +76,18 @@ const struct cmd_entry cmd_show_hooks_entry = {
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->target;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct options *oo;
enum options_table_scope scope;
char *argument, *name = NULL, *cause;
const char *target;
int window, idx, ambiguous;
int window, idx, ambiguous, parent, scope;
struct options_entry *o;
window = (self->entry == &cmd_show_window_options_entry);
window = (cmd_get_entry(self) == &cmd_show_window_options_entry);
if (args->argc == 0) {
scope = options_scope_from_flags(args, window, fs, &oo, &cause);
scope = options_scope_from_flags(args, window, target, &oo,
&cause);
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL);
@@ -98,9 +95,9 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
free(cause);
return (CMD_RETURN_ERROR);
}
return (cmd_show_options_all(self, item, oo));
return (cmd_show_options_all(self, item, scope, oo));
}
argument = format_single(item, args->argv[0], c, s, wl, NULL);
argument = format_single_from_target(item, args->argv[0]);
name = options_match(argument, &idx, &ambiguous);
if (name == NULL) {
@@ -112,49 +109,8 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
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;
}
}
scope = options_scope_from_name(args, window, name, target, &oo,
&cause);
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
goto fail;
@@ -163,8 +119,13 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
goto fail;
}
o = options_get_only(oo, name);
if (args_has(args, 'A') && o == NULL) {
o = options_get(oo, name);
parent = 1;
} else
parent = 0;
if (o != NULL)
cmd_show_options_print(self, item, o, idx);
cmd_show_options_print(self, item, o, idx, parent);
free(name);
free(argument);
@@ -178,8 +139,9 @@ fail:
static void
cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
struct options_entry *o, int idx)
struct options_entry *o, int idx, int parent)
{
struct args *args = cmd_get_args(self);
struct options_array_item *a;
const char *name = options_name(o);
char *value, *tmp = NULL, *escaped;
@@ -188,71 +150,104 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
xasprintf(&tmp, "%s[%d]", name, idx);
name = tmp;
} else {
if (options_isarray(o)) {
if (options_is_array(o)) {
a = options_array_first(o);
if (a == NULL) {
if (!args_has(self->args, 'v'))
if (!args_has(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);
cmd_show_options_print(self, item, o, idx,
parent);
a = options_array_next(a);
}
return;
}
}
value = options_tostring(o, idx, 0);
if (args_has(self->args, 'v'))
value = options_to_string(o, idx, 0);
if (args_has(args, 'v'))
cmdq_print(item, "%s", value);
else if (options_isstring(o)) {
else if (options_is_string(o)) {
escaped = args_escape(value);
cmdq_print(item, "%s %s", name, escaped);
if (parent)
cmdq_print(item, "%s* %s", name, escaped);
else
cmdq_print(item, "%s %s", name, escaped);
free(escaped);
} else
cmdq_print(item, "%s %s", name, value);
} else {
if (parent)
cmdq_print(item, "%s* %s", name, value);
else
cmdq_print(item, "%s %s", name, value);
}
free(value);
free(tmp);
}
static enum cmd_retval
cmd_show_options_all(struct cmd *self, struct cmdq_item *item,
cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
struct options *oo)
{
struct args *args = cmd_get_args(self);
const struct options_table_entry *oe;
struct options_entry *o;
struct options_array_item *a;
const char *name;
u_int idx;
const struct options_table_entry *oe;
int parent;
o = options_first(oo);
while (o != NULL) {
oe = options_table_entry(o);
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)))) {
if (cmd_get_entry(self) != &cmd_show_hooks_entry) {
o = options_first(oo);
while (o != NULL) {
if (options_table_entry(o) == NULL)
cmd_show_options_print(self, item, o, -1, 0);
o = options_next(o);
continue;
}
if (!options_isarray(o))
cmd_show_options_print(self, item, o, -1);
}
for (oe = options_table; oe->name != NULL; oe++) {
if (~oe->scope & scope)
continue;
if ((cmd_get_entry(self) != &cmd_show_hooks_entry &&
!args_has(args, 'H') &&
(oe->flags & OPTIONS_TABLE_IS_HOOK)) ||
(cmd_get_entry(self) == &cmd_show_hooks_entry &&
(~oe->flags & OPTIONS_TABLE_IS_HOOK)))
continue;
o = options_get_only(oo, oe->name);
if (o == NULL) {
if (!args_has(args, 'A'))
continue;
o = options_get(oo, oe->name);
if (o == NULL)
continue;
parent = 1;
} else
parent = 0;
if (!options_is_array(o))
cmd_show_options_print(self, item, o, -1, parent);
else if ((a = options_array_first(o)) == NULL) {
if (!args_has(self->args, 'v'))
cmdq_print(item, "%s", options_name(o));
if (!args_has(args, 'v')) {
name = options_name(o);
if (parent)
cmdq_print(item, "%s*", name);
else
cmdq_print(item, "%s", name);
}
} else {
while (a != NULL) {
idx = options_array_item_index(a);
cmd_show_options_print(self, item, o, idx);
cmd_show_options_print(self, item, o, idx,
parent);
a = options_array_next(a);
}
}
o = options_next(o);
}
return (CMD_RETURN_NORMAL);
}

View File

@@ -31,83 +31,170 @@
static enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmdq_item *);
static enum cmd_retval cmd_source_file_done(struct cmdq_item *, void *);
const struct cmd_entry cmd_source_file_entry = {
.name = "source-file",
.alias = "source",
.args = { "nq", 1, -1 },
.usage = "[-nq] path ...",
.args = { "Fnqv", 1, -1 },
.usage = "[-Fnqv] path ...",
.flags = 0,
.exec = cmd_source_file_exec
};
struct cmd_source_file_data {
struct cmdq_item *item;
int flags;
struct cmdq_item *after;
enum cmd_retval retval;
u_int current;
char **files;
u_int nfiles;
};
static enum cmd_retval
cmd_source_file_complete_cb(struct cmdq_item *item, __unused void *data)
{
cfg_print_causes(item);
return (CMD_RETURN_NORMAL);
}
static void
cmd_source_file_complete(struct client *c, struct cmd_source_file_data *cdata)
{
struct cmdq_item *new_item;
if (cfg_finished) {
if (cdata->retval == CMD_RETURN_ERROR &&
c != NULL &&
c->session == NULL)
c->retval = 1;
new_item = cmdq_get_callback(cmd_source_file_complete_cb, NULL);
cmdq_insert_after(cdata->after, new_item);
}
free(cdata->files);
free(cdata);
}
static void
cmd_source_file_done(struct client *c, const char *path, int error,
int closed, struct evbuffer *buffer, void *data)
{
struct cmd_source_file_data *cdata = data;
struct cmdq_item *item = cdata->item;
void *bdata = EVBUFFER_DATA(buffer);
size_t bsize = EVBUFFER_LENGTH(buffer);
u_int n;
struct cmdq_item *new_item;
if (!closed)
return;
if (error != 0)
cmdq_error(item, "%s: %s", path, strerror(error));
else if (bsize != 0) {
if (load_cfg_from_buffer(bdata, bsize, path, c, cdata->after,
cdata->flags, &new_item) < 0)
cdata->retval = CMD_RETURN_ERROR;
else if (new_item != NULL)
cdata->after = new_item;
}
n = ++cdata->current;
if (n < cdata->nfiles)
file_read(c, cdata->files[n], cmd_source_file_done, cdata);
else {
cmd_source_file_complete(c, cdata);
cmdq_continue(item);
}
}
static void
cmd_source_file_add(struct cmd_source_file_data *cdata, const char *path)
{
log_debug("%s: %s", __func__, path);
cdata->files = xreallocarray(cdata->files, cdata->nfiles + 1,
sizeof *cdata->files);
cdata->files[cdata->nfiles++] = xstrdup(path);
}
static enum cmd_retval
cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
int flags = 0;
struct client *c = item->client;
struct cmdq_item *new_item, *after;
enum cmd_retval retval;
char *pattern, *cwd;
const char *path, *error;
glob_t g;
int i;
u_int j;
struct args *args = cmd_get_args(self);
struct cmd_source_file_data *cdata;
struct client *c = cmdq_get_client(item);
enum cmd_retval retval = CMD_RETURN_NORMAL;
char *pattern, *cwd, *expand = NULL;
const char *path, *error;
glob_t g;
int i, result;
u_int j;
cdata = xcalloc(1, sizeof *cdata);
cdata->item = item;
if (args_has(args, 'q'))
flags |= CMD_PARSE_QUIET;
cdata->flags |= CMD_PARSE_QUIET;
if (args_has(args, 'n'))
flags |= CMD_PARSE_PARSEONLY;
cdata->flags |= CMD_PARSE_PARSEONLY;
if (args_has(args, 'v'))
cdata->flags |= CMD_PARSE_VERBOSE;
utf8_stravis(&cwd, server_client_get_cwd(c, NULL), VIS_GLOB);
retval = CMD_RETURN_NORMAL;
for (i = 0; i < args->argc; i++) {
path = args->argv[i];
if (args_has(args, 'F')) {
free(expand);
expand = format_single_from_target(item, args->argv[i]);
path = expand;
} else
path = args->argv[i];
if (strcmp(path, "-") == 0) {
cmd_source_file_add(cdata, "-");
continue;
}
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)) {
if ((result = glob(pattern, 0, NULL, &g)) != 0) {
if (result != GLOB_NOMATCH ||
(~cdata->flags & CMD_PARSE_QUIET)) {
if (result == GLOB_NOMATCH)
error = strerror(ENOENT);
else if (result == GLOB_NOSPACE)
error = strerror(ENOMEM);
else
error = strerror(EINVAL);
cmdq_error(item, "%s: %s", path, error);
retval = CMD_RETURN_ERROR;
}
free(pattern);
continue;
}
free(expand);
free(pattern);
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);
for (j = 0; j < g.gl_pathc; j++)
cmd_source_file_add(cdata, g.gl_pathv[j]);
}
cdata->after = item;
cdata->retval = retval;
if (cdata->nfiles != 0) {
file_read(c, cdata->files[0], cmd_source_file_done, cdata);
retval = CMD_RETURN_WAIT;
} else
cmd_source_file_complete(c, cdata);
free(cwd);
return (retval);
}
static enum cmd_retval
cmd_source_file_done(struct cmdq_item *item, __unused void *data)
{
cfg_print_causes(item);
return (CMD_RETURN_NORMAL);
}

View File

@@ -39,10 +39,9 @@ const struct cmd_entry cmd_split_window_entry = {
.name = "split-window",
.alias = "splitw",
.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]",
.args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1 },
.usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] "
"[-F format] [-l size] " CMD_TARGET_PANE_USAGE " [command]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -53,31 +52,49 @@ const struct cmd_entry cmd_split_window_entry = {
static enum cmd_retval
cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
struct args *args = cmd_get_args(self);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
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;
struct client *tc = cmdq_get_target_client(item);
struct session *s = target->s;
struct winlink *wl = target->wl;
struct window_pane *wp = target->wp, *new_wp;
enum layout_type type;
struct layout_cell *lc;
struct cmd_find_state fs;
int size, percentage, flags, input;
const char *template, *add;
char *cause, *cp;
const char *template, *add, *errstr, *p;
char *cause, *cp, *copy;
size_t plen;
struct args_value *value;
if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT;
else
type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "create pane failed: -l %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
if ((p = args_get(args, 'l')) != NULL) {
plen = strlen(p);
if (p[plen - 1] == '%') {
copy = xstrdup(p);
copy[plen - 1] = '\0';
percentage = strtonum(copy, 0, INT_MAX, &errstr);
free(copy);
if (errstr != NULL) {
cmdq_error(item, "percentage %s", errstr);
return (CMD_RETURN_ERROR);
}
if (type == LAYOUT_TOPBOTTOM)
size = (wp->sy * percentage) / 100;
else
size = (wp->sx * percentage) / 100;
} else {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "lines %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
} else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause);
@@ -93,7 +110,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
} else
size = -1;
server_unzoom_window(wp->window);
window_push_zoom(wp->window, 1, args_has(args, 'Z'));
input = (args_has(args, 'I') && args->argc == 0);
flags = 0;
@@ -125,7 +142,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
environ_put(sc.environ, add, 0);
add = args_next_value(&value);
}
@@ -135,14 +152,16 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
sc.flags = flags;
if (args_has(args, 'd'))
sc.flags |= SPAWN_DETACHED;
if (args_has(args, 'Z'))
sc.flags |= SPAWN_ZOOM;
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) {
server_client_remove_pane(new_wp);
layout_close_pane(new_wp);
window_remove_pane(wp->window, new_wp);
cmdq_error(item, "%s", cause);
@@ -151,13 +170,14 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
}
if (!args_has(args, 'd'))
cmd_find_from_winlink_pane(current, wl, new_wp, 0);
window_pop_zoom(wp->window);
server_redraw_window(wp->window);
server_status_session(s);
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = SPLIT_WINDOW_TEMPLATE;
cp = format_single(item, template, c, s, wl, new_wp);
cp = format_single(item, template, tc, s, wl, new_wp);
cmdq_print(item, "%s", cp);
free(cp);
}

View File

@@ -32,8 +32,8 @@ const struct cmd_entry cmd_swap_pane_entry = {
.name = "swap-pane",
.alias = "swapp",
.args = { "dDs:t:U", 0, 0 },
.usage = "[-dDU] " CMD_SRCDST_PANE_USAGE,
.args = { "dDs:t:UZ", 0, 0 },
.usage = "[-dDUZ] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 },
@@ -45,32 +45,42 @@ const struct cmd_entry cmd_swap_pane_entry = {
static enum cmd_retval
cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *source = cmdq_get_source(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct window *src_w, *dst_w;
struct window_pane *tmp_wp, *src_wp, *dst_wp;
struct layout_cell *src_lc, *dst_lc;
u_int sx, sy, xoff, yoff;
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);
dst_w = target->wl->window;
dst_wp = target->wp;
src_w = source->wl->window;
src_wp = source->wp;
if (args_has(self->args, 'D')) {
if (window_push_zoom(dst_w, 0, args_has(args, 'Z')))
server_redraw_window(dst_w);
if (args_has(args, 'D')) {
src_w = dst_w;
src_wp = TAILQ_NEXT(dst_wp, entry);
if (src_wp == NULL)
src_wp = TAILQ_FIRST(&dst_w->panes);
} else if (args_has(self->args, 'U')) {
} else if (args_has(args, 'U')) {
src_w = dst_w;
src_wp = TAILQ_PREV(dst_wp, window_panes, entry);
if (src_wp == NULL)
src_wp = TAILQ_LAST(&dst_w->panes, window_panes);
}
server_unzoom_window(src_w);
if (src_w != dst_w && window_push_zoom(src_w, 0, args_has(args, 'Z')))
server_redraw_window(src_w);
if (src_wp == dst_wp)
return (CMD_RETURN_NORMAL);
goto out;
server_client_remove_pane(src_wp);
server_client_remove_pane(dst_wp);
tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry);
TAILQ_REMOVE(&dst_w->panes, dst_wp, entry);
@@ -90,7 +100,11 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
src_wp->layout_cell = dst_lc;
src_wp->window = dst_w;
options_set_parent(src_wp->options, dst_w->options);
src_wp->flags |= PANE_STYLECHANGED;
dst_wp->window = src_w;
options_set_parent(dst_wp->options, src_w->options);
dst_wp->flags |= PANE_STYLECHANGED;
sx = src_wp->sx; sy = src_wp->sy;
xoff = src_wp->xoff; yoff = src_wp->yoff;
@@ -99,7 +113,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
dst_wp->xoff = xoff; dst_wp->yoff = yoff;
window_pane_resize(dst_wp, sx, sy);
if (!args_has(self->args, 'd')) {
if (!args_has(args, 'd')) {
if (src_w != dst_w) {
window_set_active_pane(src_w, dst_wp, 1);
window_set_active_pane(dst_w, src_wp, 1);
@@ -122,5 +136,10 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
server_redraw_window(src_w);
server_redraw_window(dst_w);
out:
if (window_pop_zoom(src_w))
server_redraw_window(src_w);
if (src_w != dst_w && window_pop_zoom(dst_w))
server_redraw_window(dst_w);
return (CMD_RETURN_NORMAL);
}

View File

@@ -45,20 +45,20 @@ const struct cmd_entry cmd_swap_window_entry = {
static enum cmd_retval
cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct session *src, *dst;
struct args *args = cmd_get_args(self);
struct cmd_find_state *source = cmdq_get_source(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct session *src = source->s, *dst = target->s;
struct session_group *sg_src, *sg_dst;
struct winlink *wl_src, *wl_dst;
struct winlink *wl_src = source->wl, *wl_dst = target->wl;
struct window *w_src, *w_dst;
wl_src = item->source.wl;
src = item->source.s;
sg_src = session_group_contains(src);
wl_dst = item->target.wl;
dst = item->target.s;
sg_dst = session_group_contains(dst);
if (src != dst && sg_src != NULL && sg_dst != NULL &&
if (src != dst &&
sg_src != NULL &&
sg_dst != NULL &&
sg_src == sg_dst) {
cmdq_error(item, "can't move window, sessions are grouped");
return (CMD_RETURN_ERROR);
@@ -77,10 +77,10 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
wl_src->window = w_dst;
TAILQ_INSERT_TAIL(&w_dst->winlinks, wl_src, wentry);
if (!args_has(self->args, 'd')) {
session_select(src, wl_src->idx);
if (args_has(args, 'd')) {
session_select(dst, wl_dst->idx);
if (src != dst)
session_select(dst, wl_dst->idx);
session_select(src, wl_src->idx);
}
session_group_synchronize_from(src);
server_redraw_session_group(src);

View File

@@ -34,33 +34,33 @@ const struct cmd_entry cmd_switch_client_entry = {
.name = "switch-client",
.alias = "switchc",
.args = { "lc:Enpt:rT:", 0, 0 },
.usage = "[-Elnpr] [-c target-client] [-t target-session] "
.args = { "lc:EFnpt:rT:Z", 0, 0 },
.usage = "[-ElnprZ] [-c target-client] [-t target-session] "
"[-T key-table]",
/* -t is special */
.flags = CMD_READONLY,
.flags = CMD_READONLY|CMD_CLIENT_CFLAG,
.exec = cmd_switch_client_exec
};
static enum cmd_retval
cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state target;
const char *tflag = args_get(args, 't');
enum cmd_find_type type;
int flags;
struct client *c;
struct client *tc = cmdq_get_target_client(item);
struct session *s;
struct winlink *wl;
struct window *w;
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;
@@ -68,14 +68,18 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
type = CMD_FIND_SESSION;
flags = CMD_FIND_PREFER_UNATTACHED;
}
if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
if (cmd_find_target(&target, item, tflag, type, flags) != 0)
return (CMD_RETURN_ERROR);
s = item->target.s;
wl = item->target.wl;
wp = item->target.wp;
s = target.s;
wl = target.wl;
wp = target.wp;
if (args_has(args, 'r'))
c->flags ^= CLIENT_READONLY;
if (args_has(args, 'r')) {
if (tc->flags & CLIENT_READONLY)
tc->flags &= ~(CLIENT_READONLY|CLIENT_IGNORESIZE);
else
tc->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE);
}
tablename = args_get(args, 'T');
if (tablename != NULL) {
@@ -85,24 +89,24 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
table->references++;
key_bindings_unref_table(c->keytable);
c->keytable = table;
key_bindings_unref_table(tc->keytable);
tc->keytable = table;
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'n')) {
if ((s = session_next_session(c->session)) == NULL) {
if ((s = session_next_session(tc->session)) == NULL) {
cmdq_error(item, "can't find next session");
return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'p')) {
if ((s = session_previous_session(c->session)) == NULL) {
if ((s = session_previous_session(tc->session)) == NULL) {
cmdq_error(item, "can't find previous session");
return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'l')) {
if (c->last_session != NULL && session_alive(c->last_session))
s = c->last_session;
if (tc->last_session != NULL && session_alive(tc->last_session))
s = tc->last_session;
else
s = NULL;
if (s == NULL) {
@@ -110,37 +114,42 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
} else {
if (item->client == NULL)
if (cmdq_get_client(item) == NULL)
return (CMD_RETURN_NORMAL);
if (wl != NULL && wp != NULL && wp != wl->window->active) {
w = wl->window;
if (window_push_zoom(w, 0, args_has(args, 'Z')))
server_redraw_window(w);
window_redraw_active_switch(w, wp);
window_set_active_pane(w, wp, 1);
if (window_pop_zoom(w))
server_redraw_window(w);
}
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);
cmd_find_from_session(current, s, 0);
}
}
if (!args_has(args, 'E'))
environ_update(s->options, c->environ, s->environ);
environ_update(s->options, tc->environ, s->environ);
if (c->session != NULL && c->session != s)
c->last_session = c->session;
c->session = s;
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);
if (tc->session != NULL && tc->session != s)
tc->last_session = tc->session;
tc->session = s;
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT)
server_client_set_key_table(tc, NULL);
tty_update_client_offset(tc);
status_timer_start(tc);
notify_client("client-session-changed", tc);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
recalculate_sizes();
server_check_unattached();
server_redraw_client(c);
server_redraw_client(tc);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
s->curw->window->latest = tc;
recalculate_sizes();
alerts_check_session(s);
return (CMD_RETURN_NORMAL);

View File

@@ -32,8 +32,8 @@ const struct cmd_entry cmd_unbind_key_entry = {
.name = "unbind-key",
.alias = "unbind",
.args = { "anT:", 0, 1 },
.usage = "[-an] [-T key-table] key",
.args = { "anqT:", 0, 1 },
.usage = "[-anq] [-T key-table] key",
.flags = CMD_AFTERHOOK,
.exec = cmd_unbind_key_exec
@@ -42,47 +42,57 @@ const struct cmd_entry cmd_unbind_key_entry = {
static enum cmd_retval
cmd_unbind_key_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
key_code key;
const char *tablename;
int quiet = args_has(args, 'q');
if (!args_has(args, 'a')) {
if (args->argc != 1) {
cmdq_error(item, "missing key");
return (CMD_RETURN_ERROR);
}
key = key_string_lookup_string(args->argv[0]);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
cmdq_error(item, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
} else {
if (args_has(args, 'a')) {
if (args->argc != 0) {
cmdq_error(item, "key given with -a");
if (!quiet)
cmdq_error(item, "key given with -a");
return (CMD_RETURN_ERROR);
}
key = KEYC_UNKNOWN;
}
if (key == KEYC_UNKNOWN) {
tablename = args_get(args, 'T');
if (tablename == NULL) {
key_bindings_remove_table("root");
key_bindings_remove_table("prefix");
return (CMD_RETURN_NORMAL);
if (args_has(args, 'n'))
tablename = "root";
else
tablename = "prefix";
}
if (key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(item, "table %s doesn't exist", tablename);
if (!quiet) {
cmdq_error(item, "table %s doesn't exist" ,
tablename);
}
return (CMD_RETURN_ERROR);
}
key_bindings_remove_table(tablename);
return (CMD_RETURN_NORMAL);
}
if (args->argc != 1) {
if (!quiet)
cmdq_error(item, "missing key");
return (CMD_RETURN_ERROR);
}
key = key_string_lookup_string(args->argv[0]);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
if (!quiet)
cmdq_error(item, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'T')) {
tablename = args_get(args, 'T');
if (key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(item, "table %s doesn't exist", tablename);
if (!quiet) {
cmdq_error(item, "table %s doesn't exist" ,
tablename);
}
return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'n'))

View File

@@ -120,7 +120,7 @@ cmd_wait_for_remove(struct wait_channel *wc)
static enum cmd_retval
cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = cmd_get_args(self);
const char *name = args->argv[0];
struct wait_channel *wc, wc0;
@@ -153,7 +153,7 @@ cmd_wait_for_signal(__unused struct cmdq_item *item, const char *name,
log_debug("signal wait channel %s, with waiters", wc->name);
TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
wi->item->flags &= ~CMDQ_WAITING;
cmdq_continue(wi->item);
TAILQ_REMOVE(&wc->waiters, wi, entry);
free(wi);
@@ -167,7 +167,7 @@ static enum cmd_retval
cmd_wait_for_wait(struct cmdq_item *item, const char *name,
struct wait_channel *wc)
{
struct client *c = item->client;
struct client *c = cmdq_get_client(item);
struct wait_item *wi;
if (c == NULL) {
@@ -198,7 +198,7 @@ cmd_wait_for_lock(struct cmdq_item *item, const char *name,
{
struct wait_item *wi;
if (item->client == NULL) {
if (cmdq_get_client(item) == NULL) {
cmdq_error(item, "not able to lock");
return (CMD_RETURN_ERROR);
}
@@ -229,7 +229,7 @@ cmd_wait_for_unlock(struct cmdq_item *item, const char *name,
}
if ((wi = TAILQ_FIRST(&wc->lockers)) != NULL) {
wi->item->flags &= ~CMDQ_WAITING;
cmdq_continue(wi->item);
TAILQ_REMOVE(&wc->lockers, wi, entry);
free(wi);
} else {
@@ -248,13 +248,13 @@ cmd_wait_for_flush(void)
RB_FOREACH_SAFE(wc, wait_channels, &wait_channels, wc1) {
TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
wi->item->flags &= ~CMDQ_WAITING;
cmdq_continue(wi->item);
TAILQ_REMOVE(&wc->waiters, wi, entry);
free(wi);
}
wc->woken = 1;
TAILQ_FOREACH_SAFE(wi, &wc->lockers, entry, wi1) {
wi->item->flags &= ~CMDQ_WAITING;
cmdq_continue(wi->item);
TAILQ_REMOVE(&wc->lockers, wi, entry);
free(wi);
}

223
cmd.c
View File

@@ -39,10 +39,12 @@ extern const struct cmd_entry cmd_clock_mode_entry;
extern const struct cmd_entry cmd_command_prompt_entry;
extern const struct cmd_entry cmd_confirm_before_entry;
extern const struct cmd_entry cmd_copy_mode_entry;
extern const struct cmd_entry cmd_customize_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_popup_entry;
extern const struct cmd_entry cmd_display_panes_entry;
extern const struct cmd_entry cmd_down_pane_entry;
extern const struct cmd_entry cmd_find_window_entry;
@@ -128,10 +130,12 @@ const struct cmd_entry *cmd_table[] = {
&cmd_command_prompt_entry,
&cmd_confirm_before_entry,
&cmd_copy_mode_entry,
&cmd_customize_mode_entry,
&cmd_delete_buffer_entry,
&cmd_detach_client_entry,
&cmd_display_menu_entry,
&cmd_display_message_entry,
&cmd_display_popup_entry,
&cmd_display_panes_entry,
&cmd_find_window_entry,
&cmd_has_session_entry,
@@ -204,6 +208,27 @@ const struct cmd_entry *cmd_table[] = {
NULL
};
/* Instance of a command. */
struct cmd {
const struct cmd_entry *entry;
struct args *args;
u_int group;
char *file;
u_int line;
char *alias;
int argc;
char **argv;
TAILQ_ENTRY(cmd) qentry;
};
TAILQ_HEAD(cmds, cmd);
/* Next group number for new command list. */
static u_int cmd_list_next_group = 1;
/* Log an argument vector. */
void printflike(3, 4)
cmd_log_argv(int argc, char **argv, const char *fmt, ...)
{
@@ -220,6 +245,7 @@ cmd_log_argv(int argc, char **argv, const char *fmt, ...)
free(prefix);
}
/* Prepend to an argument vector. */
void
cmd_prepend_argv(int *argc, char ***argv, char *arg)
{
@@ -236,6 +262,7 @@ cmd_prepend_argv(int *argc, char ***argv, char *arg)
(*argc)++;
}
/* Append to an argument vector. */
void
cmd_append_argv(int *argc, char ***argv, char *arg)
{
@@ -243,6 +270,7 @@ cmd_append_argv(int *argc, char ***argv, char *arg)
(*argv)[(*argc)++] = xstrdup(arg);
}
/* Pack an argument vector up into a buffer. */
int
cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
{
@@ -265,6 +293,7 @@ cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
return (0);
}
/* Unpack an argument vector from a packed buffer. */
int
cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
{
@@ -293,6 +322,7 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
return (0);
}
/* Copy an argument vector, ensuring it is terminated by NULL. */
char **
cmd_copy_argv(int argc, char **argv)
{
@@ -309,6 +339,7 @@ cmd_copy_argv(int argc, char **argv)
return (new_argv);
}
/* Free an argument vector. */
void
cmd_free_argv(int argc, char **argv)
{
@@ -321,32 +352,67 @@ cmd_free_argv(int argc, char **argv)
free(argv);
}
/* Convert argument vector to a string. */
char *
cmd_stringify_argv(int argc, char **argv)
{
char *buf;
char *buf = NULL, *s;
size_t len = 0;
int i;
size_t len;
if (argc == 0)
return (xstrdup(""));
len = 0;
buf = NULL;
for (i = 0; i < argc; i++) {
len += strlen(argv[i]) + 1;
s = args_escape(argv[i]);
log_debug("%s: %u %s = %s", __func__, i, argv[i], s);
len += strlen(s) + 1;
buf = xrealloc(buf, len);
if (i == 0)
*buf = '\0';
else
strlcat(buf, " ", len);
strlcat(buf, argv[i], len);
strlcat(buf, s, len);
free(s);
}
return (buf);
}
/* Get entry for command. */
const struct cmd_entry *
cmd_get_entry(struct cmd *cmd)
{
return (cmd->entry);
}
/* Get arguments for command. */
struct args *
cmd_get_args(struct cmd *cmd)
{
return (cmd->args);
}
/* Get group for command. */
u_int
cmd_get_group(struct cmd *cmd)
{
return (cmd->group);
}
/* Get file and line for command. */
void
cmd_get_source(struct cmd *cmd, const char **file, u_int *line)
{
if (file != NULL)
*file = cmd->file;
if (line != NULL)
*line = cmd->line;
}
/* Look for an alias for a command. */
char *
cmd_get_alias(const char *name)
{
@@ -377,12 +443,13 @@ cmd_get_alias(const char *name)
return (NULL);
}
/* Look up a command entry by name. */
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];
char s[8192];
ambiguous = 0;
for (loop = cmd_table; *loop != NULL; loop++) {
@@ -426,6 +493,7 @@ ambiguous:
return (NULL);
}
/* Parse a single command from an argument vector. */
struct cmd *
cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause)
{
@@ -474,6 +542,7 @@ usage:
return (NULL);
}
/* Free a command. */
void
cmd_free(struct cmd *cmd)
{
@@ -486,6 +555,7 @@ cmd_free(struct cmd *cmd)
free(cmd);
}
/* Get a command as a string. */
char *
cmd_print(struct cmd *cmd)
{
@@ -501,6 +571,133 @@ cmd_print(struct cmd *cmd)
return (out);
}
/* Create a new command list. */
struct cmd_list *
cmd_list_new(void)
{
struct cmd_list *cmdlist;
cmdlist = xcalloc(1, sizeof *cmdlist);
cmdlist->references = 1;
cmdlist->group = cmd_list_next_group++;
cmdlist->list = xcalloc(1, sizeof *cmdlist->list);
TAILQ_INIT(cmdlist->list);
return (cmdlist);
}
/* Append a command to a command list. */
void
cmd_list_append(struct cmd_list *cmdlist, struct cmd *cmd)
{
cmd->group = cmdlist->group;
TAILQ_INSERT_TAIL(cmdlist->list, cmd, qentry);
}
/* Move all commands from one command list to another */
void
cmd_list_move(struct cmd_list *cmdlist, struct cmd_list *from)
{
TAILQ_CONCAT(cmdlist->list, from->list, qentry);
cmdlist->group = cmd_list_next_group++;
}
/* Free a command list. */
void
cmd_list_free(struct cmd_list *cmdlist)
{
struct cmd *cmd, *cmd1;
if (--cmdlist->references != 0)
return;
TAILQ_FOREACH_SAFE(cmd, cmdlist->list, qentry, cmd1) {
TAILQ_REMOVE(cmdlist->list, cmd, qentry);
cmd_free(cmd);
}
free(cmdlist->list);
free(cmdlist);
}
/* Get a command list as a string. */
char *
cmd_list_print(struct cmd_list *cmdlist, int escaped)
{
struct cmd *cmd, *next;
char *buf, *this;
size_t len;
len = 1;
buf = xcalloc(1, len);
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
this = cmd_print(cmd);
len += strlen(this) + 6;
buf = xrealloc(buf, len);
strlcat(buf, this, len);
next = TAILQ_NEXT(cmd, qentry);
if (next != NULL) {
if (cmd->group != next->group) {
if (escaped)
strlcat(buf, " \\;\\; ", len);
else
strlcat(buf, " ;; ", len);
} else {
if (escaped)
strlcat(buf, " \\; ", len);
else
strlcat(buf, " ; ", len);
}
}
free(this);
}
return (buf);
}
/* Get first command in list. */
struct cmd *
cmd_list_first(struct cmd_list *cmdlist)
{
return (TAILQ_FIRST(cmdlist->list));
}
/* Get next command in list. */
struct cmd *
cmd_list_next(struct cmd *cmd)
{
return (TAILQ_NEXT(cmd, qentry));
}
/* Do all of the commands in this command list have this flag? */
int
cmd_list_all_have(struct cmd_list *cmdlist, int flag)
{
struct cmd *cmd;
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
if (~cmd->entry->flags & flag)
return (0);
}
return (1);
}
/* Do any of the commands in this command list have this flag? */
int
cmd_list_any_have(struct cmd_list *cmdlist, int flag)
{
struct cmd *cmd;
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
if (cmd->entry->flags & flag)
return (1);
}
return (0);
}
/* Adjust current mouse position for a pane. */
int
cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
@@ -517,8 +714,8 @@ cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
}
log_debug("%s: x=%u, y=%u%s", __func__, x, y, last ? " (last)" : "");
if (m->statusat == 0 && y > 0)
y--;
if (m->statusat == 0 && y >= m->statuslines)
y -= m->statuslines;
if (x < wp->xoff || x >= wp->xoff + wp->sx)
return (-1);
@@ -581,7 +778,7 @@ char *
cmd_template_replace(const char *template, const char *s, int idx)
{
char ch, *buf;
const char *ptr, *cp, quote[] = "\"\\$";
const char *ptr, *cp, quote[] = "\"\\$;~";
int replaced, quoted;
size_t len;
@@ -612,10 +809,6 @@ cmd_template_replace(const char *template, const char *s, int idx)
for (cp = s; *cp != '\0'; cp++) {
if (quoted && strchr(quote, *cp) != NULL)
buf[len++] = '\\';
if (quoted && *cp == ';') {
buf[len++] = '\\';
buf[len++] = '\\';
}
buf[len++] = *cp;
}
buf[len] = '\0';

701
colour.c
View File

@@ -22,6 +22,7 @@
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "tmux.h"
@@ -111,6 +112,9 @@ colour_tostring(int c)
static char s[32];
u_char r, g, b;
if (c == -1)
return ("invalid");
if (c & COLOUR_FLAG_RGB) {
colour_split_rgb(c, &r, &g, &b);
xsnprintf(s, sizeof s, "#%02x%02x%02x", r, g, b);
@@ -189,6 +193,12 @@ colour_fromstring(const char *s)
return (-1);
return (n | COLOUR_FLAG_256);
}
if (strncasecmp(s, "color", (sizeof "color") - 1) == 0) {
n = strtonum(s + (sizeof "color") - 1, 0, 255, &errstr);
if (errstr != NULL)
return (-1);
return (n | COLOUR_FLAG_256);
}
if (strcasecmp(s, "default") == 0)
return (8);
@@ -227,14 +237,88 @@ colour_fromstring(const char *s)
return (96);
if (strcasecmp(s, "brightwhite") == 0 || strcmp(s, "97") == 0)
return (97);
return (-1);
return (colour_byname(s));
}
/* Convert 256 colour palette to 16. */
u_char
colour_256to16(u_char c)
/* Convert 256 colour to RGB colour. */
int
colour_256toRGB(int c)
{
static const u_char table[256] = {
static const int table[256] = {
0x000000, 0x800000, 0x008000, 0x808000,
0x000080, 0x800080, 0x008080, 0xc0c0c0,
0x808080, 0xff0000, 0x00ff00, 0xffff00,
0x0000ff, 0xff00ff, 0x00ffff, 0xffffff,
0x000000, 0x00005f, 0x000087, 0x0000af,
0x0000d7, 0x0000ff, 0x005f00, 0x005f5f,
0x005f87, 0x005faf, 0x005fd7, 0x005fff,
0x008700, 0x00875f, 0x008787, 0x0087af,
0x0087d7, 0x0087ff, 0x00af00, 0x00af5f,
0x00af87, 0x00afaf, 0x00afd7, 0x00afff,
0x00d700, 0x00d75f, 0x00d787, 0x00d7af,
0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f,
0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff,
0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af,
0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f,
0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff,
0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af,
0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f,
0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff,
0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af,
0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f,
0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff,
0x870000, 0x87005f, 0x870087, 0x8700af,
0x8700d7, 0x8700ff, 0x875f00, 0x875f5f,
0x875f87, 0x875faf, 0x875fd7, 0x875fff,
0x878700, 0x87875f, 0x878787, 0x8787af,
0x8787d7, 0x8787ff, 0x87af00, 0x87af5f,
0x87af87, 0x87afaf, 0x87afd7, 0x87afff,
0x87d700, 0x87d75f, 0x87d787, 0x87d7af,
0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f,
0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff,
0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af,
0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f,
0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff,
0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af,
0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f,
0xafaf87, 0xafafaf, 0xafafd7, 0xafafff,
0xafd700, 0xafd75f, 0xafd787, 0xafd7af,
0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f,
0xafff87, 0xafffaf, 0xafffd7, 0xafffff,
0xd70000, 0xd7005f, 0xd70087, 0xd700af,
0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f,
0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff,
0xd78700, 0xd7875f, 0xd78787, 0xd787af,
0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f,
0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff,
0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af,
0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f,
0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff,
0xff0000, 0xff005f, 0xff0087, 0xff00af,
0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f,
0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff,
0xff8700, 0xff875f, 0xff8787, 0xff87af,
0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f,
0xffaf87, 0xffafaf, 0xffafd7, 0xffafff,
0xffd700, 0xffd75f, 0xffd787, 0xffd7af,
0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f,
0xffff87, 0xffffaf, 0xffffd7, 0xffffff,
0x080808, 0x121212, 0x1c1c1c, 0x262626,
0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e,
0x585858, 0x626262, 0x6c6c6c, 0x767676,
0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e,
0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6,
0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee
};
return (table[c & 0xff] | COLOUR_FLAG_RGB);
}
/* Convert 256 colour to 16 colour. */
int
colour_256to16(int c)
{
static const char table[256] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 4, 4, 4, 12, 12, 2, 6, 4, 4, 12, 12, 2, 2, 6, 4,
12, 12, 2, 2, 2, 6, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10,
@@ -253,5 +337,610 @@ colour_256to16(u_char c)
8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15
};
return (table[c]);
return (table[c & 0xff]);
}
/* Get colour by X11 colour name. */
int
colour_byname(const char *name)
{
static const struct {
const char *name;
int c;
} colours[] = {
{ "AliceBlue", 0xf0f8ff },
{ "AntiqueWhite", 0xfaebd7 },
{ "AntiqueWhite1", 0xffefdb },
{ "AntiqueWhite2", 0xeedfcc },
{ "AntiqueWhite3", 0xcdc0b0 },
{ "AntiqueWhite4", 0x8b8378 },
{ "BlanchedAlmond", 0xffebcd },
{ "BlueViolet", 0x8a2be2 },
{ "CadetBlue", 0x5f9ea0 },
{ "CadetBlue1", 0x98f5ff },
{ "CadetBlue2", 0x8ee5ee },
{ "CadetBlue3", 0x7ac5cd },
{ "CadetBlue4", 0x53868b },
{ "CornflowerBlue", 0x6495ed },
{ "DarkBlue", 0x00008b },
{ "DarkCyan", 0x008b8b },
{ "DarkGoldenrod", 0xb8860b },
{ "DarkGoldenrod1", 0xffb90f },
{ "DarkGoldenrod2", 0xeead0e },
{ "DarkGoldenrod3", 0xcd950c },
{ "DarkGoldenrod4", 0x8b6508 },
{ "DarkGray", 0xa9a9a9 },
{ "DarkGreen", 0x006400 },
{ "DarkGrey", 0xa9a9a9 },
{ "DarkKhaki", 0xbdb76b },
{ "DarkMagenta", 0x8b008b },
{ "DarkOliveGreen", 0x556b2f },
{ "DarkOliveGreen1", 0xcaff70 },
{ "DarkOliveGreen2", 0xbcee68 },
{ "DarkOliveGreen3", 0xa2cd5a },
{ "DarkOliveGreen4", 0x6e8b3d },
{ "DarkOrange", 0xff8c00 },
{ "DarkOrange1", 0xff7f00 },
{ "DarkOrange2", 0xee7600 },
{ "DarkOrange3", 0xcd6600 },
{ "DarkOrange4", 0x8b4500 },
{ "DarkOrchid", 0x9932cc },
{ "DarkOrchid1", 0xbf3eff },
{ "DarkOrchid2", 0xb23aee },
{ "DarkOrchid3", 0x9a32cd },
{ "DarkOrchid4", 0x68228b },
{ "DarkRed", 0x8b0000 },
{ "DarkSalmon", 0xe9967a },
{ "DarkSeaGreen", 0x8fbc8f },
{ "DarkSeaGreen1", 0xc1ffc1 },
{ "DarkSeaGreen2", 0xb4eeb4 },
{ "DarkSeaGreen3", 0x9bcd9b },
{ "DarkSeaGreen4", 0x698b69 },
{ "DarkSlateBlue", 0x483d8b },
{ "DarkSlateGray", 0x2f4f4f },
{ "DarkSlateGray1", 0x97ffff },
{ "DarkSlateGray2", 0x8deeee },
{ "DarkSlateGray3", 0x79cdcd },
{ "DarkSlateGray4", 0x528b8b },
{ "DarkSlateGrey", 0x2f4f4f },
{ "DarkTurquoise", 0x00ced1 },
{ "DarkViolet", 0x9400d3 },
{ "DeepPink", 0xff1493 },
{ "DeepPink1", 0xff1493 },
{ "DeepPink2", 0xee1289 },
{ "DeepPink3", 0xcd1076 },
{ "DeepPink4", 0x8b0a50 },
{ "DeepSkyBlue", 0x00bfff },
{ "DeepSkyBlue1", 0x00bfff },
{ "DeepSkyBlue2", 0x00b2ee },
{ "DeepSkyBlue3", 0x009acd },
{ "DeepSkyBlue4", 0x00688b },
{ "DimGray", 0x696969 },
{ "DimGrey", 0x696969 },
{ "DodgerBlue", 0x1e90ff },
{ "DodgerBlue1", 0x1e90ff },
{ "DodgerBlue2", 0x1c86ee },
{ "DodgerBlue3", 0x1874cd },
{ "DodgerBlue4", 0x104e8b },
{ "FloralWhite", 0xfffaf0 },
{ "ForestGreen", 0x228b22 },
{ "GhostWhite", 0xf8f8ff },
{ "GreenYellow", 0xadff2f },
{ "HotPink", 0xff69b4 },
{ "HotPink1", 0xff6eb4 },
{ "HotPink2", 0xee6aa7 },
{ "HotPink3", 0xcd6090 },
{ "HotPink4", 0x8b3a62 },
{ "IndianRed", 0xcd5c5c },
{ "IndianRed1", 0xff6a6a },
{ "IndianRed2", 0xee6363 },
{ "IndianRed3", 0xcd5555 },
{ "IndianRed4", 0x8b3a3a },
{ "LavenderBlush", 0xfff0f5 },
{ "LavenderBlush1", 0xfff0f5 },
{ "LavenderBlush2", 0xeee0e5 },
{ "LavenderBlush3", 0xcdc1c5 },
{ "LavenderBlush4", 0x8b8386 },
{ "LawnGreen", 0x7cfc00 },
{ "LemonChiffon", 0xfffacd },
{ "LemonChiffon1", 0xfffacd },
{ "LemonChiffon2", 0xeee9bf },
{ "LemonChiffon3", 0xcdc9a5 },
{ "LemonChiffon4", 0x8b8970 },
{ "LightBlue", 0xadd8e6 },
{ "LightBlue1", 0xbfefff },
{ "LightBlue2", 0xb2dfee },
{ "LightBlue3", 0x9ac0cd },
{ "LightBlue4", 0x68838b },
{ "LightCoral", 0xf08080 },
{ "LightCyan", 0xe0ffff },
{ "LightCyan1", 0xe0ffff },
{ "LightCyan2", 0xd1eeee },
{ "LightCyan3", 0xb4cdcd },
{ "LightCyan4", 0x7a8b8b },
{ "LightGoldenrod", 0xeedd82 },
{ "LightGoldenrod1", 0xffec8b },
{ "LightGoldenrod2", 0xeedc82 },
{ "LightGoldenrod3", 0xcdbe70 },
{ "LightGoldenrod4", 0x8b814c },
{ "LightGoldenrodYellow", 0xfafad2 },
{ "LightGray", 0xd3d3d3 },
{ "LightGreen", 0x90ee90 },
{ "LightGrey", 0xd3d3d3 },
{ "LightPink", 0xffb6c1 },
{ "LightPink1", 0xffaeb9 },
{ "LightPink2", 0xeea2ad },
{ "LightPink3", 0xcd8c95 },
{ "LightPink4", 0x8b5f65 },
{ "LightSalmon", 0xffa07a },
{ "LightSalmon1", 0xffa07a },
{ "LightSalmon2", 0xee9572 },
{ "LightSalmon3", 0xcd8162 },
{ "LightSalmon4", 0x8b5742 },
{ "LightSeaGreen", 0x20b2aa },
{ "LightSkyBlue", 0x87cefa },
{ "LightSkyBlue1", 0xb0e2ff },
{ "LightSkyBlue2", 0xa4d3ee },
{ "LightSkyBlue3", 0x8db6cd },
{ "LightSkyBlue4", 0x607b8b },
{ "LightSlateBlue", 0x8470ff },
{ "LightSlateGray", 0x778899 },
{ "LightSlateGrey", 0x778899 },
{ "LightSteelBlue", 0xb0c4de },
{ "LightSteelBlue1", 0xcae1ff },
{ "LightSteelBlue2", 0xbcd2ee },
{ "LightSteelBlue3", 0xa2b5cd },
{ "LightSteelBlue4", 0x6e7b8b },
{ "LightYellow", 0xffffe0 },
{ "LightYellow1", 0xffffe0 },
{ "LightYellow2", 0xeeeed1 },
{ "LightYellow3", 0xcdcdb4 },
{ "LightYellow4", 0x8b8b7a },
{ "LimeGreen", 0x32cd32 },
{ "MediumAquamarine", 0x66cdaa },
{ "MediumBlue", 0x0000cd },
{ "MediumOrchid", 0xba55d3 },
{ "MediumOrchid1", 0xe066ff },
{ "MediumOrchid2", 0xd15fee },
{ "MediumOrchid3", 0xb452cd },
{ "MediumOrchid4", 0x7a378b },
{ "MediumPurple", 0x9370db },
{ "MediumPurple1", 0xab82ff },
{ "MediumPurple2", 0x9f79ee },
{ "MediumPurple3", 0x8968cd },
{ "MediumPurple4", 0x5d478b },
{ "MediumSeaGreen", 0x3cb371 },
{ "MediumSlateBlue", 0x7b68ee },
{ "MediumSpringGreen", 0x00fa9a },
{ "MediumTurquoise", 0x48d1cc },
{ "MediumVioletRed", 0xc71585 },
{ "MidnightBlue", 0x191970 },
{ "MintCream", 0xf5fffa },
{ "MistyRose", 0xffe4e1 },
{ "MistyRose1", 0xffe4e1 },
{ "MistyRose2", 0xeed5d2 },
{ "MistyRose3", 0xcdb7b5 },
{ "MistyRose4", 0x8b7d7b },
{ "NavajoWhite", 0xffdead },
{ "NavajoWhite1", 0xffdead },
{ "NavajoWhite2", 0xeecfa1 },
{ "NavajoWhite3", 0xcdb38b },
{ "NavajoWhite4", 0x8b795e },
{ "NavyBlue", 0x000080 },
{ "OldLace", 0xfdf5e6 },
{ "OliveDrab", 0x6b8e23 },
{ "OliveDrab1", 0xc0ff3e },
{ "OliveDrab2", 0xb3ee3a },
{ "OliveDrab3", 0x9acd32 },
{ "OliveDrab4", 0x698b22 },
{ "OrangeRed", 0xff4500 },
{ "OrangeRed1", 0xff4500 },
{ "OrangeRed2", 0xee4000 },
{ "OrangeRed3", 0xcd3700 },
{ "OrangeRed4", 0x8b2500 },
{ "PaleGoldenrod", 0xeee8aa },
{ "PaleGreen", 0x98fb98 },
{ "PaleGreen1", 0x9aff9a },
{ "PaleGreen2", 0x90ee90 },
{ "PaleGreen3", 0x7ccd7c },
{ "PaleGreen4", 0x548b54 },
{ "PaleTurquoise", 0xafeeee },
{ "PaleTurquoise1", 0xbbffff },
{ "PaleTurquoise2", 0xaeeeee },
{ "PaleTurquoise3", 0x96cdcd },
{ "PaleTurquoise4", 0x668b8b },
{ "PaleVioletRed", 0xdb7093 },
{ "PaleVioletRed1", 0xff82ab },
{ "PaleVioletRed2", 0xee799f },
{ "PaleVioletRed3", 0xcd6889 },
{ "PaleVioletRed4", 0x8b475d },
{ "PapayaWhip", 0xffefd5 },
{ "PeachPuff", 0xffdab9 },
{ "PeachPuff1", 0xffdab9 },
{ "PeachPuff2", 0xeecbad },
{ "PeachPuff3", 0xcdaf95 },
{ "PeachPuff4", 0x8b7765 },
{ "PowderBlue", 0xb0e0e6 },
{ "RebeccaPurple", 0x663399 },
{ "RosyBrown", 0xbc8f8f },
{ "RosyBrown1", 0xffc1c1 },
{ "RosyBrown2", 0xeeb4b4 },
{ "RosyBrown3", 0xcd9b9b },
{ "RosyBrown4", 0x8b6969 },
{ "RoyalBlue", 0x4169e1 },
{ "RoyalBlue1", 0x4876ff },
{ "RoyalBlue2", 0x436eee },
{ "RoyalBlue3", 0x3a5fcd },
{ "RoyalBlue4", 0x27408b },
{ "SaddleBrown", 0x8b4513 },
{ "SandyBrown", 0xf4a460 },
{ "SeaGreen", 0x2e8b57 },
{ "SeaGreen1", 0x54ff9f },
{ "SeaGreen2", 0x4eee94 },
{ "SeaGreen3", 0x43cd80 },
{ "SeaGreen4", 0x2e8b57 },
{ "SkyBlue", 0x87ceeb },
{ "SkyBlue1", 0x87ceff },
{ "SkyBlue2", 0x7ec0ee },
{ "SkyBlue3", 0x6ca6cd },
{ "SkyBlue4", 0x4a708b },
{ "SlateBlue", 0x6a5acd },
{ "SlateBlue1", 0x836fff },
{ "SlateBlue2", 0x7a67ee },
{ "SlateBlue3", 0x6959cd },
{ "SlateBlue4", 0x473c8b },
{ "SlateGray", 0x708090 },
{ "SlateGray1", 0xc6e2ff },
{ "SlateGray2", 0xb9d3ee },
{ "SlateGray3", 0x9fb6cd },
{ "SlateGray4", 0x6c7b8b },
{ "SlateGrey", 0x708090 },
{ "SpringGreen", 0x00ff7f },
{ "SpringGreen1", 0x00ff7f },
{ "SpringGreen2", 0x00ee76 },
{ "SpringGreen3", 0x00cd66 },
{ "SpringGreen4", 0x008b45 },
{ "SteelBlue", 0x4682b4 },
{ "SteelBlue1", 0x63b8ff },
{ "SteelBlue2", 0x5cacee },
{ "SteelBlue3", 0x4f94cd },
{ "SteelBlue4", 0x36648b },
{ "VioletRed", 0xd02090 },
{ "VioletRed1", 0xff3e96 },
{ "VioletRed2", 0xee3a8c },
{ "VioletRed3", 0xcd3278 },
{ "VioletRed4", 0x8b2252 },
{ "WebGray", 0x808080 },
{ "WebGreen", 0x008000 },
{ "WebGrey", 0x808080 },
{ "WebMaroon", 0x800000 },
{ "WebPurple", 0x800080 },
{ "WhiteSmoke", 0xf5f5f5 },
{ "X11Gray", 0xbebebe },
{ "X11Green", 0x00ff00 },
{ "X11Grey", 0xbebebe },
{ "X11Maroon", 0xb03060 },
{ "X11Purple", 0xa020f0 },
{ "YellowGreen", 0x9acd32 },
{ "alice blue", 0xf0f8ff },
{ "antique white", 0xfaebd7 },
{ "aqua", 0x00ffff },
{ "aquamarine", 0x7fffd4 },
{ "aquamarine1", 0x7fffd4 },
{ "aquamarine2", 0x76eec6 },
{ "aquamarine3", 0x66cdaa },
{ "aquamarine4", 0x458b74 },
{ "azure", 0xf0ffff },
{ "azure1", 0xf0ffff },
{ "azure2", 0xe0eeee },
{ "azure3", 0xc1cdcd },
{ "azure4", 0x838b8b },
{ "beige", 0xf5f5dc },
{ "bisque", 0xffe4c4 },
{ "bisque1", 0xffe4c4 },
{ "bisque2", 0xeed5b7 },
{ "bisque3", 0xcdb79e },
{ "bisque4", 0x8b7d6b },
{ "black", 0x000000 },
{ "blanched almond", 0xffebcd },
{ "blue violet", 0x8a2be2 },
{ "blue", 0x0000ff },
{ "blue1", 0x0000ff },
{ "blue2", 0x0000ee },
{ "blue3", 0x0000cd },
{ "blue4", 0x00008b },
{ "brown", 0xa52a2a },
{ "brown1", 0xff4040 },
{ "brown2", 0xee3b3b },
{ "brown3", 0xcd3333 },
{ "brown4", 0x8b2323 },
{ "burlywood", 0xdeb887 },
{ "burlywood1", 0xffd39b },
{ "burlywood2", 0xeec591 },
{ "burlywood3", 0xcdaa7d },
{ "burlywood4", 0x8b7355 },
{ "cadet blue", 0x5f9ea0 },
{ "chartreuse", 0x7fff00 },
{ "chartreuse1", 0x7fff00 },
{ "chartreuse2", 0x76ee00 },
{ "chartreuse3", 0x66cd00 },
{ "chartreuse4", 0x458b00 },
{ "chocolate", 0xd2691e },
{ "chocolate1", 0xff7f24 },
{ "chocolate2", 0xee7621 },
{ "chocolate3", 0xcd661d },
{ "chocolate4", 0x8b4513 },
{ "coral", 0xff7f50 },
{ "coral1", 0xff7256 },
{ "coral2", 0xee6a50 },
{ "coral3", 0xcd5b45 },
{ "coral4", 0x8b3e2f },
{ "cornflower blue", 0x6495ed },
{ "cornsilk", 0xfff8dc },
{ "cornsilk1", 0xfff8dc },
{ "cornsilk2", 0xeee8cd },
{ "cornsilk3", 0xcdc8b1 },
{ "cornsilk4", 0x8b8878 },
{ "crimson", 0xdc143c },
{ "cyan", 0x00ffff },
{ "cyan1", 0x00ffff },
{ "cyan2", 0x00eeee },
{ "cyan3", 0x00cdcd },
{ "cyan4", 0x008b8b },
{ "dark blue", 0x00008b },
{ "dark cyan", 0x008b8b },
{ "dark goldenrod", 0xb8860b },
{ "dark gray", 0xa9a9a9 },
{ "dark green", 0x006400 },
{ "dark grey", 0xa9a9a9 },
{ "dark khaki", 0xbdb76b },
{ "dark magenta", 0x8b008b },
{ "dark olive green", 0x556b2f },
{ "dark orange", 0xff8c00 },
{ "dark orchid", 0x9932cc },
{ "dark red", 0x8b0000 },
{ "dark salmon", 0xe9967a },
{ "dark sea green", 0x8fbc8f },
{ "dark slate blue", 0x483d8b },
{ "dark slate gray", 0x2f4f4f },
{ "dark slate grey", 0x2f4f4f },
{ "dark turquoise", 0x00ced1 },
{ "dark violet", 0x9400d3 },
{ "deep pink", 0xff1493 },
{ "deep sky blue", 0x00bfff },
{ "dim gray", 0x696969 },
{ "dim grey", 0x696969 },
{ "dodger blue", 0x1e90ff },
{ "firebrick", 0xb22222 },
{ "firebrick1", 0xff3030 },
{ "firebrick2", 0xee2c2c },
{ "firebrick3", 0xcd2626 },
{ "firebrick4", 0x8b1a1a },
{ "floral white", 0xfffaf0 },
{ "forest green", 0x228b22 },
{ "fuchsia", 0xff00ff },
{ "gainsboro", 0xdcdcdc },
{ "ghost white", 0xf8f8ff },
{ "gold", 0xffd700 },
{ "gold1", 0xffd700 },
{ "gold2", 0xeec900 },
{ "gold3", 0xcdad00 },
{ "gold4", 0x8b7500 },
{ "goldenrod", 0xdaa520 },
{ "goldenrod1", 0xffc125 },
{ "goldenrod2", 0xeeb422 },
{ "goldenrod3", 0xcd9b1d },
{ "goldenrod4", 0x8b6914 },
{ "green yellow", 0xadff2f },
{ "green", 0x00ff00 },
{ "green1", 0x00ff00 },
{ "green2", 0x00ee00 },
{ "green3", 0x00cd00 },
{ "green4", 0x008b00 },
{ "honeydew", 0xf0fff0 },
{ "honeydew1", 0xf0fff0 },
{ "honeydew2", 0xe0eee0 },
{ "honeydew3", 0xc1cdc1 },
{ "honeydew4", 0x838b83 },
{ "hot pink", 0xff69b4 },
{ "indian red", 0xcd5c5c },
{ "indigo", 0x4b0082 },
{ "ivory", 0xfffff0 },
{ "ivory1", 0xfffff0 },
{ "ivory2", 0xeeeee0 },
{ "ivory3", 0xcdcdc1 },
{ "ivory4", 0x8b8b83 },
{ "khaki", 0xf0e68c },
{ "khaki1", 0xfff68f },
{ "khaki2", 0xeee685 },
{ "khaki3", 0xcdc673 },
{ "khaki4", 0x8b864e },
{ "lavender blush", 0xfff0f5 },
{ "lavender", 0xe6e6fa },
{ "lawn green", 0x7cfc00 },
{ "lemon chiffon", 0xfffacd },
{ "light blue", 0xadd8e6 },
{ "light coral", 0xf08080 },
{ "light cyan", 0xe0ffff },
{ "light goldenrod yellow", 0xfafad2 },
{ "light goldenrod", 0xeedd82 },
{ "light gray", 0xd3d3d3 },
{ "light green", 0x90ee90 },
{ "light grey", 0xd3d3d3 },
{ "light pink", 0xffb6c1 },
{ "light salmon", 0xffa07a },
{ "light sea green", 0x20b2aa },
{ "light sky blue", 0x87cefa },
{ "light slate blue", 0x8470ff },
{ "light slate gray", 0x778899 },
{ "light slate grey", 0x778899 },
{ "light steel blue", 0xb0c4de },
{ "light yellow", 0xffffe0 },
{ "lime green", 0x32cd32 },
{ "lime", 0x00ff00 },
{ "linen", 0xfaf0e6 },
{ "magenta", 0xff00ff },
{ "magenta1", 0xff00ff },
{ "magenta2", 0xee00ee },
{ "magenta3", 0xcd00cd },
{ "magenta4", 0x8b008b },
{ "maroon", 0xb03060 },
{ "maroon1", 0xff34b3 },
{ "maroon2", 0xee30a7 },
{ "maroon3", 0xcd2990 },
{ "maroon4", 0x8b1c62 },
{ "medium aquamarine", 0x66cdaa },
{ "medium blue", 0x0000cd },
{ "medium orchid", 0xba55d3 },
{ "medium purple", 0x9370db },
{ "medium sea green", 0x3cb371 },
{ "medium slate blue", 0x7b68ee },
{ "medium spring green", 0x00fa9a },
{ "medium turquoise", 0x48d1cc },
{ "medium violet red", 0xc71585 },
{ "midnight blue", 0x191970 },
{ "mint cream", 0xf5fffa },
{ "misty rose", 0xffe4e1 },
{ "moccasin", 0xffe4b5 },
{ "navajo white", 0xffdead },
{ "navy blue", 0x000080 },
{ "navy", 0x000080 },
{ "old lace", 0xfdf5e6 },
{ "olive drab", 0x6b8e23 },
{ "olive", 0x808000 },
{ "orange red", 0xff4500 },
{ "orange", 0xffa500 },
{ "orange1", 0xffa500 },
{ "orange2", 0xee9a00 },
{ "orange3", 0xcd8500 },
{ "orange4", 0x8b5a00 },
{ "orchid", 0xda70d6 },
{ "orchid1", 0xff83fa },
{ "orchid2", 0xee7ae9 },
{ "orchid3", 0xcd69c9 },
{ "orchid4", 0x8b4789 },
{ "pale goldenrod", 0xeee8aa },
{ "pale green", 0x98fb98 },
{ "pale turquoise", 0xafeeee },
{ "pale violet red", 0xdb7093 },
{ "papaya whip", 0xffefd5 },
{ "peach puff", 0xffdab9 },
{ "peru", 0xcd853f },
{ "pink", 0xffc0cb },
{ "pink1", 0xffb5c5 },
{ "pink2", 0xeea9b8 },
{ "pink3", 0xcd919e },
{ "pink4", 0x8b636c },
{ "plum", 0xdda0dd },
{ "plum1", 0xffbbff },
{ "plum2", 0xeeaeee },
{ "plum3", 0xcd96cd },
{ "plum4", 0x8b668b },
{ "powder blue", 0xb0e0e6 },
{ "purple", 0xa020f0 },
{ "purple1", 0x9b30ff },
{ "purple2", 0x912cee },
{ "purple3", 0x7d26cd },
{ "purple4", 0x551a8b },
{ "rebecca purple", 0x663399 },
{ "red", 0xff0000 },
{ "red1", 0xff0000 },
{ "red2", 0xee0000 },
{ "red3", 0xcd0000 },
{ "red4", 0x8b0000 },
{ "rosy brown", 0xbc8f8f },
{ "royal blue", 0x4169e1 },
{ "saddle brown", 0x8b4513 },
{ "salmon", 0xfa8072 },
{ "salmon1", 0xff8c69 },
{ "salmon2", 0xee8262 },
{ "salmon3", 0xcd7054 },
{ "salmon4", 0x8b4c39 },
{ "sandy brown", 0xf4a460 },
{ "sea green", 0x2e8b57 },
{ "seashell", 0xfff5ee },
{ "seashell1", 0xfff5ee },
{ "seashell2", 0xeee5de },
{ "seashell3", 0xcdc5bf },
{ "seashell4", 0x8b8682 },
{ "sienna", 0xa0522d },
{ "sienna1", 0xff8247 },
{ "sienna2", 0xee7942 },
{ "sienna3", 0xcd6839 },
{ "sienna4", 0x8b4726 },
{ "silver", 0xc0c0c0 },
{ "sky blue", 0x87ceeb },
{ "slate blue", 0x6a5acd },
{ "slate gray", 0x708090 },
{ "slate grey", 0x708090 },
{ "snow", 0xfffafa },
{ "snow1", 0xfffafa },
{ "snow2", 0xeee9e9 },
{ "snow3", 0xcdc9c9 },
{ "snow4", 0x8b8989 },
{ "spring green", 0x00ff7f },
{ "steel blue", 0x4682b4 },
{ "tan", 0xd2b48c },
{ "tan1", 0xffa54f },
{ "tan2", 0xee9a49 },
{ "tan3", 0xcd853f },
{ "tan4", 0x8b5a2b },
{ "teal", 0x008080 },
{ "thistle", 0xd8bfd8 },
{ "thistle1", 0xffe1ff },
{ "thistle2", 0xeed2ee },
{ "thistle3", 0xcdb5cd },
{ "thistle4", 0x8b7b8b },
{ "tomato", 0xff6347 },
{ "tomato1", 0xff6347 },
{ "tomato2", 0xee5c42 },
{ "tomato3", 0xcd4f39 },
{ "tomato4", 0x8b3626 },
{ "turquoise", 0x40e0d0 },
{ "turquoise1", 0x00f5ff },
{ "turquoise2", 0x00e5ee },
{ "turquoise3", 0x00c5cd },
{ "turquoise4", 0x00868b },
{ "violet red", 0xd02090 },
{ "violet", 0xee82ee },
{ "web gray", 0x808080 },
{ "web green", 0x008000 },
{ "web grey", 0x808080 },
{ "web maroon", 0x800000 },
{ "web purple", 0x800080 },
{ "wheat", 0xf5deb3 },
{ "wheat1", 0xffe7ba },
{ "wheat2", 0xeed8ae },
{ "wheat3", 0xcdba96 },
{ "wheat4", 0x8b7e66 },
{ "white smoke", 0xf5f5f5 },
{ "white", 0xffffff },
{ "x11 gray", 0xbebebe },
{ "x11 green", 0x00ff00 },
{ "x11 grey", 0xbebebe },
{ "x11 maroon", 0xb03060 },
{ "x11 purple", 0xa020f0 },
{ "yellow green", 0x9acd32 },
{ "yellow", 0xffff00 },
{ "yellow1", 0xffff00 },
{ "yellow2", 0xeeee00 },
{ "yellow3", 0xcdcd00 },
{ "yellow4", 0x8b8b00 }
};
u_int i;
int c;
if (strncmp(name, "grey", 4) == 0 || strncmp(name, "gray", 4) == 0) {
if (!isdigit((u_char)name[4]))
return (0xbebebe|COLOUR_FLAG_RGB);
c = round(2.55 * atoi(name + 4));
if (c < 0 || c > 255)
return (-1);
return (colour_join_rgb(c, c, c));
}
for (i = 0; i < nitems(colours); i++) {
if (strcasecmp(colours[i].name, name) == 0)
return (colours[i].c|COLOUR_FLAG_RGB);
}
return (-1);
}

View File

@@ -21,15 +21,41 @@
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <fnmatch.h>
#include <limits.h>
#include <stdio.h>
#include <termios.h>
#include <wchar.h>
#ifdef HAVE_EVENT2_EVENT_H
#include <event2/event.h>
#include <event2/event_compat.h>
#include <event2/event_struct.h>
#include <event2/buffer.h>
#include <event2/buffer_compat.h>
#include <event2/bufferevent.h>
#include <event2/bufferevent_struct.h>
#include <event2/bufferevent_compat.h>
#else
#include <event.h>
#endif
#ifdef HAVE_MALLOC_TRIM
#include <malloc.h>
#endif
#ifdef HAVE_UTF8PROC
#include <utf8proc.h>
#endif
#ifndef __GNUC__
#define __attribute__(a)
#endif
#ifdef BROKEN___DEAD
#undef __dead
#endif
#ifndef __unused
#define __unused __attribute__ ((__unused__))
#endif
@@ -39,6 +65,9 @@
#ifndef __packed
#define __packed __attribute__ ((__packed__))
#endif
#ifndef __weak
#define __weak __attribute__ ((__weak__))
#endif
#ifndef ECHOPRT
#define ECHOPRT 0
@@ -61,19 +90,46 @@ void warn(const char *, ...);
void warnx(const char *, ...);
#endif
#ifndef HAVE_PATHS_H
#define _PATH_BSHELL "/bin/sh"
#define _PATH_TMP "/tmp/"
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#ifndef _PATH_BSHELL
#define _PATH_BSHELL "/bin/sh"
#endif
#ifndef _PATH_TMP
#define _PATH_TMP "/tmp/"
#endif
#ifndef _PATH_DEVNULL
#define _PATH_DEVNULL "/dev/null"
#endif
#ifndef _PATH_TTY
#define _PATH_TTY "/dev/tty"
#endif
#ifndef _PATH_DEV
#define _PATH_DEV "/dev/"
#endif
#ifndef _PATH_DEFPATH
#define _PATH_DEFPATH "/usr/bin:/bin"
#endif
#ifndef _PATH_VI
#define _PATH_VI "/usr/bin/vi"
#endif
#ifndef __OpenBSD__
#define pledge(s, p) (0)
#endif
#ifndef IMAXBEL
#define IMAXBEL 0
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#else
@@ -98,10 +154,6 @@ void warnx(const char *, ...);
#include "compat/bitstring.h"
#endif
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#ifdef HAVE_LIBUTIL_H
#include <libutil.h>
#endif
@@ -154,6 +206,14 @@ void warnx(const char *, ...);
#define O_DIRECTORY 0
#endif
#ifndef FNM_CASEFOLD
#ifdef FNM_IGNORECASE
#define FNM_CASEFOLD FNM_IGNORECASE
#else
#define FNM_CASEFOLD 0
#endif
#endif
#ifndef INFTIM
#define INFTIM -1
#endif
@@ -205,6 +265,13 @@ void warnx(const char *, ...);
#define HOST_NAME_MAX 255
#endif
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC CLOCK_REALTIME
#endif
#ifndef HAVE_FLOCK
#define LOCK_SH 0
#define LOCK_EX 0
@@ -282,6 +349,11 @@ const char *getprogname(void);
void setproctitle(const char *, ...);
#endif
#ifndef HAVE_CLOCK_GETTIME
/* clock_gettime.c */
int clock_gettime(int, struct timespec *);
#endif
#ifndef HAVE_B64_NTOP
/* base64.c */
#undef b64_ntop
@@ -313,6 +385,11 @@ int vasprintf(char **, const char *, va_list);
char *fgetln(FILE *, size_t *);
#endif
#ifndef HAVE_GETLINE
/* getline.c */
ssize_t getline(char **, size_t *, FILE *);
#endif
#ifndef HAVE_SETENV
/* setenv.c */
int setenv(const char *, const char *, int);
@@ -346,7 +423,11 @@ int utf8proc_mbtowc(wchar_t *, const char *, size_t);
int utf8proc_wctomb(char *, wchar_t);
#endif
#ifndef HAVE_GETOPT
#ifdef NEED_FUZZING
/* tmux.c */
#define main __weak main
#endif
/* getopt.c */
extern int BSDopterr;
extern int BSDoptind;
@@ -360,6 +441,5 @@ int BSDgetopt(int, char *const *, const char *);
#define optopt BSDoptopt
#define optreset BSDoptreset
#define optarg BSDoptarg
#endif
#endif /* COMPAT_H */

View File

@@ -19,8 +19,10 @@
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "compat.h"
#include "xmalloc.h"
int
asprintf(char **ret, const char *fmt, ...)

37
compat/clock_gettime.c Normal file
View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2021 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 <sys/time.h>
#include "compat.h"
#ifndef TIMEVAL_TO_TIMESPEC
#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
(ts)->tv_sec = (tv)->tv_sec; \
(ts)->tv_nsec = (tv)->tv_usec * 1000; \
} while (0)
#endif
int
clock_gettime(int clock, struct timespec *ts)
{
struct timeval tv;
gettimeofday(&tv, NULL);
TIMEVAL_TO_TIMESPEC(&tv, ts);
return 0;
}

View File

@@ -44,6 +44,9 @@
# include <ndir.h>
# endif
#endif
#if defined(HAVE_LIBPROC_H)
# include <libproc.h>
#endif
#include "compat.h"
@@ -55,39 +58,15 @@
__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $";
#endif /* lint */
#ifndef HAVE_FCNTL_CLOSEM
/*
* Close all file descriptors greater than or equal to lowfd.
*/
#ifdef HAVE_FCNTL_CLOSEM
void
closefrom(int lowfd)
static void
closefrom_fallback(int lowfd)
{
(void) fcntl(lowfd, F_CLOSEM, 0);
}
#else
void
closefrom(int lowfd)
{
long fd, maxfd;
#if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID)
char fdpath[PATH_MAX], *endp;
struct dirent *dent;
DIR *dirp;
int len;
long fd, maxfd;
/* Check for a /proc/$$/fd directory. */
len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid());
if (len > 0 && (size_t)len <= sizeof(fdpath) && (dirp = opendir(fdpath))) {
while ((dent = readdir(dirp)) != NULL) {
fd = strtol(dent->d_name, &endp, 10);
if (dent->d_name != endp && *endp == '\0' &&
fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
(void) close((int) fd);
}
(void) closedir(dirp);
} else
#endif
{
/*
* Fall back on sysconf() or getdtablesize(). We avoid checking
* resource limits since it is possible to open a file descriptor
@@ -99,11 +78,78 @@ closefrom(int lowfd)
maxfd = getdtablesize();
#endif /* HAVE_SYSCONF */
if (maxfd < 0)
maxfd = OPEN_MAX;
maxfd = OPEN_MAX;
for (fd = lowfd; fd < maxfd; fd++)
(void) close((int) fd);
(void) close((int) fd);
}
#endif /* HAVE_FCNTL_CLOSEM */
#ifdef HAVE_FCNTL_CLOSEM
void
closefrom(int lowfd)
{
(void) fcntl(lowfd, F_CLOSEM, 0);
}
#elif defined(HAVE_LIBPROC_H) && defined(HAVE_PROC_PIDINFO)
void
closefrom(int lowfd)
{
int i, r, sz;
pid_t pid = getpid();
struct proc_fdinfo *fdinfo_buf = NULL;
sz = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
if (sz == 0)
return; /* no fds, really? */
else if (sz == -1)
goto fallback;
if ((fdinfo_buf = malloc(sz)) == NULL)
goto fallback;
r = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fdinfo_buf, sz);
if (r < 0 || r > sz)
goto fallback;
for (i = 0; i < r / (int)PROC_PIDLISTFD_SIZE; i++) {
if (fdinfo_buf[i].proc_fd >= lowfd)
close(fdinfo_buf[i].proc_fd);
}
free(fdinfo_buf);
return;
fallback:
free(fdinfo_buf);
closefrom_fallback(lowfd);
return;
}
#elif defined(HAVE_DIRFD) && defined(HAVE_PROC_PID)
void
closefrom(int lowfd)
{
long fd;
char fdpath[PATH_MAX], *endp;
struct dirent *dent;
DIR *dirp;
int len;
/* Check for a /proc/$$/fd directory. */
len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid());
if (len > 0 && (size_t)len < sizeof(fdpath) && (dirp = opendir(fdpath))) {
while ((dent = readdir(dirp)) != NULL) {
fd = strtol(dent->d_name, &endp, 10);
if (dent->d_name != endp && *endp == '\0' &&
fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
(void) close((int) fd);
}
(void) closedir(dirp);
return;
}
/* /proc/$$/fd strategy failed, fall back to brute force closure */
closefrom_fallback(lowfd);
}
#else
void
closefrom(int lowfd)
{
closefrom_fallback(lowfd);
}
#endif /* !HAVE_FCNTL_CLOSEM */
#endif /* HAVE_CLOSEFROM */

82
compat/forkpty-haiku.c Normal file
View File

@@ -0,0 +1,82 @@
/*
* 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 <sys/ioctl.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include "compat.h"
void fatal(const char *, ...);
void fatalx(const char *, ...);
pid_t
forkpty(int *master, char *name, struct termios *tio, struct winsize *ws)
{
int slave = -1;
char *path;
pid_t pid;
if ((*master = open("/dev/ptmx", O_RDWR|O_NOCTTY)) == -1)
return (-1);
if (grantpt(*master) != 0)
goto out;
if (unlockpt(*master) != 0)
goto out;
if ((path = ptsname(*master)) == NULL)
goto out;
if (name != NULL)
strlcpy(name, path, TTY_NAME_MAX);
if ((slave = open(path, O_RDWR|O_NOCTTY)) == -1)
goto out;
switch (pid = fork()) {
case -1:
goto out;
case 0:
close(*master);
setsid();
if (ioctl(slave, TIOCSCTTY, NULL) == -1)
fatal("ioctl failed");
if (tio != NULL && tcsetattr(slave, TCSAFLUSH, tio) == -1)
fatal("tcsetattr failed");
if (ioctl(slave, TIOCSWINSZ, ws) == -1)
fatal("ioctl failed");
dup2(slave, 0);
dup2(slave, 1);
dup2(slave, 2);
if (slave > 2)
close(slave);
return (0);
}
close(slave);
return (pid);
out:
if (*master != -1)
close(*master);
if (slave != -1)
close(slave);
return (-1);
}

29
compat/getdtablesize.c Normal file
View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2020 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 <unistd.h>
#include "compat.h"
#ifdef HAVE_SYSCONF
int
getdtablesize(void)
{
return (sysconf(_SC_OPEN_MAX));
}
#endif

93
compat/getline.c Normal file
View File

@@ -0,0 +1,93 @@
/* $NetBSD: getline.c,v 1.1.1.6 2015/01/02 20:34:27 christos Exp $ */
/* NetBSD: getline.c,v 1.2 2014/09/16 17:23:50 christos Exp */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/* NETBSD ORIGINAL: external/bsd/file/dist/src/getline.c */
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "tmux.h"
static ssize_t
getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp)
{
char *ptr, *eptr;
if (*buf == NULL || *bufsiz == 0) {
if ((*buf = malloc(BUFSIZ)) == NULL)
return -1;
*bufsiz = BUFSIZ;
}
for (ptr = *buf, eptr = *buf + *bufsiz;;) {
int c = fgetc(fp);
if (c == -1) {
if (feof(fp)) {
ssize_t diff = (ssize_t)(ptr - *buf);
if (diff != 0) {
*ptr = '\0';
return diff;
}
}
return -1;
}
*ptr++ = c;
if (c == delimiter) {
*ptr = '\0';
return ptr - *buf;
}
if (ptr + 2 >= eptr) {
char *nbuf;
size_t nbufsiz = *bufsiz * 2;
ssize_t d = ptr - *buf;
if ((nbuf = realloc(*buf, nbufsiz)) == NULL)
return -1;
*buf = nbuf;
*bufsiz = nbufsiz;
eptr = nbuf + nbufsiz;
ptr = nbuf + d;
}
}
}
ssize_t
getline(char **buf, size_t *bufsiz, FILE *fp)
{
return getdelim(buf, bufsiz, '\n', fp);
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: imsg-buffer.c,v 1.11 2017/12/14 09:27:44 kettenis Exp $ */
/* $OpenBSD: imsg-buffer.c,v 1.12 2019/01/20 02:50:03 bcook Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -70,7 +70,7 @@ ibuf_dynamic(size_t len, size_t max)
static int
ibuf_realloc(struct ibuf *buf, size_t len)
{
u_char *b;
unsigned char *b;
/* on static buffers max is eq size and so the following fails */
if (buf->wpos + len > buf->max) {

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: imsg.h,v 1.4 2017/03/24 09:34:12 nicm Exp $ */
/* $OpenBSD: imsg.h,v 1.5 2019/01/20 02:50:03 bcook Exp $ */
/*
* Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -21,13 +21,15 @@
#ifndef _IMSG_H_
#define _IMSG_H_
#include <stdint.h>
#define IBUF_READ_SIZE 65535
#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
#define MAX_IMSGSIZE 16384
struct ibuf {
TAILQ_ENTRY(ibuf) entry;
u_char *buf;
unsigned char *buf;
size_t size;
size_t max;
size_t wpos;
@@ -42,8 +44,8 @@ struct msgbuf {
};
struct ibuf_read {
u_char buf[IBUF_READ_SIZE];
u_char *rptr;
unsigned char buf[IBUF_READ_SIZE];
unsigned char *rptr;
size_t wpos;
};

View File

@@ -1,6 +1,6 @@
# configure.ac
AC_INIT([tmux], 3.0-rc3)
AC_INIT([tmux], 3.2a)
AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc)
@@ -21,6 +21,26 @@ SAVED_CFLAGS="$CFLAGS"
SAVED_CPPFLAGS="$CPPFLAGS"
SAVED_LDFLAGS="$LDFLAGS"
# Is this oss-fuzz build?
AC_ARG_ENABLE(
fuzzing,
AC_HELP_STRING(--enable-fuzzing, build fuzzers)
)
AC_ARG_VAR(
FUZZING_LIBS,
AC_HELP_STRING(libraries to link fuzzing targets with)
)
# Set up convenient fuzzing defaults before initializing compiler.
if test "x$enable_fuzzing" = xyes; then
AC_DEFINE(NEED_FUZZING)
test "x$CC" = x && CC=clang
test "x$FUZZING_LIBS" = x && \
FUZZING_LIBS="-fsanitize=fuzzer"
test "x$SAVED_CFLAGS" = x && \
AM_CFLAGS="-g -fsanitize=fuzzer-no-link,address"
fi
# Set up the compiler in two different ways and say yes we may want to install.
AC_PROG_CC
AM_PROG_CC_C_O
@@ -54,8 +74,11 @@ if test "x$enable_static" = xyes; then
LDFLAGS="$AM_LDFLAGS $SAVED_LDFLAGS"
fi
# Do we need fuzzers?
AM_CONDITIONAL(NEED_FUZZING, test "x$enable_fuzzing" = xyes)
# Is this gcc?
AM_CONDITIONAL(IS_GCC, test "x$GCC" = xyes)
AM_CONDITIONAL(IS_GCC, test "x$GCC" = xyes -a "x$enable_fuzzing" != xyes)
# Is this Sun CC?
AC_EGREP_CPP(
@@ -76,6 +99,7 @@ AC_CHECK_HEADERS([ \
dirent.h \
fcntl.h \
inttypes.h \
libproc.h \
libutil.h \
ndir.h \
paths.h \
@@ -87,6 +111,12 @@ AC_CHECK_HEADERS([ \
util.h \
])
# Look for sys_signame.
AC_SEARCH_LIBS(sys_signame, , AC_DEFINE(HAVE_SYS_SIGNAME))
# Look for fmod.
AC_CHECK_LIB(m, fmod)
# Look for library needed for flock.
AC_SEARCH_LIBS(flock, bsd)
@@ -95,22 +125,24 @@ AC_CHECK_FUNCS([ \
dirfd \
flock \
prctl \
sysconf \
proc_pidinfo \
sysconf
])
# Check for functions with a compatibility implementation.
AC_REPLACE_FUNCS([ \
asprintf \
cfmakeraw \
clock_gettime \
closefrom \
explicit_bzero \
fgetln \
freezero \
getdtablecount \
getdtablesize \
getline \
getprogname \
memmem \
recallocarray \
reallocarray \
setenv \
setproctitle \
strcasestr \
@@ -118,95 +150,156 @@ AC_REPLACE_FUNCS([ \
strlcpy \
strndup \
strsep \
strtonum \
])
AC_FUNC_STRNLEN
# Check if strtonum works.
AC_MSG_CHECKING([for working strtonum])
AC_RUN_IFELSE([AC_LANG_PROGRAM(
[#include <stdlib.h>],
[return (strtonum("0", 0, 1, NULL) == 0 ? 0 : 1);]
)],
[AC_DEFINE(HAVE_STRTONUM) AC_MSG_RESULT(yes)],
[AC_LIBOBJ(strtonum) AC_MSG_RESULT(no)]
)
# Clang sanitizers wrap reallocarray even if it isn't available on the target
# system. When compiled it always returns NULL and crashes the program. To
# detect this we need a more complicated test.
AC_MSG_CHECKING([for working reallocarray])
AC_RUN_IFELSE([AC_LANG_PROGRAM(
[#include <stdlib.h>],
[return (reallocarray(NULL, 1, 1) == NULL);]
)],
AC_MSG_RESULT(yes),
[AC_LIBOBJ(reallocarray) AC_MSG_RESULT([no])],
[AC_LIBOBJ(reallocarray) AC_MSG_RESULT([no])]
)
AC_MSG_CHECKING([for working recallocarray])
AC_RUN_IFELSE([AC_LANG_PROGRAM(
[#include <stdlib.h>],
[return (recallocarray(NULL, 1, 1, 1) == NULL);]
)],
AC_MSG_RESULT(yes),
[AC_LIBOBJ(recallocarray) AC_MSG_RESULT([no])],
[AC_LIBOBJ(recallocarray) AC_MSG_RESULT([no])]
)
# Look for clock_gettime. Must come before event_init.
AC_SEARCH_LIBS(clock_gettime, rt)
# Look for libevent.
# Always use our getopt because 1) glibc's doesn't enforce argument order 2)
# musl does not set optarg to NULL for flags without arguments (although it is
# not required to, but it is helpful) 3) there are probably other weird
# implementations.
AC_LIBOBJ(getopt)
# Look for libevent. Try libevent_core or libevent with pkg-config first then
# look for the library.
PKG_CHECK_MODULES(
LIBEVENT,
libevent,
LIBEVENT_CORE,
[libevent_core >= 2],
[
AM_CFLAGS="$LIBEVENT_CFLAGS $AM_CFLAGS"
CFLAGS="$AM_CFLAGS $SAVED_CFLAGS"
LIBS="$LIBEVENT_LIBS $LIBS"
AM_CPPFLAGS="$LIBEVENT_CORE_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$AM_CPPFLAGS $SAVED_CPPFLAGS"
LIBS="$LIBEVENT_CORE_LIBS $LIBS"
found_libevent=yes
],
found_libevent=no
)
if test x$found_libevent = xno; then
PKG_CHECK_MODULES(
LIBEVENT,
[libevent >= 2],
[
AM_CPPFLAGS="$LIBEVENT_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$AM_CPPFLAGS $SAVED_CPPFLAGS"
LIBS="$LIBEVENT_LIBS $LIBS"
found_libevent=yes
],
found_libevent=no
)
fi
if test x$found_libevent = xno; then
AC_SEARCH_LIBS(
event_init,
[event_core event event-1.4],
found_libevent=yes,
found_libevent=no
)
fi
AC_CHECK_HEADER(
event2/event.h,
AC_DEFINE(HAVE_EVENT2_EVENT_H),
[
AC_SEARCH_LIBS(
event_init,
[event event-1.4 event2],
found_libevent=yes,
AC_CHECK_HEADER(
event.h,
AC_DEFINE(HAVE_EVENT_H),
found_libevent=no
)
]
)
AC_CHECK_HEADER(
event.h,
,
found_libevent=no
)
if test "x$found_libevent" = xno; then
AC_MSG_ERROR("libevent not found")
fi
# Look for ncurses.
# Look for ncurses or curses. Try pkg-config first then directly for the
# library.
PKG_CHECK_MODULES(
LIBTINFO,
tinfo,
found_ncurses=yes,
[
AM_CPPFLAGS="$LIBTINFO_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$LIBTINFO_CFLAGS $SAVED_CPPFLAGS"
LIBS="$LIBTINFO_LIBS $LIBS"
found_ncurses=yes
],
found_ncurses=no
)
if test "x$found_ncurses" = xno; then
PKG_CHECK_MODULES(
LIBNCURSES,
ncurses,
found_ncurses=yes,
[
AM_CPPFLAGS="$LIBNCURSES_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$LIBNCURSES_CFLAGS $SAVED_CPPFLAGS"
LIBS="$LIBNCURSES_LIBS $LIBS"
found_ncurses=yes
],
found_ncurses=no
)
fi
if test "x$found_ncurses" = xno; then
PKG_CHECK_MODULES(
LIBNCURSES,
LIBNCURSESW,
ncursesw,
found_ncurses=yes,
[
AM_CPPFLAGS="$LIBNCURSESW_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$LIBNCURSESW_CFLAGS $SAVED_CPPFLAGS"
LIBS="$LIBNCURSESW_LIBS $LIBS"
found_ncurses=yes
],
found_ncurses=no
)
fi
if test "x$found_ncurses" = xyes; then
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.
AC_CHECK_LIB(
tinfo,
if test "x$found_ncurses" = xno; then
AC_SEARCH_LIBS(
setupterm,
[tinfo ncurses ncursesw],
found_ncurses=yes,
found_ncurses=no
)
if test "x$found_ncurses" = xno; then
AC_CHECK_LIB(
ncurses,
setupterm,
found_ncurses=yes,
found_ncurses=no
)
fi
if test "x$found_ncurses" = xyes; then
AC_CHECK_HEADER(
ncurses.h,
LIBS="$LIBS -lncurses",
found_ncurses=no)
found_ncurses=no
)
fi
fi
if test "x$found_ncurses" = xyes; then
AC_DEFINE(HAVE_NCURSES_H)
else
# No ncurses, try curses.
AC_CHECK_LIB(
curses,
setupterm,
@@ -216,7 +309,8 @@ else
AC_CHECK_HEADER(
curses.h,
,
found_curses=no)
found_curses=no
)
if test "x$found_curses" = xyes; then
LIBS="$LIBS -lcurses"
AC_DEFINE(HAVE_CURSES_H)
@@ -282,12 +376,11 @@ AC_TRY_LINK(
found_b64_ntop=yes,
found_b64_ntop=no
)
AC_MSG_RESULT($found_b64_ntop)
OLD_LIBS="$LIBS"
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"
LIBS="$OLD_LIBS -lresolv"
AC_TRY_LINK(
[
#include <sys/types.h>
@@ -298,15 +391,27 @@ if test "x$found_b64_ntop" = xno; then
found_b64_ntop=yes,
found_b64_ntop=no
)
if test "x$found_b64_ntop" = xno; then
LIBS="$OLD_LIBS"
AC_MSG_RESULT(no)
fi
AC_MSG_RESULT($found_b64_ntop)
fi
if test "x$found_b64_ntop" = xno; then
AC_MSG_CHECKING(for b64_ntop with -lnetwork)
LIBS="$OLD_LIBS -lnetwork"
AC_TRY_LINK(
[
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
],
[b64_ntop(NULL, 0, NULL, 0);],
found_b64_ntop=yes,
found_b64_ntop=no
)
AC_MSG_RESULT($found_b64_ntop)
fi
if test "x$found_b64_ntop" = xyes; then
AC_DEFINE(HAVE_B64_NTOP)
AC_MSG_RESULT(yes)
else
LIBS="$OLD_LIBS"
AC_LIBOBJ(base64)
fi
@@ -315,8 +420,34 @@ AC_SEARCH_LIBS(inet_ntoa, nsl)
AC_SEARCH_LIBS(socket, socket)
AC_CHECK_LIB(xnet, socket)
# Check for CMSG_DATA. Some platforms require _XOPEN_SOURCE_EXTENDED (for
# example see xopen_networking(7) on HP-UX).
# Check if using glibc and have malloc_trim(3). The glibc free(3) is pretty bad
# about returning memory to the kernel unless the application tells it when to
# with malloc_trim(3).
AC_MSG_CHECKING(if free doesn't work very well)
AC_LINK_IFELSE([AC_LANG_SOURCE(
[
#include <stdlib.h>
#ifdef __GLIBC__
#include <malloc.h>
int main(void) {
malloc_trim (0);
exit(0);
}
#else
no
#endif
])],
found_malloc_trim=yes,
found_malloc_trim=no
)
AC_MSG_RESULT($found_malloc_trim)
if test "x$found_malloc_trim" = xyes; then
AC_DEFINE(HAVE_MALLOC_TRIM)
fi
# Check for CMSG_DATA. On some platforms like HP-UX this requires UNIX 95
# (_XOPEN_SOURCE and _XOPEN_SOURCE_EXTENDED) (see xopen_networking(7)). On
# others, UNIX 03 (_XOPEN_SOURCE 600, see standards(7) on Solaris).
XOPEN_DEFINES=
AC_MSG_CHECKING(for CMSG_DATA)
AC_EGREP_CPP(
@@ -349,6 +480,25 @@ if test "x$found_cmsg_data" = xno; then
AC_MSG_RESULT($found_cmsg_data)
if test "x$found_cmsg_data" = xyes; then
XOPEN_DEFINES="-D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED"
fi
fi
if test "x$found_cmsg_data" = xno; then
AC_MSG_CHECKING(if CMSG_DATA needs _XOPEN_SOURCE 600)
AC_EGREP_CPP(
yes,
[
#define _XOPEN_SOURCE 600
#include <sys/socket.h>
#ifdef CMSG_DATA
yes
#endif
],
found_cmsg_data=yes,
found_cmsg_data=no
)
AC_MSG_RESULT($found_cmsg_data)
if test "x$found_cmsg_data" = xyes; then
XOPEN_DEFINES="-D_XOPEN_SOURCE=600"
else
AC_MSG_ERROR("CMSG_DATA not found")
fi
@@ -424,40 +574,6 @@ else
AC_LIBOBJ(unvis)
fi
# Look for getopt. glibc's getopt does not enforce argument order and the ways
# of making it do so are stupid, so just use our own instead.
AC_CHECK_FUNC(getopt, found_getopt=yes, found_getopt=no)
if test "x$found_getopt" != xno; then
AC_MSG_CHECKING(if getopt is suitable)
AC_EGREP_CPP(
yes,
[
#include <features.h>
#ifdef __GLIBC__
yes
#endif
],
[
found_getopt=no
AC_MSG_RESULT(no)
],
AC_MSG_RESULT(yes))
fi
if test "x$found_getopt" != xno; then
AC_CHECK_DECLS(
[optarg, optind, optreset],
,
found_getopt=no,
[
#include <unistd.h>
])
fi
if test "x$found_getopt" != xno; then
AC_DEFINE(HAVE_GETOPT)
else
AC_LIBOBJ(getopt)
fi
# 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
@@ -571,6 +687,12 @@ case "$host_os" in
AC_MSG_RESULT(darwin)
PLATFORM=darwin
#
# OS X uses __dead2 instead of __dead, like FreeBSD. But it
# defines __dead away so it needs to be removed before we can
# replace it.
#
AC_DEFINE(BROKEN___DEAD)
#
# 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.
@@ -625,6 +747,10 @@ case "$host_os" in
AC_MSG_RESULT(cygwin)
PLATFORM=cygwin
;;
*haiku*)
AC_MSG_RESULT(haiku)
PLATFORM=haiku
;;
*)
AC_MSG_RESULT(unknown)
PLATFORM=unknown
@@ -640,6 +766,7 @@ AM_CONDITIONAL(IS_NETBSD, test "x$PLATFORM" = xnetbsd)
AM_CONDITIONAL(IS_OPENBSD, test "x$PLATFORM" = xopenbsd)
AM_CONDITIONAL(IS_SUNOS, test "x$PLATFORM" = xsunos)
AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux)
AM_CONDITIONAL(IS_HAIKU, test "x$PLATFORM" = xhaiku)
AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown)
# Save our CFLAGS/CPPFLAGS/LDFLAGS for the Makefile and restore the old user

View File

@@ -26,36 +26,6 @@
#define CONTROL_SHOULD_NOTIFY_CLIENT(c) \
((c) != NULL && ((c)->flags & CLIENT_CONTROL))
void
control_notify_input(struct client *c, struct window_pane *wp,
const u_char *buf, size_t len)
{
struct evbuffer *message;
u_int i;
if (c->session == NULL)
return;
/*
* 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] == '\\')
evbuffer_add_printf(message, "\\%03o", buf[i]);
else
evbuffer_add_printf(message, "%c", buf[i]);
}
control_write_buffer(c, message);
evbuffer_free(message);
}
}
void
control_notify_pane_mode_changed(int pane)
{
@@ -79,7 +49,7 @@ control_notify_window_layout_changed(struct window *w)
char *cp;
template = "%layout-change #{window_id} #{window_layout} "
"#{window_visible_layout} #{window_flags}";
"#{window_visible_layout} #{window_raw_flags}";
TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
@@ -201,6 +171,17 @@ control_notify_client_session_changed(struct client *cc)
}
}
void
control_notify_client_detached(struct client *cc)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (CONTROL_SHOULD_NOTIFY_CLIENT(c))
control_write(c, "%%client-detached %s", cc->name);
}
}
void
control_notify_session_renamed(struct session *s)
{

1080
control.c

File diff suppressed because it is too large Load Diff

View File

@@ -18,6 +18,7 @@
#include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -86,8 +87,10 @@ environ_copy(struct environ *srcenv, struct environ *dstenv)
RB_FOREACH(envent, environ, srcenv) {
if (envent->value == NULL)
environ_clear(dstenv, envent->name);
else
environ_set(dstenv, envent->name, "%s", envent->value);
else {
environ_set(dstenv, envent->name, envent->flags,
"%s", envent->value);
}
}
}
@@ -103,18 +106,21 @@ environ_find(struct environ *env, const char *name)
/* Set an environment variable. */
void
environ_set(struct environ *env, const char *name, const char *fmt, ...)
environ_set(struct environ *env, const char *name, int flags, const char *fmt,
...)
{
struct environ_entry *envent;
va_list ap;
va_start(ap, fmt);
if ((envent = environ_find(env, name)) != NULL) {
envent->flags = flags;
free(envent->value);
xvasprintf(&envent->value, fmt, ap);
} else {
envent = xmalloc(sizeof *envent);
envent->name = xstrdup(name);
envent->flags = flags;
xvasprintf(&envent->value, fmt, ap);
RB_INSERT(environ, env, envent);
}
@@ -133,6 +139,7 @@ environ_clear(struct environ *env, const char *name)
} else {
envent = xmalloc(sizeof *envent);
envent->name = xstrdup(name);
envent->flags = 0;
envent->value = NULL;
RB_INSERT(environ, env, envent);
}
@@ -140,7 +147,7 @@ environ_clear(struct environ *env, const char *name)
/* Set an environment variable from a NAME=VALUE string. */
void
environ_put(struct environ *env, const char *var)
environ_put(struct environ *env, const char *var, int flags)
{
char *name, *value;
@@ -152,7 +159,7 @@ environ_put(struct environ *env, const char *var)
name = xstrdup(var);
name[strcspn(name, "=")] = '\0';
environ_set(env, name, "%s", value);
environ_set(env, name, flags, "%s", value);
free(name);
}
@@ -170,7 +177,7 @@ environ_unset(struct environ *env, const char *name)
free(envent);
}
/* Copy variables from a destination into a source * environment. */
/* Copy variables from a destination into a source environment. */
void
environ_update(struct options *oo, struct environ *src, struct environ *dst)
{
@@ -185,10 +192,14 @@ environ_update(struct options *oo, struct environ *src, struct environ *dst)
a = options_array_first(o);
while (a != NULL) {
ov = options_array_item_value(a);
if ((envent = environ_find(src, ov->string)) == NULL)
RB_FOREACH(envent, environ, src) {
if (fnmatch(ov->string, envent->name, 0) == 0)
break;
}
if (envent == NULL)
environ_clear(dst, ov->string);
else
environ_set(dst, envent->name, "%s", envent->value);
environ_set(dst, envent->name, 0, "%s", envent->value);
a = options_array_next(a);
}
}
@@ -201,7 +212,9 @@ environ_push(struct environ *env)
environ = xcalloc(1, sizeof *environ);
RB_FOREACH(envent, environ, env) {
if (envent->value != NULL && *envent->name != '\0')
if (envent->value != NULL &&
*envent->name != '\0' &&
(~envent->flags & ENVIRON_HIDDEN))
setenv(envent->name, envent->value, 1);
}
}
@@ -243,14 +256,17 @@ environ_for_session(struct session *s, int no_TERM)
if (!no_TERM) {
value = options_get_string(global_options, "default-terminal");
environ_set(env, "TERM", "%s", value);
environ_set(env, "TERM", 0, "%s", value);
environ_set(env, "TERM_PROGRAM", 0, "%s", "tmux");
environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion());
}
if (s != NULL)
idx = s->id;
else
idx = -1;
environ_set(env, "TMUX", "%s,%ld,%d", socket_path, (long)getpid(), idx);
environ_set(env, "TMUX", 0, "%s,%ld,%d", socket_path, (long)getpid(),
idx);
return (env);
}

819
file.c Normal file
View File

@@ -0,0 +1,819 @@
/* $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 <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
/*
* IPC file handling. Both client and server use the same data structures
* (client_file and client_files) to store list of active files. Most functions
* are for use either in client or server but not both.
*/
static int file_next_stream = 3;
RB_GENERATE(client_files, client_file, entry, file_cmp);
/* Get path for file, either as given or from working directory. */
static char *
file_get_path(struct client *c, const char *file)
{
char *path;
if (*file == '/')
path = xstrdup(file);
else
xasprintf(&path, "%s/%s", server_client_get_cwd(c, NULL), file);
return (path);
}
/* Tree comparison function. */
int
file_cmp(struct client_file *cf1, struct client_file *cf2)
{
if (cf1->stream < cf2->stream)
return (-1);
if (cf1->stream > cf2->stream)
return (1);
return (0);
}
/*
* Create a file object in the client process - the peer is the server to send
* messages to. Check callback is fired when the file is finished with so the
* process can decide if it needs to exit (if it is waiting for files to
* flush).
*/
struct client_file *
file_create_with_peer(struct tmuxpeer *peer, struct client_files *files,
int stream, client_file_cb cb, void *cbdata)
{
struct client_file *cf;
cf = xcalloc(1, sizeof *cf);
cf->c = NULL;
cf->references = 1;
cf->stream = stream;
cf->buffer = evbuffer_new();
if (cf->buffer == NULL)
fatalx("out of memory");
cf->cb = cb;
cf->data = cbdata;
cf->peer = peer;
cf->tree = files;
RB_INSERT(client_files, files, cf);
return (cf);
}
/* Create a file object in the server, communicating with the given client. */
struct client_file *
file_create_with_client(struct client *c, int stream, client_file_cb cb,
void *cbdata)
{
struct client_file *cf;
if (c != NULL && (c->flags & CLIENT_ATTACHED))
c = NULL;
cf = xcalloc(1, sizeof *cf);
cf->c = c;
cf->references = 1;
cf->stream = stream;
cf->buffer = evbuffer_new();
if (cf->buffer == NULL)
fatalx("out of memory");
cf->cb = cb;
cf->data = cbdata;
if (cf->c != NULL) {
cf->peer = cf->c->peer;
cf->tree = &cf->c->files;
RB_INSERT(client_files, &cf->c->files, cf);
cf->c->references++;
}
return (cf);
}
/* Free a file. */
void
file_free(struct client_file *cf)
{
if (--cf->references != 0)
return;
evbuffer_free(cf->buffer);
free(cf->path);
if (cf->tree != NULL)
RB_REMOVE(client_files, cf->tree, cf);
if (cf->c != NULL)
server_client_unref(cf->c);
free(cf);
}
/* Event to fire the done callback. */
static void
file_fire_done_cb(__unused int fd, __unused short events, void *arg)
{
struct client_file *cf = arg;
struct client *c = cf->c;
if (cf->cb != NULL && (c == NULL || (~c->flags & CLIENT_DEAD)))
cf->cb(c, cf->path, cf->error, 1, cf->buffer, cf->data);
file_free(cf);
}
/* Add an event to fire the done callback (used by the server). */
void
file_fire_done(struct client_file *cf)
{
event_once(-1, EV_TIMEOUT, file_fire_done_cb, cf, NULL);
}
/* Fire the read callback. */
void
file_fire_read(struct client_file *cf)
{
if (cf->cb != NULL)
cf->cb(cf->c, cf->path, cf->error, 0, cf->buffer, cf->data);
}
/* Can this file be printed to? */
int
file_can_print(struct client *c)
{
if (c == NULL)
return (0);
if (c->session != NULL && (~c->flags & CLIENT_CONTROL))
return (0);
return (1);
}
/* Print a message to a file. */
void
file_print(struct client *c, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
file_vprint(c, fmt, ap);
va_end(ap);
}
/* Print a message to a file. */
void
file_vprint(struct client *c, const char *fmt, va_list ap)
{
struct client_file find, *cf;
struct msg_write_open msg;
if (!file_can_print(c))
return;
find.stream = 1;
if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) {
cf = file_create_with_client(c, 1, NULL, NULL);
cf->path = xstrdup("-");
evbuffer_add_vprintf(cf->buffer, fmt, ap);
msg.stream = 1;
msg.fd = STDOUT_FILENO;
msg.flags = 0;
proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg);
} else {
evbuffer_add_vprintf(cf->buffer, fmt, ap);
file_push(cf);
}
}
/* Print a buffer to a file. */
void
file_print_buffer(struct client *c, void *data, size_t size)
{
struct client_file find, *cf;
struct msg_write_open msg;
if (!file_can_print(c))
return;
find.stream = 1;
if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) {
cf = file_create_with_client(c, 1, NULL, NULL);
cf->path = xstrdup("-");
evbuffer_add(cf->buffer, data, size);
msg.stream = 1;
msg.fd = STDOUT_FILENO;
msg.flags = 0;
proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg);
} else {
evbuffer_add(cf->buffer, data, size);
file_push(cf);
}
}
/* Report an error to a file. */
void
file_error(struct client *c, const char *fmt, ...)
{
struct client_file find, *cf;
struct msg_write_open msg;
va_list ap;
if (!file_can_print(c))
return;
va_start(ap, fmt);
find.stream = 2;
if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) {
cf = file_create_with_client(c, 2, NULL, NULL);
cf->path = xstrdup("-");
evbuffer_add_vprintf(cf->buffer, fmt, ap);
msg.stream = 2;
msg.fd = STDERR_FILENO;
msg.flags = 0;
proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg);
} else {
evbuffer_add_vprintf(cf->buffer, fmt, ap);
file_push(cf);
}
va_end(ap);
}
/* Write data to a file. */
void
file_write(struct client *c, const char *path, int flags, const void *bdata,
size_t bsize, client_file_cb cb, void *cbdata)
{
struct client_file *cf;
struct msg_write_open *msg;
size_t msglen;
int fd = -1;
u_int stream = file_next_stream++;
FILE *f;
const char *mode;
if (strcmp(path, "-") == 0) {
cf = file_create_with_client(c, stream, cb, cbdata);
cf->path = xstrdup("-");
fd = STDOUT_FILENO;
if (c == NULL ||
(c->flags & CLIENT_ATTACHED) ||
(c->flags & CLIENT_CONTROL)) {
cf->error = EBADF;
goto done;
}
goto skip;
}
cf = file_create_with_client(c, stream, cb, cbdata);
cf->path = file_get_path(c, path);
if (c == NULL || c->flags & CLIENT_ATTACHED) {
if (flags & O_APPEND)
mode = "ab";
else
mode = "wb";
f = fopen(cf->path, mode);
if (f == NULL) {
cf->error = errno;
goto done;
}
if (fwrite(bdata, 1, bsize, f) != bsize) {
fclose(f);
cf->error = EIO;
goto done;
}
fclose(f);
goto done;
}
skip:
evbuffer_add(cf->buffer, bdata, bsize);
msglen = strlen(cf->path) + 1 + sizeof *msg;
if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
cf->error = E2BIG;
goto done;
}
msg = xmalloc(msglen);
msg->stream = cf->stream;
msg->fd = fd;
msg->flags = flags;
memcpy(msg + 1, cf->path, msglen - sizeof *msg);
if (proc_send(cf->peer, MSG_WRITE_OPEN, -1, msg, msglen) != 0) {
free(msg);
cf->error = EINVAL;
goto done;
}
free(msg);
return;
done:
file_fire_done(cf);
}
/* Read a file. */
void
file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
{
struct client_file *cf;
struct msg_read_open *msg;
size_t msglen;
int fd = -1;
u_int stream = file_next_stream++;
FILE *f;
size_t size;
char buffer[BUFSIZ];
if (strcmp(path, "-") == 0) {
cf = file_create_with_client(c, stream, cb, cbdata);
cf->path = xstrdup("-");
fd = STDIN_FILENO;
if (c == NULL ||
(c->flags & CLIENT_ATTACHED) ||
(c->flags & CLIENT_CONTROL)) {
cf->error = EBADF;
goto done;
}
goto skip;
}
cf = file_create_with_client(c, stream, cb, cbdata);
cf->path = file_get_path(c, path);
if (c == NULL || c->flags & CLIENT_ATTACHED) {
f = fopen(cf->path, "rb");
if (f == NULL) {
cf->error = errno;
goto done;
}
for (;;) {
size = fread(buffer, 1, sizeof buffer, f);
if (evbuffer_add(cf->buffer, buffer, size) != 0) {
cf->error = ENOMEM;
goto done;
}
if (size != sizeof buffer)
break;
}
if (ferror(f)) {
cf->error = EIO;
goto done;
}
fclose(f);
goto done;
}
skip:
msglen = strlen(cf->path) + 1 + sizeof *msg;
if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
cf->error = E2BIG;
goto done;
}
msg = xmalloc(msglen);
msg->stream = cf->stream;
msg->fd = fd;
memcpy(msg + 1, cf->path, msglen - sizeof *msg);
if (proc_send(cf->peer, MSG_READ_OPEN, -1, msg, msglen) != 0) {
free(msg);
cf->error = EINVAL;
goto done;
}
free(msg);
return;
done:
file_fire_done(cf);
}
/* Push event, fired if there is more writing to be done. */
static void
file_push_cb(__unused int fd, __unused short events, void *arg)
{
struct client_file *cf = arg;
if (cf->c == NULL || ~cf->c->flags & CLIENT_DEAD)
file_push(cf);
file_free(cf);
}
/* Push uwritten data to the client for a file, if it will accept it. */
void
file_push(struct client_file *cf)
{
struct msg_write_data *msg;
size_t msglen, sent, left;
struct msg_write_close close;
msg = xmalloc(sizeof *msg);
left = EVBUFFER_LENGTH(cf->buffer);
while (left != 0) {
sent = left;
if (sent > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg)
sent = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg;
msglen = (sizeof *msg) + sent;
msg = xrealloc(msg, msglen);
msg->stream = cf->stream;
memcpy(msg + 1, EVBUFFER_DATA(cf->buffer), sent);
if (proc_send(cf->peer, MSG_WRITE, -1, msg, msglen) != 0)
break;
evbuffer_drain(cf->buffer, sent);
left = EVBUFFER_LENGTH(cf->buffer);
log_debug("file %d sent %zu, left %zu", cf->stream, sent, left);
}
if (left != 0) {
cf->references++;
event_once(-1, EV_TIMEOUT, file_push_cb, cf, NULL);
} else if (cf->stream > 2) {
close.stream = cf->stream;
proc_send(cf->peer, MSG_WRITE_CLOSE, -1, &close, sizeof close);
file_fire_done(cf);
}
free(msg);
}
/* Check if any files have data left to write. */
int
file_write_left(struct client_files *files)
{
struct client_file *cf;
size_t left;
int waiting = 0;
RB_FOREACH(cf, client_files, files) {
if (cf->event == NULL)
continue;
left = EVBUFFER_LENGTH(cf->event->output);
if (left != 0) {
waiting++;
log_debug("file %u %zu bytes left", cf->stream, left);
}
}
return (waiting != 0);
}
/* Client file write error callback. */
static void
file_write_error_callback(__unused struct bufferevent *bev, __unused short what,
void *arg)
{
struct client_file *cf = arg;
log_debug("write error file %d", cf->stream);
bufferevent_free(cf->event);
cf->event = NULL;
close(cf->fd);
cf->fd = -1;
if (cf->cb != NULL)
cf->cb(NULL, NULL, 0, -1, NULL, cf->data);
}
/* Client file write callback. */
static void
file_write_callback(__unused struct bufferevent *bev, void *arg)
{
struct client_file *cf = arg;
log_debug("write check file %d", cf->stream);
if (cf->cb != NULL)
cf->cb(NULL, NULL, 0, -1, NULL, cf->data);
if (cf->closed && EVBUFFER_LENGTH(cf->event->output) == 0) {
bufferevent_free(cf->event);
close(cf->fd);
RB_REMOVE(client_files, cf->tree, cf);
file_free(cf);
}
}
/* Handle a file write open message (client). */
void
file_write_open(struct client_files *files, struct tmuxpeer *peer,
struct imsg *imsg, int allow_streams, int close_received,
client_file_cb cb, void *cbdata)
{
struct msg_write_open *msg = imsg->data;
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
const char *path;
struct msg_write_ready reply;
struct client_file find, *cf;
const int flags = O_NONBLOCK|O_WRONLY|O_CREAT;
int error = 0;
if (msglen < sizeof *msg)
fatalx("bad MSG_WRITE_OPEN size");
if (msglen == sizeof *msg)
path = "-";
else
path = (const char *)(msg + 1);
log_debug("open write file %d %s", msg->stream, path);
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) != NULL) {
error = EBADF;
goto reply;
}
cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata);
if (cf->closed) {
error = EBADF;
goto reply;
}
cf->fd = -1;
if (msg->fd == -1)
cf->fd = open(path, msg->flags|flags, 0644);
else if (allow_streams) {
if (msg->fd != STDOUT_FILENO && msg->fd != STDERR_FILENO)
errno = EBADF;
else {
cf->fd = dup(msg->fd);
if (close_received)
close(msg->fd); /* can only be used once */
}
} else
errno = EBADF;
if (cf->fd == -1) {
error = errno;
goto reply;
}
cf->event = bufferevent_new(cf->fd, NULL, file_write_callback,
file_write_error_callback, cf);
bufferevent_enable(cf->event, EV_WRITE);
goto reply;
reply:
reply.stream = msg->stream;
reply.error = error;
proc_send(peer, MSG_WRITE_READY, -1, &reply, sizeof reply);
}
/* Handle a file write data message (client). */
void
file_write_data(struct client_files *files, struct imsg *imsg)
{
struct msg_write_data *msg = imsg->data;
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
struct client_file find, *cf;
size_t size = msglen - sizeof *msg;
if (msglen < sizeof *msg)
fatalx("bad MSG_WRITE size");
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
fatalx("unknown stream number");
log_debug("write %zu to file %d", size, cf->stream);
if (cf->event != NULL)
bufferevent_write(cf->event, msg + 1, size);
}
/* Handle a file write close message (client). */
void
file_write_close(struct client_files *files, struct imsg *imsg)
{
struct msg_write_close *msg = imsg->data;
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
struct client_file find, *cf;
if (msglen != sizeof *msg)
fatalx("bad MSG_WRITE_CLOSE size");
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
fatalx("unknown stream number");
log_debug("close file %d", cf->stream);
if (cf->event == NULL || EVBUFFER_LENGTH(cf->event->output) == 0) {
if (cf->event != NULL)
bufferevent_free(cf->event);
if (cf->fd != -1)
close(cf->fd);
RB_REMOVE(client_files, files, cf);
file_free(cf);
}
}
/* Client file read error callback. */
static void
file_read_error_callback(__unused struct bufferevent *bev, __unused short what,
void *arg)
{
struct client_file *cf = arg;
struct msg_read_done msg;
log_debug("read error file %d", cf->stream);
msg.stream = cf->stream;
msg.error = 0;
proc_send(cf->peer, MSG_READ_DONE, -1, &msg, sizeof msg);
bufferevent_free(cf->event);
close(cf->fd);
RB_REMOVE(client_files, cf->tree, cf);
file_free(cf);
}
/* Client file read callback. */
static void
file_read_callback(__unused struct bufferevent *bev, void *arg)
{
struct client_file *cf = arg;
void *bdata;
size_t bsize;
struct msg_read_data *msg;
size_t msglen;
msg = xmalloc(sizeof *msg);
for (;;) {
bdata = EVBUFFER_DATA(cf->event->input);
bsize = EVBUFFER_LENGTH(cf->event->input);
if (bsize == 0)
break;
if (bsize > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg)
bsize = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg;
log_debug("read %zu from file %d", bsize, cf->stream);
msglen = (sizeof *msg) + bsize;
msg = xrealloc(msg, msglen);
msg->stream = cf->stream;
memcpy(msg + 1, bdata, bsize);
proc_send(cf->peer, MSG_READ, -1, msg, msglen);
evbuffer_drain(cf->event->input, bsize);
}
free(msg);
}
/* Handle a file read open message (client). */
void
file_read_open(struct client_files *files, struct tmuxpeer *peer,
struct imsg *imsg, int allow_streams, int close_received, client_file_cb cb,
void *cbdata)
{
struct msg_read_open *msg = imsg->data;
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
const char *path;
struct msg_read_done reply;
struct client_file find, *cf;
const int flags = O_NONBLOCK|O_RDONLY;
int error;
if (msglen < sizeof *msg)
fatalx("bad MSG_READ_OPEN size");
if (msglen == sizeof *msg)
path = "-";
else
path = (const char *)(msg + 1);
log_debug("open read file %d %s", msg->stream, path);
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) != NULL) {
error = EBADF;
goto reply;
}
cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata);
if (cf->closed) {
error = EBADF;
goto reply;
}
cf->fd = -1;
if (msg->fd == -1)
cf->fd = open(path, flags);
else if (allow_streams) {
if (msg->fd != STDIN_FILENO)
errno = EBADF;
else {
cf->fd = dup(msg->fd);
if (close_received)
close(msg->fd); /* can only be used once */
}
} else
errno = EBADF;
if (cf->fd == -1) {
error = errno;
goto reply;
}
cf->event = bufferevent_new(cf->fd, file_read_callback, NULL,
file_read_error_callback, cf);
bufferevent_enable(cf->event, EV_READ);
return;
reply:
reply.stream = msg->stream;
reply.error = error;
proc_send(peer, MSG_READ_DONE, -1, &reply, sizeof reply);
}
/* Handle a write ready message (server). */
void
file_write_ready(struct client_files *files, struct imsg *imsg)
{
struct msg_write_ready *msg = imsg->data;
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
struct client_file find, *cf;
if (msglen != sizeof *msg)
fatalx("bad MSG_WRITE_READY size");
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
return;
if (msg->error != 0) {
cf->error = msg->error;
file_fire_done(cf);
} else
file_push(cf);
}
/* Handle read data message (server). */
void
file_read_data(struct client_files *files, struct imsg *imsg)
{
struct msg_read_data *msg = imsg->data;
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
struct client_file find, *cf;
void *bdata = msg + 1;
size_t bsize = msglen - sizeof *msg;
if (msglen < sizeof *msg)
fatalx("bad MSG_READ_DATA size");
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
return;
log_debug("file %d read %zu bytes", cf->stream, bsize);
if (cf->error == 0) {
if (evbuffer_add(cf->buffer, bdata, bsize) != 0) {
cf->error = ENOMEM;
file_fire_done(cf);
} else
file_fire_read(cf);
}
}
/* Handle a read done message (server). */
void
file_read_done(struct client_files *files, struct imsg *imsg)
{
struct msg_read_done *msg = imsg->data;
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
struct client_file find, *cf;
if (msglen != sizeof *msg)
fatalx("bad MSG_READ_DONE size");
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
return;
log_debug("file %d read done", cf->stream);
cf->error = msg->error;
file_fire_done(cf);
}

View File

@@ -142,7 +142,8 @@ format_draw_put_list(struct screen_write_ctx *octx,
width -= list_left->cx;
}
if (start + width < list->cx && width > list_right->cx) {
screen_write_cursormove(octx, ocx + offset + width - 1, ocy, 0);
screen_write_cursormove(octx, ocx + offset + width -
list_right->cx, ocy, 0);
screen_write_fast_copy(octx, list_right, 0, 0, list_right->cx,
1);
width -= list_right->cx;
@@ -156,13 +157,14 @@ format_draw_put_list(struct screen_write_ctx *octx,
static void
format_draw_none(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct format_ranges *frs)
struct screen *abs_centre, struct format_ranges *frs)
{
u_int width_left, width_centre, width_right;
u_int width_left, width_centre, width_right, width_abs_centre;
width_left = left->cx;
width_centre = centre->cx;
width_right = right->cx;
width_abs_centre = abs_centre->cx;
/*
* Try to keep as much of the left and right as possible at the expense
@@ -198,23 +200,34 @@ format_draw_none(struct screen_write_ctx *octx, u_int available, u_int ocx,
- width_centre / 2,
centre->cx / 2 - width_centre / 2,
width_centre);
/*
* Write abs_centre in the perfect centre of all horizontal space.
*/
if (width_abs_centre > available)
width_abs_centre = available;
format_draw_put(octx, ocx, ocy, abs_centre, frs,
(available - width_abs_centre) / 2,
0,
width_abs_centre);
}
/* Draw format with list on the left. */
static void
format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct screen *list, struct screen *list_left, struct screen *list_right,
struct screen *after, int focus_start, int focus_end,
struct format_ranges *frs)
struct screen *abs_centre, struct screen *list, struct screen *list_left,
struct screen *list_right, struct screen *after, int focus_start,
int focus_end, struct format_ranges *frs)
{
u_int width_left, width_centre, width_right;
u_int width_list, width_after;
u_int width_list, width_after, width_abs_centre;
struct screen_write_ctx ctx;
width_left = left->cx;
width_centre = centre->cx;
width_right = right->cx;
width_abs_centre = abs_centre->cx;
width_list = list->cx;
width_after = after->cx;
@@ -241,12 +254,12 @@ format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx,
/* If there is no list left, pass off to the no list function. */
if (width_list == 0) {
screen_write_start(&ctx, NULL, left);
screen_write_start(&ctx, left);
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
screen_write_stop(&ctx);
format_draw_none(octx, available, ocx, ocy, left, centre,
right, frs);
right, abs_centre, frs);
return;
}
@@ -290,23 +303,34 @@ format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx,
focus_start = focus_end = 0;
format_draw_put_list(octx, ocx, ocy, width_left, width_list, list,
list_left, list_right, focus_start, focus_end, frs);
/*
* Write abs_centre in the perfect centre of all horizontal space.
*/
if (width_abs_centre > available)
width_abs_centre = available;
format_draw_put(octx, ocx, ocy, abs_centre, frs,
(available - width_abs_centre) / 2,
0,
width_abs_centre);
}
/* Draw format with list in the centre. */
static void
format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct screen *list, struct screen *list_left, struct screen *list_right,
struct screen *after, int focus_start, int focus_end,
struct format_ranges *frs)
struct screen *abs_centre, struct screen *list, struct screen *list_left,
struct screen *list_right, struct screen *after, int focus_start,
int focus_end, struct format_ranges *frs)
{
u_int width_left, width_centre, width_right;
u_int width_list, width_after, middle;
u_int width_left, width_centre, width_right, middle;
u_int width_list, width_after, width_abs_centre;
struct screen_write_ctx ctx;
width_left = left->cx;
width_centre = centre->cx;
width_right = right->cx;
width_abs_centre = abs_centre->cx;
width_list = list->cx;
width_after = after->cx;
@@ -333,12 +357,12 @@ format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx,
/* If there is no list left, pass off to the no list function. */
if (width_list == 0) {
screen_write_start(&ctx, NULL, centre);
screen_write_start(&ctx, centre);
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
screen_write_stop(&ctx);
format_draw_none(octx, available, ocx, ocy, left, centre,
right, frs);
right, abs_centre, frs);
return;
}
@@ -387,23 +411,34 @@ format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx,
format_draw_put_list(octx, ocx, ocy, middle - width_list / 2,
width_list, list, list_left, list_right, focus_start, focus_end,
frs);
/*
* Write abs_centre in the perfect centre of all horizontal space.
*/
if (width_abs_centre > available)
width_abs_centre = available;
format_draw_put(octx, ocx, ocy, abs_centre, frs,
(available - width_abs_centre) / 2,
0,
width_abs_centre);
}
/* Draw format with list on the right. */
static void
format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct screen *list, struct screen *list_left, struct screen *list_right,
struct screen *after, int focus_start, int focus_end,
struct format_ranges *frs)
struct screen *abs_centre, struct screen *list,
struct screen *list_left, struct screen *list_right, struct screen *after,
int focus_start, int focus_end, struct format_ranges *frs)
{
u_int width_left, width_centre, width_right;
u_int width_list, width_after;
u_int width_list, width_after, width_abs_centre;
struct screen_write_ctx ctx;
width_left = left->cx;
width_centre = centre->cx;
width_right = right->cx;
width_abs_centre = abs_centre->cx;
width_list = list->cx;
width_after = after->cx;
@@ -430,12 +465,12 @@ format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx,
/* If there is no list left, pass off to the no list function. */
if (width_list == 0) {
screen_write_start(&ctx, NULL, right);
screen_write_start(&ctx, right);
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
screen_write_stop(&ctx);
format_draw_none(octx, available, ocx, ocy, left, centre,
right, frs);
right, abs_centre, frs);
return;
}
@@ -483,6 +518,130 @@ format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx,
format_draw_put_list(octx, ocx, ocy, available - width_list -
width_after, width_list, list, list_left, list_right, focus_start,
focus_end, frs);
/*
* Write abs_centre in the perfect centre of all horizontal space.
*/
if (width_abs_centre > available)
width_abs_centre = available;
format_draw_put(octx, ocx, ocy, abs_centre, frs,
(available - width_abs_centre) / 2,
0,
width_abs_centre);
}
static void
format_draw_absolute_centre(struct screen_write_ctx *octx, u_int available,
u_int ocx, u_int ocy, struct screen *left, struct screen *centre,
struct screen *right, struct screen *abs_centre, struct screen *list,
struct screen *list_left, struct screen *list_right, struct screen *after,
int focus_start, int focus_end, struct format_ranges *frs)
{
u_int width_left, width_centre, width_right, width_abs_centre;
u_int width_list, width_after, middle, abs_centre_offset;
width_left = left->cx;
width_centre = centre->cx;
width_right = right->cx;
width_abs_centre = abs_centre->cx;
width_list = list->cx;
width_after = after->cx;
/*
* Trim first centre, then the right, then the left.
*/
while (width_left +
width_centre +
width_right > available) {
if (width_centre > 0)
width_centre--;
else if (width_right > 0)
width_right--;
else
width_left--;
}
/*
* We trim list after and abs_centre independently, as we are drawing
* them over the rest. Trim first the list, then after the list, then
* abs_centre.
*/
while (width_list + width_after + width_abs_centre > available) {
if (width_list > 0)
width_list--;
else if (width_after > 0)
width_after--;
else
width_abs_centre--;
}
/* Write left at 0. */
format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
/* Write right at available - width_right. */
format_draw_put(octx, ocx, ocy, right, frs,
available - width_right,
right->cx - width_right,
width_right);
/*
* Keep writing centre at the relative centre. Only the list is written
* in the absolute centre of the horizontal space.
*/
middle = (width_left + ((available - width_right) - width_left) / 2);
/*
* Write centre at
* middle - width_centre.
*/
format_draw_put(octx, ocx, ocy, centre, frs,
middle - width_centre,
0,
width_centre);
/*
* If there is no focus given, keep the centre in focus.
*/
if (focus_start == -1 || focus_end == -1)
focus_start = focus_end = list->cx / 2;
/*
* We centre abs_centre and the list together, so their shared centre is
* in the perfect centre of horizontal space.
*/
abs_centre_offset = (available - width_list - width_abs_centre) / 2;
/*
* Write abs_centre before the list.
*/
format_draw_put(octx, ocx, ocy, abs_centre, frs, abs_centre_offset,
0, width_abs_centre);
abs_centre_offset += width_abs_centre;
/*
* Draw the list in the absolute centre
*/
format_draw_put_list(octx, ocx, ocy, abs_centre_offset, width_list,
list, list_left, list_right, focus_start, focus_end, frs);
abs_centre_offset += width_list;
/*
* Write after at the end of the centre
*/
format_draw_put(octx, ocx, ocy, after, frs, abs_centre_offset, 0,
width_after);
}
/* Draw multiple characters. */
static void
format_draw_many(struct screen_write_ctx *ctx, struct style *sy, char ch,
u_int n)
{
u_int i;
utf8_set(&sy->gc.data, ch);
for (i = 0; i < n; i++)
screen_write_cell(ctx, &sy->gc);
}
/* Draw a format to a screen. */
@@ -493,6 +652,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
enum { LEFT,
CENTRE,
RIGHT,
ABSOLUTE_CENTRE,
LIST,
LIST_LEFT,
LIST_RIGHT,
@@ -501,6 +661,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
const char *names[] = { "LEFT",
"CENTRE",
"RIGHT",
"ABSOLUTE_CENTRE",
"LIST",
"LIST_LEFT",
"LIST_RIGHT",
@@ -508,12 +669,17 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
size_t size = strlen(expanded);
struct screen *os = octx->s, s[TOTAL];
struct screen_write_ctx ctx[TOTAL];
u_int ocx = os->cx, ocy = os->cy, i, width[TOTAL];
u_int map[] = { LEFT, LEFT, CENTRE, RIGHT };
u_int ocx = os->cx, ocy = os->cy, n, i, width[TOTAL];
u_int map[] = { LEFT,
LEFT,
CENTRE,
RIGHT,
ABSOLUTE_CENTRE };
int focus_start = -1, focus_end = -1;
int list_state = -1;
int list_state = -1, fill = -1, even;
enum style_align list_align = STYLE_ALIGN_DEFAULT;
struct style sy;
struct grid_cell gc, current_default;
struct style sy, saved_sy;
struct utf8_data *ud = &sy.gc.data;
const char *cp, *end;
enum utf8_state more;
@@ -522,7 +688,8 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
struct format_ranges frs;
struct style_range *sr;
style_set(&sy, base);
memcpy(&current_default, base, sizeof current_default);
style_set(&sy, &current_default);
TAILQ_INIT(&frs);
log_debug("%s: %s", __func__, expanded);
@@ -533,8 +700,8 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
*/
for (i = 0; i < TOTAL; i++) {
screen_init(&s[i], size, 1, 0);
screen_write_start(&ctx[i], NULL, &s[i]);
screen_write_clearendofline(&ctx[i], base->bg);
screen_write_start(&ctx[i], &s[i]);
screen_write_clearendofline(&ctx[i], current_default.bg);
width[i] = 0;
}
@@ -544,7 +711,39 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
*/
cp = expanded;
while (*cp != '\0') {
if (cp[0] != '#' || cp[1] != '[') {
/* Handle sequences of #. */
if (cp[0] == '#' && cp[1] != '[' && cp[1] != '\0') {
for (n = 1; cp[n] == '#'; n++)
/* nothing */;
even = ((n % 2) == 0);
if (cp[n] != '[') {
cp += n;
if (even)
n = (n / 2);
else
n = (n / 2) + 1;
width[current] += n;
format_draw_many(&ctx[current], &sy, '#', n);
continue;
}
if (even)
cp += (n + 1);
else
cp += (n - 1);
if (sy.ignore)
continue;
format_draw_many(&ctx[current], &sy, '#', n / 2);
width[current] += (n / 2);
if (even) {
utf8_set(ud, '[');
screen_write_cell(&ctx[current], &sy.gc);
width[current]++;
}
continue;
}
/* Is this not a style? */
if (cp[0] != '#' || cp[1] != '[' || sy.ignore) {
/* See if this is a UTF-8 character. */
if ((more = utf8_open(ud, *cp)) == UTF8_MORE) {
while (*++cp != '\0' && more == UTF8_MORE)
@@ -564,7 +763,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
cp++;
}
/* Draw the cell to th current screen. */
/* Draw the cell to the current screen. */
screen_write_cell(&ctx[current], &sy.gc);
width[current] += ud->width;
continue;
@@ -580,7 +779,8 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
goto out;
}
tmp = xstrndup(cp + 2, end - (cp + 2));
if (style_parse(&sy, base, tmp) != 0) {
style_copy(&saved_sy, &sy);
if (style_parse(&sy, &current_default, tmp) != 0) {
log_debug("%s: invalid style '%s'", __func__, tmp);
free(tmp);
cp = end + 1;
@@ -590,6 +790,20 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
style_tostring(&sy));
free(tmp);
/* If this style has a fill colour, store it for later. */
if (sy.fill != 8)
fill = sy.fill;
/* If this style pushed or popped the default, update it. */
if (sy.default_type == STYLE_DEFAULT_PUSH) {
memcpy(&current_default, &saved_sy.gc,
sizeof current_default);
sy.default_type = STYLE_DEFAULT_BASE;
} else if (sy.default_type == STYLE_DEFAULT_POP) {
memcpy(&current_default, base, sizeof current_default);
sy.default_type = STYLE_DEFAULT_BASE;
}
/* Check the list state. */
switch (sy.list) {
case STYLE_LIST_ON:
@@ -711,33 +925,51 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
fr->argument, names[fr->index], fr->start, fr->end);
}
/* Clear the available area. */
if (fill != -1) {
memcpy(&gc, &grid_default_cell, sizeof gc);
gc.bg = fill;
for (i = 0; i < available; i++)
screen_write_putc(octx, &gc, ' ');
}
/*
* Draw the screens. How they are arranged depends on where the list
* appearsq.
* appears.
*/
switch (list_align) {
case STYLE_ALIGN_DEFAULT:
/* No list. */
format_draw_none(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &frs);
&s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &frs);
break;
case STYLE_ALIGN_LEFT:
/* List is part of the left. */
format_draw_left(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
&s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
&s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST],
&s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER],
focus_start, focus_end, &frs);
break;
case STYLE_ALIGN_CENTRE:
/* List is part of the centre. */
format_draw_centre(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
&s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
&s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST],
&s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER],
focus_start, focus_end, &frs);
break;
case STYLE_ALIGN_RIGHT:
/* List is part of the right. */
format_draw_right(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
&s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
&s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST],
&s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER],
focus_start, focus_end, &frs);
break;
case STYLE_ALIGN_ABSOLUTE_CENTRE:
/* List is in the centre of the entire horizontal space. */
format_draw_absolute_centre(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &s[ABSOLUTE_CENTRE], &s[LIST],
&s[LIST_LEFT], &s[LIST_RIGHT], &s[AFTER],
focus_start, focus_end, &frs);
break;
}
@@ -770,16 +1002,36 @@ u_int
format_width(const char *expanded)
{
const char *cp, *end;
u_int width = 0;
u_int n, width = 0;
struct utf8_data ud;
enum utf8_state more;
cp = expanded;
while (*cp != '\0') {
if (cp[0] == '#' && cp[1] == '[') {
if (*cp == '#') {
for (n = 1; cp[n] == '#'; n++)
/* nothing */;
if (cp[n] != '[') {
width += n;
cp += n;
continue;
}
width += (n / 2); /* one for each ## */
if ((n % 2) == 0) {
/*
* An even number of #s means that all #s are
* escaped, so not a style.
*/
width++; /* one for the [ */
cp += (n + 1);
continue;
}
cp += (n - 1); /* point to the [ */
end = format_skip(cp + 2, "]");
if (end == NULL)
return 0;
return (0);
cp = end + 1;
} else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) {
while (*++cp != '\0' && more == UTF8_MORE)
@@ -791,24 +1043,63 @@ format_width(const char *expanded)
} else if (*cp > 0x1f && *cp < 0x7f) {
width++;
cp++;
}
} else
cp++;
}
return (width);
}
/* Trim on the left, taking #[] into account. */
/*
* Trim on the left, taking #[] into account. Note, we copy the whole set of
* unescaped #s, but only add their escaped size to width. This is because the
* format_draw function will actually do the escaping when it runs
*/
char *
format_trim_left(const char *expanded, u_int limit)
{
char *copy, *out;
const char *cp = expanded, *end;
u_int width = 0;
u_int even, n, width = 0;
struct utf8_data ud;
enum utf8_state more;
out = copy = xmalloc(strlen(expanded) + 1);
out = copy = xcalloc(1, strlen(expanded) + 1);
while (*cp != '\0') {
if (cp[0] == '#' && cp[1] == '[') {
if (width >= limit)
break;
if (*cp == '#') {
for (end = cp + 1; *end == '#'; end++)
/* nothing */;
n = end - cp;
if (*end != '[') {
if (n > limit - width)
n = limit - width;
memcpy(out, cp, n);
out += n;
width += n;
cp = end;
continue;
}
even = ((n % 2) == 0);
n /= 2;
if (n > limit - width)
n = limit - width;
width += n;
n *= 2;
memcpy(out, cp, n);
out += n;
if (even) {
if (width + 1 <= limit) {
*out++ = '[';
width++;
}
cp = end + 1;
continue;
}
cp = end - 1;
end = format_skip(cp + 2, "]");
if (end == NULL)
break;
@@ -824,8 +1115,10 @@ format_trim_left(const char *expanded, u_int limit)
out += ud.size;
}
width += ud.width;
} else
} else {
cp -= ud.have;
cp++;
}
} else if (*cp > 0x1f && *cp < 0x7f) {
if (width + 1 <= limit)
*out++ = *cp;
@@ -844,7 +1137,7 @@ format_trim_right(const char *expanded, u_int limit)
{
char *copy, *out;
const char *cp = expanded, *end;
u_int width = 0, total_width, skip;
u_int width = 0, total_width, skip, old_n, even, n;
struct utf8_data ud;
enum utf8_state more;
@@ -853,12 +1146,64 @@ format_trim_right(const char *expanded, u_int limit)
return (xstrdup(expanded));
skip = total_width - limit;
out = copy = xmalloc(strlen(expanded) + 1);
out = copy = xcalloc(1, strlen(expanded) + 1);
while (*cp != '\0') {
if (cp[0] == '#' && cp[1] == '[') {
if (*cp == '#') {
for (end = cp + 1; *end == '#'; end++)
/* nothing */;
old_n = n = end - cp;
if (*end != '[') {
if (width <= skip) {
if (skip - width >= n)
n = 0;
else
n -= (skip - width);
}
if (n != 0) {
memcpy(out, cp, n);
out += n;
}
/*
* The width always increases by the full
* amount even if we can't copy anything yet.
*/
width += old_n;
cp = end;
continue;
}
even = ((n % 2) == 0);
n /= 2;
if (width <= skip) {
if (skip - width >= n)
n = 0;
else
n -= (skip - width);
}
if (n != 0) {
/*
* Copy the full amount because it hasn't been
* escaped yet.
*/
memcpy(out, cp, old_n);
out += old_n;
}
cp += old_n;
width += (old_n / 2) - even;
if (even) {
if (width > skip)
*out++ = '[';
width++;
continue;
}
cp = end - 1;
end = format_skip(cp + 2, "]");
if (end == NULL)
if (end == NULL) {
break;
}
memcpy(out, cp, end + 1 - cp);
out += (end + 1 - cp);
cp = end + 1;
@@ -871,8 +1216,10 @@ format_trim_right(const char *expanded, u_int limit)
out += ud.size;
}
width += ud.width;
} else
} else {
cp -= ud.have;
cp++;
}
} else if (*cp > 0x1f && *cp < 0x7f) {
if (width >= skip)
*out++ = *cp;

4054
format.c

File diff suppressed because it is too large Load Diff

89
fuzz/input-fuzzer.c Normal file
View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 2020 Sergey Nizovtsev <snizovtsev@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 <stddef.h>
#include <assert.h>
#include "tmux.h"
#define FUZZER_MAXLEN 512
#define PANE_WIDTH 80
#define PANE_HEIGHT 25
struct event_base *libevent;
int
LLVMFuzzerTestOneInput(const unsigned char *data, size_t size)
{
struct bufferevent *vpty[2];
struct window *w;
struct window_pane *wp;
int error;
/*
* Since AFL doesn't support -max_len paramenter we have to
* discard long inputs manually.
*/
if (size > FUZZER_MAXLEN)
return 0;
w = window_create(PANE_WIDTH, PANE_HEIGHT, 0, 0);
wp = window_add_pane(w, NULL, 0, 0);
bufferevent_pair_new(libevent, BEV_OPT_CLOSE_ON_FREE, vpty);
wp->ictx = input_init(wp, vpty[0]);
window_add_ref(w, __func__);
input_parse_buffer(wp, (u_char*) data, size);
while (cmdq_next(NULL) != 0)
;
error = event_base_loop(libevent, EVLOOP_NONBLOCK);
if (error == -1)
errx(1, "event_base_loop failed");
assert(w->references == 1);
window_remove_ref(w, __func__);
bufferevent_free(vpty[0]);
bufferevent_free(vpty[1]);
return 0;
}
int
LLVMFuzzerInitialize(__unused int *argc, __unused char ***argv)
{
const struct options_table_entry *oe;
global_environ = environ_create();
global_options = options_create(NULL);
global_s_options = options_create(NULL);
global_w_options = options_create(NULL);
for (oe = options_table; oe->name != NULL; oe++) {
if (oe->scope & OPTIONS_TABLE_SERVER)
options_default(global_options, oe);
if (oe->scope & OPTIONS_TABLE_SESSION)
options_default(global_s_options, oe);
if (oe->scope & OPTIONS_TABLE_WINDOW)
options_default(global_w_options, oe);
}
libevent = osdep_event_init();
options_set_number(global_w_options, "monitor-bell", 0);
options_set_number(global_w_options, "allow-rename", 1);
options_set_number(global_options, "set-clipboard", 2);
return 0;
}

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