294 Commits
2.6 ... 2.8

Author SHA1 Message Date
Nicholas Marriott
01918cb017 tmux 2.8. 2018-10-17 19:29:35 +01:00
Nicholas Marriott
aa6e6fa0f2 2.8. 2018-08-17 11:45:40 +01:00
Nicholas Marriott
9bdbe171b7 2.8-rc. 2018-08-17 11:31:16 +01:00
Thomas Adam
98a3c98c28 Merge branch 'obsd-master' 2018-08-17 11:20:20 +01:00
Nicholas Marriott
de2ddddd60 Add a full stop. 2018-08-17 10:30:04 +01:00
nicm
a9ffb56b65 Add the KEYC_XTERM flag to all function keys that imply a modifier so
that they are correctly translated into xterm(1)-style keys. GitHub
issue 1437.
2018-08-16 14:04:03 +00:00
nicm
14b97fc889 Add size to arguments struct too. 2018-08-14 11:38:05 +00:00
nicm
d0a600ccaa Some tidying, use a struct for arguments (there will be more later) and
add a helper function.
2018-08-14 11:31:34 +00:00
Thomas Adam
a368548645 Merge branch 'obsd-master' 2018-08-10 11:41:07 +01:00
Nicholas Marriott
13fe06a459 Update CHANGES. 2018-08-10 10:21:40 +01:00
nicm
87e87030fe Whoops, didn't mean to commit this. 2018-08-09 09:54:22 +00:00
nicm
a5ef1f2ed6 Bump the UTF-8 character array up to 18 to allow for more combining
characters (some languages use up to five). This size doesn't make as
much difference now that UTF-8 goes into an extended cell. GitHub issue
1430.
2018-08-09 09:53:44 +00:00
nicm
f5d7a80272 calloc the mode data instead of malloc and initialize everything. 2018-08-05 08:59:30 +00:00
Thomas Adam
33f9b316a3 Merge branch 'obsd-master' 2018-08-02 21:02:25 +01:00
nicm
d6ff630498 Log command arguments. 2018-08-02 18:35:21 +00:00
Thomas Adam
eceaa9a493 Merge branch 'obsd-master' 2018-08-02 15:02:25 +01:00
Thomas Adam
2e19a5ecb9 Merge branch 'obsd-master' 2018-08-02 13:02:26 +01:00
nicm
fb1f0fee5a session_groups can be static also. 2018-08-02 11:56:12 +00:00
nicm
6048b0f483 Make key trees and some other bits static. 2018-08-02 11:44:07 +00:00
nicm
f12b857415 Minor tidying. 2018-08-02 11:18:34 +00:00
Thomas Adam
79bdca4638 Merge branch 'obsd-master' 2018-08-02 11:02:25 +01:00
nicm
21f8ac2766 Make display-panes block the client until a pane is chosen or it times out. 2018-08-02 07:55:16 +00:00
Thomas Adam
89b56c3451 Merge branch 'obsd-master' 2018-08-01 17:02:25 +01:00
nicm
fe7486d43b Initialize new lineflag member. 2018-08-01 15:22:40 +00:00
Thomas Adam
400b807d75 Merge branch 'obsd-master' 2018-07-31 17:02:31 +01:00
nicm
5f07da6227 Do not leak path or use it after free. 2018-07-31 13:06:44 +00:00
Thomas Adam
7eb3ef66e5 Merge branch 'obsd-master' 2018-07-31 13:02:25 +01:00
nicm
82776c456e Move struct screen_sel into screen.c and tidy up members that are only
used by copy mode.
2018-07-31 11:49:26 +00:00
nicm
80bdd89856 Clear history on RIS like most other terminals do. 2018-07-31 10:32:19 +00:00
Thomas Adam
ed6327c87b Merge branch 'obsd-master' 2018-07-30 13:02:25 +01:00
nicm
b21a710de7 Remove a leftover unused struct. 2018-07-30 11:24:55 +00:00
Thomas Adam
aa32457772 Merge branch 'obsd-master' 2018-07-23 21:02:25 +01:00
kn
5c78b48cdf Point to glob in section 7 for the actual list of special characters instead
the C API in section 3.

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

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

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

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

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

tmux can use the RGB flag to detect RGB colour support (keeping the old
Tc extension for backwards compatibility for now). However, as we still
want to send 256 colour information unchanged when possible, the new
setaf/setab are awkward. So when RGB is present, reserve setaf/setab
only for ANSI colours and use the escape sequences directly for 256 and
RGB colours. (To my knowledge no recent terminal uses unusual escape
sequences for these in any case.)
2018-02-04 10:10:39 +00:00
Nicholas Marriott
4e4c500879 Add more to TODO. 2018-01-29 12:46:52 +00:00
Nicholas Marriott
0407d847a4 Add to TODO. 2018-01-29 12:44:31 +00:00
Thomas Adam
19afd842bf Merge branch 'obsd-master' 2018-01-18 16:02:25 +00:00
nicm
17d4c39f24 Discard all but the last line when reading from a #() command - the
callback is just going to be fired again straight away to go through all
the lines, it is better just to use the last one straight away.
2018-01-18 14:28:11 +00:00
Thomas Adam
d9e740f86d Merge branch 'obsd-master' 2018-01-18 08:02:30 +00:00
nicm
c9037fde1c Remove unused hooks_run function, from Thomas Adam. 2018-01-18 07:10:53 +00:00
Thomas Adam
84ddc72744 Merge branch 'obsd-master' 2018-01-17 11:26:10 +00:00
nicm
75842bfe66 Fix drawing of ACS characters (they need to go character-at-a-time),
accidentally broken in last commit.
2018-01-16 17:03:18 +00:00
nicm
5849b73b81 Add -I to pipe-pane to connect pane stdin as well as stdout, suggested
by Kristof Kovacs in GitHub issue 1186.
2018-01-16 09:00:38 +00:00
Nicholas Marriott
58e9d12f23 msys is apparently a cygwin variant that doesn't say it is cygwin... 2018-01-16 08:29:15 +00:00
nicm
53b25635da Another redundant check, GitHub issue 1219. 2018-01-15 15:30:03 +00:00
nicm
481703d669 Some unused code, GitHub issue 1219. 2018-01-15 15:27:03 +00:00
nicm
b0c1cefeda Do not collect top-bit-set characters in case they need to be replaced. 2018-01-12 16:43:47 +00:00
nicm
2c5a6f9af5 Simplify character replacement on non-UTF-8 terminals and make a common
function.
2018-01-12 16:41:00 +00:00
nicm
c03565611e Simplify UTF-8 states down into one state. 2018-01-12 16:32:12 +00:00
nicm
f32fd2df69 Improve error message if creating socket parent directory fails, from
Thomas Adam for GitHub issue 1215.
2018-01-12 10:22:02 +00:00
nicm
829fe38ab1 Improve logging for layout cells. 2018-01-12 10:16:03 +00:00
Thomas Adam
06684c93de Merge branch 'obsd-master' 2018-01-01 12:01:13 +00:00
nicm
d17c90583a Prefer PWD for current directory if present in client, from Wei Zhao in
GitHub issue 1183.
2018-01-01 11:19:08 +00:00
nicm
fe26f977e6 Add C-g at command prompt for emacs people, GitHub issue 1213. 2018-01-01 11:03:54 +00:00
Thomas Adam
6e99a2f4bb Merge branch 'obsd-master' 2017-12-31 22:01:15 +00:00
nicm
c9896d9554 Initialize the size of new panes created by the even-* layout correctly;
reported by Andreas Kahari and Anton Lindqvist.
2017-12-31 20:00:44 +00:00
Thomas Adam
ad417f6eb7 Merge branch 'obsd-master' 2017-12-28 14:01:14 +00:00
nicm
299c552e33 Redrawing status is needed after changing window flags or title does not
update if status line is off, GitHub issue 1191.
2017-12-28 12:10:50 +00:00
Thomas Adam
cd46568ebe Merge branch 'obsd-master' 2017-12-27 14:43:20 +00:00
nicm
937f8ed095 Draw command prompt correctly with status line off. 2017-12-27 13:55:42 +00:00
Nicholas Marriott
6ce8fe0537 Still need to globfree on failure. 2017-12-27 13:54:37 +00:00
nicm
c363c236aa Fix memory leak in screen_redraw_make_pane_status. 2017-12-22 23:16:41 +00:00
Thomas Adam
e19df0e869 Merge branch 'obsd-master' 2017-12-22 12:01:22 +00:00
nicm
7ba5ad4cfb Do not try to set default value on user options (they don't have one),
from Charles Howard in GitHub issue 1161.
2017-12-22 10:18:51 +00:00
nicm
5c82432200 Remove duplicate WheelUp/WheelDown entries in list, GitHub issue 1184. 2017-12-22 10:16:36 +00:00
Thomas Adam
74ecc866cf Merge branch 'obsd-master' 2017-12-19 16:01:20 +00:00
nicm
b20a00f93e Report better error from server when socket create fails, GitHub issue
1201.
2017-12-19 15:00:39 +00:00
Thomas Adam
641a885af8 Merge branch 'obsd-master' 2017-12-19 00:01:18 +00:00
nicm
62144b9f57 Do not try to put more in command message than will fit when sending
(the server will treat as a fatal error). GitHub issue 1200.
2017-12-18 22:13:36 +00:00
Thomas Adam
43a1294ed9 Merge branch 'obsd-master' 2017-12-18 14:01:18 +00:00
nicm
58f6456af7 Remove unused variable from Thomas Adam. 2017-12-18 12:39:34 +00:00
Thomas Adam
2c6af068d7 Merge branch 'obsd-master' 2017-11-17 12:01:17 +00:00
nicm
695dc5a153 Allow formats in selectp -T, from Thomas Adam. 2017-11-17 09:52:18 +00:00
Thomas Adam
5fddddbe21 Merge branch 'obsd-master' 2017-11-16 12:01:18 +00:00
nicm
e5ae9dd53d Add -and-cancel variants for scrolling commands to exit copy mode when
the bottom is reached, from Stephen Hicks.
2017-11-16 11:16:15 +00:00
Thomas Adam
102df8dc80 Merge branch 'obsd-master' 2017-11-15 22:01:22 +00:00
Nicholas Marriott
e58d16b2df Add to CHANGES. 2017-11-15 20:14:49 +00:00
Thomas Adam
e755ca37b3 Merge branch 'obsd-master' 2017-11-15 20:01:22 +00:00
nicm
3b649d2fcd Add a common function for spreading out cells and use it for the two
even layouts and to add a -E flag to select-layout to spread out cells
evenly without changing parent cells.
2017-11-15 19:59:27 +00:00
nicm
533a5719c5 Completely rewrite the reflow code to correctly handle double width
characters (previously they were not accounted for).
2017-11-15 19:21:24 +00:00
nicm
aeda2e5808 If there is a double width character at the very end of the line with
not enough room to draw it, just leave it out.
2017-11-15 19:18:57 +00:00
Thomas Adam
392da897ff Merge branch 'obsd-master' 2017-11-13 14:01:18 +00:00
nicm
d81fa579c3 When searching in copy mode, do not scroll if the result is already on
screen. GitHub issue 1150.
2017-11-13 11:49:11 +00:00
Thomas Adam
515da63d2b Merge branch 'obsd-master' 2017-11-10 00:01:19 +00:00
nicm
384736e955 If we successfully change the directory, set PWD too to give the shell a
hint in case of symlinks.
2017-11-09 23:02:13 +00:00
Thomas Adam
6f3b6c8d92 Merge branch 'obsd-master' 2017-11-03 18:01:21 +00:00
nicm
a2681ffcee Clear key properly if on space with nothing in it. 2017-11-03 17:11:20 +00:00
nicm
50a5f84cb4 Support mouse on preview in tree mode. 2017-11-03 17:02:33 +00:00
Thomas Adam
24c387206c Merge branch 'obsd-master' 2017-11-03 16:01:17 +00:00
nicm
ba93a647f1 Change mouse in modes so that one click moves the cursor and a double
click chooses the line.
2017-11-03 14:23:44 +00:00
Thomas Adam
e1606172dd Merge branch 'obsd-master' 2017-11-03 00:01:20 +00:00
Thomas Adam
c9ec33d0d0 Merge branch 'obsd-master' 2017-11-02 22:01:20 +00:00
nicm
43264dfbf4 Make the mode draw function use the parent screen directly rather than
its own to avoid copying twice.
2017-11-02 22:00:42 +00:00
nicm
8d37f699ad Add a "fast" version of screen_write_copy for tree mode that doesn't do
all the checks and selection and marking stuff needed for copy mode.
2017-11-02 21:29:17 +00:00
Thomas Adam
8c29f7413b Merge branch 'obsd-master' 2017-11-02 20:01:26 +00:00
nicm
17655e5ba6 Format for group list of "other sessions" is a bit weird, just list all
the sessions in the group.
2017-11-02 18:52:05 +00:00
nicm
95850e1aca Tweak previous slightly so that current session is chosen if it is in
the group rather than first.
2017-11-02 18:43:51 +00:00
nicm
c1f62f1fde Only show the first member of session groups in tree mode (-G flag
disables).
2017-11-02 18:27:35 +00:00
nicm
3887d95bca There is no point in reflowing panes which have not changed width. 2017-11-02 18:26:38 +00:00
Thomas Adam
cf782c4f54 Merge branch 'obsd-master' 2017-10-26 10:01:18 +01:00
nicm
e91e8a2a6c Fix crash exiting command prompt (from Alex Maese in GitHub issue 1139)
and a man page tweak from jmc.
2017-10-26 08:17:12 +00:00
Thomas Adam
d36ac3db15 Merge branch 'obsd-master' 2017-10-25 18:01:17 +01:00
nicm
be4c01697c Note that notifications are also hooks. 2017-10-25 15:20:10 +00:00
Thomas Adam
0072bc65e6 Merge branch 'obsd-master' 2017-10-25 16:01:22 +01:00
Nicholas Marriott
37f83adca8 Update CHANGES. 2017-10-25 15:26:54 +01:00
nicm
578a63bbc9 Default allow-rename to off because it is ridiculous that applications
are even able to do this and confusing when they do.
2017-10-25 14:14:52 +00:00
Thomas Adam
6b83ca0077 Merge branch 'obsd-master' 2017-10-25 14:01:26 +01:00
nicm
78ae4ee82c h/l keys for expand and collapse. 2017-10-25 12:13:20 +00:00
Nicholas Marriott
d6edd06749 Merge branch 'master' of github.com:tmux/tmux 2017-10-25 12:29:23 +01:00
Nicholas Marriott
6e8d29e9a2 Update TODO. 2017-10-25 12:29:10 +01:00
nicm
8dd776106d Add P key to paste tagged in buffer mode, and trim some code that should
no longer be necessary.
2017-10-25 11:26:11 +00:00
Thomas Adam
e85213a944 Merge branch 'obsd-master' 2017-10-22 15:47:07 +01:00
nicm
26f1857154 Use window_pane_index() when drawing pane numbers (so pane-base-index is
applied), from Thomas Adam. GitHub issue 1125.
2017-10-22 13:16:54 +00:00
Nicholas Marriott
f7a037ba26 Apparently vim(1) now has syntax highlighting built in, GitHub issue 1124. 2017-10-22 14:14:14 +01:00
Thomas Adam
61114c6c72 Merge branch 'obsd-master' 2017-10-20 16:01:17 +01:00
nicm
d3e8709ab5 Clear status line with spaces again so reverse works, spotted by sthen. 2017-10-20 13:10:54 +00:00
Nicholas Marriott
37531673a3 Need compat for queue.h. 2017-10-20 13:26:54 +01:00
Thomas Adam
31901e3c07 Merge branch 'obsd-master'
Conflicts:
	server-fn.c
2017-10-20 12:36:29 +01:00
Nicholas Marriott
a34de2e378 Save and restore LIBS when checking for b64_ntop, reported by Ralf Friedl. 2017-10-17 10:35:35 +01:00
nicm
2f6935a630 Infrastructure for drawing status lines of more than one line in height,
still only one is allowed but this lets tmux draw bigger ones.
2017-10-16 19:30:53 +00:00
nicm
a5fd5782f8 Show exit status and time in the remain-on-exit pane text, mostly from
Timo Boettcher in GitHub issue 1103.
2017-10-12 11:32:27 +00:00
Nicholas Marriott
fb02df66cc Merge branch 'master' of github.com:tmux/tmux 2017-10-12 11:56:32 +01:00
Nicholas Marriott
d10def5b0b Check missed during merge. 2017-10-12 11:56:06 +01:00
Thomas Adam
2357bfb254 Merge branch 'obsd-master' 2017-10-11 16:01:17 +01:00
Thomas Adam
87babfa473 Merge branch 'obsd-master' 2017-10-11 14:01:17 +01:00
nicm
eb9839fd32 Box around label in preview. 2017-10-11 12:57:49 +00:00
nicm
6e5121be7e Clear to end of line properly with UTF-8 present. 2017-10-11 11:26:58 +00:00
Thomas Adam
4efd41f3af Merge branch 'obsd-master' 2017-10-11 10:01:19 +01:00
nicm
99351c9cae Add C-n and C-p keys for tree mode, and choose the right initial line
when no panes.
2017-10-11 08:08:16 +00:00
Nicholas Marriott
60074a6bc6 Merge branch 'master' of github.com:tmux/tmux 2017-10-11 08:03:55 +01:00
Nicholas Marriott
a3967de9a5 Include headers if found regardless of forkpty. 2017-10-11 08:03:31 +01:00
Thomas Adam
044019d9d6 Merge branch 'obsd-master' 2017-10-09 14:01:16 +01:00
nicm
db44151a37 kind should be S-Down not S-Up. 2017-10-09 11:35:35 +00:00
Thomas Adam
ceab7154d4 Merge branch 'obsd-master' 2017-10-08 18:40:41 +01:00
nicm
0b4c408168 Fix description of history_size, from Campbell Barton. 2017-10-08 16:45:01 +00:00
Thomas Adam
f069c0ba09 Merge branch 'obsd-master' 2017-10-06 20:01:17 +01:00
nicm
9c4caf49a2 Support %else in config files to match %if, from Brad Town in GitHub
issue 1071.
2017-10-06 18:02:30 +00:00
Thomas Adam
2be01ab4ec Merge branch 'obsd-master' 2017-10-06 13:33:32 +01:00
nicm
b462063cd5 Add -- to some key bindings so leading -s work. 2017-10-05 13:43:34 +00:00
Nicholas Marriott
8aaf86a6ea Merge branch '2.6-rc' 2017-10-05 14:39:33 +01:00
nicm
88517ceebb Add support for the xterm(1) title stack, from Brad Town, GitHub issue
1075.
2017-10-05 13:29:18 +00:00
nicm
6a292f09ba When writing batches of characters to the screen, we need to clear
padding or later UTF-8 characters could be displayed incorrectly. GitHub
issue 1090.
2017-10-05 08:12:24 +00:00
Thomas Adam
ff526e43de Merge branch 'obsd-master' 2017-09-22 12:01:13 +01:00
nicm
d563aa7c7b Initialize alerts timer event where it is used, avoids crash with new windows. 2017-09-22 09:04:46 +00:00
Thomas Adam
ae5a62a514 Merge branch 'obsd-master' 2017-09-13 10:01:10 +01:00
nicm
c86d83f835 Remove unused (always 1) arguments from some functions, from Daniel
Mueller in GitHub issue 1073.
2017-09-13 07:31:07 +00:00
Thomas Adam
9a1b9f15a1 Merge branch 'obsd-master' 2017-09-11 22:01:10 +01:00
nicm
af2c7ce646 Check event is initialized before delete; fixes crash reported by
Michael Nickerson in GitHub issue 1068.
2017-09-11 20:11:45 +00:00
Nicholas Marriott
b541a97821 2.6-rc3. 2017-09-11 10:12:25 +01:00
78 changed files with 3605 additions and 1784 deletions

98
CHANGES
View File

@@ -1,3 +1,101 @@
CHANGES FROM 2.7 to 2.8
* Make display-panes block the client until a pane is chosen or it
times out.
* Clear history on RIS like most other terminals do.
* Add an "Any" key to run a command if a key is pressed that is not
bound in the current key table.
* Expand formats in load-buffer and save-buffer.
* Add a rectangle_toggle format.
* Add set-hook -R to run a hook immediately.
* Add README.ja.
* Add pane focus hooks.
* Allow any punctuation as separator for s/x/y not only /.
* Improve resizing with the mouse (fix resizing the wrong pane in some
layouts, and allow resizing multiple panes at the same time).
* Allow , and } to be escaped in formats as #, and #}.
* Add KRB5CCNAME to update-environment.
* Change meaning of -c to display-message so the client is used if it
matches the session given to -t.
* Fixes to : form of SGR.
* Add x and X to choose-tree to kill sessions, windows or panes.
CHANGES FROM 2.6 TO 2.7
* Remove EVENT_* variables from environment on platforms where tmux uses them
so they do not pass on to panes.
* Fixes for hooks at server exit.
* Remove SGR 10 (was equivalent to SGR 0 but no other terminal seems to do
this).
* Expand formats in window and session names.
* Add -Z flag to choose-tree, choose-client, choose-buffer to automatically
zoom the pane when the mode is entered and unzoom when it exits, assuming the
pane is not already zoomed. This is now part of the default key bindings.
* Add C-g to exit modes with emacs keys.
* Add exit-empty option to exit server if no sessions (defaults to on).
* Show if a filter is present in choose modes.
* Add pipe-pane -I to to connect stdin of the child process.
* Performance improvements for reflow.
* Use RGB terminfo(5) capability to detect RGB colour terminals (the existing
Tc extension remains unchanged).
* Support for ISO colon-separated SGR sequences.
* Add select-layout -E to spread panes out evenly (bound to E key).
* Support wide characters properly when reflowing.
* Pass PWD to new panes as a hint to shells, as well as calling chdir().
* Performance improvements for the various choose modes.
* Only show first member of session groups in tree mode (-G flag to choose-tree
to show all).
* Support %else in config files to match %if; from Brad Town in GitHub issue
1071.
* Fix "kind" terminfo(5) capability to be S-Down not S-Up.
* Add a box around the preview label in tree mode.
* Show exit status and time in the remain-on-exit pane text; from Timo
Boettcher in GitHub issue 1103.
* Correctly use pane-base-index in tree mode.
* Change the allow-rename option default to off.
* Support for xterm(1) title stack escape sequences (GitHub issue 1075 from
Brad Town).
* Correctly remove padding cells to fix a UTF-8 display problem (GitHub issue
1090).
CHANGES FROM 2.5 TO 2.6, 05 October 2017
* Add select-pane -T to set pane title.

View File

@@ -6,7 +6,7 @@ CLEANFILES = tmux.1.mdoc tmux.1.man
# Distribution tarball options.
EXTRA_DIST = \
CHANGES README COPYING example_tmux.conf compat/*.[ch] \
CHANGES README README.ja COPYING example_tmux.conf compat/*.[ch] \
osdep-*.c mdoc2man.awk tmux.1
# Preprocessor flags.

11
README
View File

@@ -1,8 +1,8 @@
Welcome to tmux!
tmux is a "terminal multiplexer", it enables a number of terminals (or windows)
to be accessed and controlled from a single terminal. tmux is intended to be a
simple, modern, BSD-licensed alternative to programs such as GNU screen.
tmux is a terminal multiplexer: it enables a number of terminals to be created,
accessed, and controlled from a single screen. tmux may be detached from a
screen and continue running in the background, then later reattached.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.
@@ -43,11 +43,6 @@ the source tree with:
A small example configuration in example_tmux.conf.
A vim(1) syntax file is available at:
https://github.com/ericpruitt/tmux.vim
https://raw.githubusercontent.com/ericpruitt/tmux.vim/master/vim/syntax/tmux.vim
And a bash(1) completion file at:
https://github.com/imomaliev/tmux-bash-completion

62
README.ja Normal file
View File

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

15
TODO
View File

@@ -49,6 +49,7 @@
* improve word and line selection in copy mode (for example when
dragging it should select by word. compare how xterm works. GitHub
issue 682)
* key to search for word under cursor (GitHub issue 1240)
- layout stuff
* way to tag a layout as a number/name
@@ -110,21 +111,23 @@
bind -n DoubleClick3Status confirm-before -p "kill-window #I? (y/n)" kill-window
* respawn -c flag same as neww etc
* marker lines in history (GitHub issue 1042)
* tree mode stuff: predefined filters, tag-all key, ...
* tree mode stuff: make command prompt (:) common code so all modes get it,
predefined filters, tag-all key, ...
* drag panes and windows around to move/swap them in choose mode
- hooks
* more hooks for various things
* finish after hooks for special commands. these do not have a hook at
the moment:
the moment:
attach-session detach-client kill-server respawn-window
swap-window break-pane find-window kill-session rotate-window
switch-client choose-tree if-shell kill-window run-shell
wait-for command-prompt join-pane move-window source-file
confirm-before kill-pane respawn-pane swap-pane
at the moment AFTERHOOK uses current only if target is not valid,
but target is ALWAYS valid - it should use current if no -t flag?
then select-* could use AFTERHOOK
at the moment AFTERHOOK uses current only if target is not valid,
but target is ALWAYS valid - it should use current if no -t flag?
then select-* could use AFTERHOOK
* multiple hooks with the same name?
* finish hooks for notifys
* for session_closed, if no sessions at all, perhaps fake up a
temporary one
temporary one

View File

@@ -200,8 +200,10 @@ alerts_check_bell(struct window *w)
* not check WINLINK_BELL).
*/
s = wl->session;
if (s->curw != wl)
if (s->curw != wl) {
wl->flags |= WINLINK_BELL;
server_status_session(s);
}
if (!alerts_action_applies(wl, "bell-action"))
continue;
notify_winlink("alert-bell", wl);
@@ -234,8 +236,10 @@ alerts_check_activity(struct window *w)
if (wl->flags & WINLINK_ACTIVITY)
continue;
s = wl->session;
if (s->curw != wl)
if (s->curw != wl) {
wl->flags |= WINLINK_ACTIVITY;
server_status_session(s);
}
if (!alerts_action_applies(wl, "activity-action"))
continue;
notify_winlink("alert-activity", wl);
@@ -268,8 +272,10 @@ alerts_check_silence(struct window *w)
if (wl->flags & WINLINK_SILENCE)
continue;
s = wl->session;
if (s->curw != wl)
if (s->curw != wl) {
wl->flags |= WINLINK_SILENCE;
server_status_session(s);
}
if (!alerts_action_applies(wl, "silence-action"))
continue;
notify_winlink("alert-silence", wl);

174
cfg.c
View File

@@ -26,6 +26,17 @@
#include "tmux.h"
/* Condition for %if, %elif, %else and %endif. */
struct cfg_cond {
size_t line; /* line number of %if */
int met; /* condition was met */
int skip; /* skip later %elif/%else */
int saw_else; /* saw a %else */
TAILQ_ENTRY(cfg_cond) entry;
};
TAILQ_HEAD(cfg_conds, cfg_cond);
static char *cfg_file;
int cfg_finished;
static char **cfg_causes;
@@ -101,6 +112,124 @@ start_cfg(void)
cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
}
static int
cfg_check_condition(const char *path, size_t line, const char *p, int *skip)
{
struct format_tree *ft;
char *s;
int result;
while (isspace((u_char)*p))
p++;
if (p[0] == '\0') {
cfg_add_cause("%s:%zu: invalid condition", path, line);
*skip = 1;
return (0);
}
ft = format_create(NULL, NULL, FORMAT_NONE, FORMAT_NOJOBS);
s = format_expand(ft, p);
result = format_true(s);
free(s);
format_free(ft);
*skip = result;
return (result);
}
static void
cfg_handle_if(const char *path, size_t line, struct cfg_conds *conds,
const char *p)
{
struct cfg_cond *cond;
struct cfg_cond *parent = TAILQ_FIRST(conds);
/*
* Add a new condition. If a previous condition exists and isn't
* currently met, this new one also can't be met.
*/
cond = xcalloc(1, sizeof *cond);
cond->line = line;
if (parent == NULL || parent->met)
cond->met = cfg_check_condition(path, line, p, &cond->skip);
else
cond->skip = 1;
cond->saw_else = 0;
TAILQ_INSERT_HEAD(conds, cond, entry);
}
static void
cfg_handle_elif(const char *path, size_t line, struct cfg_conds *conds,
const char *p)
{
struct cfg_cond *cond = TAILQ_FIRST(conds);
/*
* If a previous condition exists and wasn't met, check this
* one instead and change the state.
*/
if (cond == NULL || cond->saw_else)
cfg_add_cause("%s:%zu: unexpected %%elif", path, line);
else if (!cond->skip)
cond->met = cfg_check_condition(path, line, p, &cond->skip);
else
cond->met = 0;
}
static void
cfg_handle_else(const char *path, size_t line, struct cfg_conds *conds)
{
struct cfg_cond *cond = TAILQ_FIRST(conds);
/*
* If a previous condition exists and wasn't met and wasn't already
* %else, use this one instead.
*/
if (cond == NULL || cond->saw_else) {
cfg_add_cause("%s:%zu: unexpected %%else", path, line);
return;
}
cond->saw_else = 1;
cond->met = !cond->skip;
cond->skip = 1;
}
static void
cfg_handle_endif(const char *path, size_t line, struct cfg_conds *conds)
{
struct cfg_cond *cond = TAILQ_FIRST(conds);
/*
* Remove previous condition if one exists.
*/
if (cond == NULL) {
cfg_add_cause("%s:%zu: unexpected %%endif", path, line);
return;
}
TAILQ_REMOVE(conds, cond, entry);
free(cond);
}
static void
cfg_handle_directive(const char *p, const char *path, size_t line,
struct cfg_conds *conds)
{
int n = 0;
while (p[n] != '\0' && !isspace((u_char)p[n]))
n++;
if (strncmp(p, "%if", n) == 0)
cfg_handle_if(path, line, conds, p + n);
else if (strncmp(p, "%elif", n) == 0)
cfg_handle_elif(path, line, conds, p + n);
else if (strcmp(p, "%else") == 0)
cfg_handle_else(path, line, conds);
else if (strcmp(p, "%endif") == 0)
cfg_handle_endif(path, line, conds);
else
cfg_add_cause("%s:%zu: invalid directive: %s", path, line, p);
}
int
load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
{
@@ -108,11 +237,13 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
const char delim[3] = { '\\', '\\', '\0' };
u_int found = 0;
size_t line = 0;
char *buf, *cause1, *p, *q, *s;
char *buf, *cause1, *p, *q;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
int condition = 0;
struct format_tree *ft;
struct cfg_cond *cond, *cond1;
struct cfg_conds conds;
TAILQ_INIT(&conds);
log_debug("loading %s", path);
if ((f = fopen(path, "rb")) == NULL) {
@@ -136,33 +267,12 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
while (q != p && isspace((u_char)*q))
*q-- = '\0';
if (condition != 0 && strcmp(p, "%endif") == 0) {
condition = 0;
if (*p == '%') {
cfg_handle_directive(p, path, line, &conds);
continue;
}
if (strncmp(p, "%if ", 4) == 0) {
if (condition != 0) {
cfg_add_cause("%s:%zu: nested %%if", path,
line);
continue;
}
ft = format_create(NULL, NULL, FORMAT_NONE,
FORMAT_NOJOBS);
s = p + 3;
while (isspace((u_char)*s))
s++;
s = format_expand(ft, s);
if (*s != '\0' && (s[0] != '0' || s[1] != '\0'))
condition = 1;
else
condition = -1;
free(s);
format_free(ft);
continue;
}
if (condition == -1)
cond = TAILQ_FIRST(&conds);
if (cond != NULL && !cond->met)
continue;
cmdlist = cmd_string_parse(p, path, line, &cause1);
@@ -176,8 +286,6 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
}
free(buf);
if (cmdlist == NULL)
continue;
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
if (item != NULL)
cmdq_insert_after(item, new_item);
@@ -189,6 +297,12 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
}
fclose(f);
TAILQ_FOREACH_REVERSE_SAFE(cond, &conds, cfg_conds, entry, cond1) {
cfg_add_cause("%s:%zu: unterminated %%if", path, cond->line);
TAILQ_REMOVE(&conds, cond, entry);
free(cond);
}
return (found);
}

View File

@@ -17,11 +17,10 @@
*/
#include <sys/types.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <errno.h>
#include <event.h>
@@ -278,10 +277,10 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL);
/* Save these before pledge(). */
if ((cwd = getcwd(path, sizeof path)) == NULL) {
if ((cwd = find_home()) == NULL)
cwd = "/";
}
if ((cwd = getenv("PWD")) == NULL &&
(cwd = getcwd(path, sizeof path)) == NULL &&
(cwd = find_home()) == NULL)
cwd = "/";
if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
ttynam = "";
@@ -338,6 +337,10 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
size = 0;
for (i = 0; i < argc; i++)
size += strlen(argv[i]) + 1;
if (size > MAX_IMSGSIZE - (sizeof *data)) {
fprintf(stderr, "command too long\n");
return (1);
}
data = xmalloc((sizeof *data) + size);
/* Prepare command for server. */
@@ -449,6 +452,7 @@ client_write(int fd, const char *data, size_t size)
{
ssize_t used;
log_debug("%s: %.*s", __func__, (int)size, data);
while (size != 0) {
used = write(fd, data, size);
if (used == -1) {

View File

@@ -100,6 +100,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
s->cwd = format_single(item, cflag, c, s, wl, wp);
}
c->last_session = c->session;
if (c->session != NULL) {
if (dflag) {
TAILQ_FOREACH(c_loop, &clients, entry) {

View File

@@ -30,8 +30,8 @@ const struct cmd_entry cmd_choose_tree_entry = {
.name = "choose-tree",
.alias = NULL,
.args = { "F:f:NO:st:w", 0, 1 },
.usage = "[-Nsw] [-F format] [-f filter] [-O sort-order] "
.args = { "F:Gf:NO:st:wZ", 0, 1 },
.usage = "[-GNsw] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
@@ -44,7 +44,7 @@ const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client",
.alias = NULL,
.args = { "F:f:NO:t:", 0, 1 },
.args = { "F:f:NO:t:Z", 0, 1 },
.usage = "[-N] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE,
@@ -58,7 +58,7 @@ const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer",
.alias = NULL,
.args = { "F:f:NO:t:", 0, 1 },
.args = { "F:f:NO:t:Z", 0, 1 },
.usage = "[-N] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE,

View File

@@ -53,7 +53,7 @@ static enum cmd_retval
cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c;
struct client *c, *target_c;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
@@ -65,7 +65,6 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "only one of -F or argument must be given");
return (CMD_RETURN_ERROR);
}
c = cmd_find_client(item, args_get(args, 'c'), 1);
template = args_get(args, 'F');
if (args->argc != 0)
@@ -73,8 +72,19 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
if (template == NULL)
template = DISPLAY_MESSAGE_TEMPLATE;
/*
* -c is intended to be the client where the message should be
* displayed if -p is not given. But it makes sense to use it for the
* formats too, assuming it matches the session. If it doesn't, use the
* best client for the session.
*/
c = cmd_find_client(item, args_get(args, 'c'), 1);
if (c != NULL && c->session == s)
target_c = c;
else
target_c = cmd_find_best_client(s);
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, c, s, wl, wp);
format_defaults(ft, target_c, s, wl, wp);
msg = format_expand_time(ft, template, time(NULL));
if (args_has(self->args, 'p'))

View File

@@ -55,6 +55,7 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
s = c->session;
if (c->identify_callback != NULL)
return (CMD_RETURN_NORMAL);
@@ -64,7 +65,7 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
c->identify_callback_data = xstrdup(args->argv[0]);
else
c->identify_callback_data = xstrdup("select-pane -t '%%'");
s = c->session;
c->identify_callback_item = item;
if (args_has(args, 'd')) {
delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause);
@@ -77,7 +78,7 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
delay = options_get_number(s->options, "display-panes-time");
server_client_set_identify(c, delay);
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
static enum cmd_retval
@@ -96,34 +97,36 @@ cmd_display_panes_callback(struct client *c, struct window_pane *wp)
{
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
char *template, *cmd, *expanded, *cause;
char *cmd, *expanded, *cause;
template = c->identify_callback_data;
if (wp == NULL)
goto out;
xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(template, expanded, 1);
cmd = cmd_template_replace(c->identify_callback_data, expanded, 1);
cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);
if (cmdlist == NULL) {
if (cause != NULL) {
new_item = cmdq_get_callback(cmd_display_panes_error,
cause);
} else
new_item = NULL;
} else {
if (cmdlist == NULL && cause != NULL)
new_item = cmdq_get_callback(cmd_display_panes_error, cause);
else if (cmdlist == NULL)
new_item = NULL;
else {
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist);
}
if (new_item != NULL)
cmdq_append(c, new_item);
cmdq_insert_after(c->identify_callback_item, new_item);
free(cmd);
free(expanded);
out:
c->identify_callback_item->flags &= ~CMDQ_WAITING;
c->identify_callback_item = NULL;
free(c->identify_callback_data);
c->identify_callback_data = NULL;
c->identify_callback = NULL;
}

View File

@@ -34,6 +34,7 @@ static int cmd_find_best_winlink_with_window(struct cmd_find_state *);
static const char *cmd_find_map_table(const char *[][2], const char *);
static void cmd_find_log_state(const char *, struct cmd_find_state *);
static int cmd_find_get_session(struct cmd_find_state *, const char *);
static int cmd_find_get_window(struct cmd_find_state *, const char *, int);
static int cmd_find_get_window_with_session(struct cmd_find_state *,
@@ -82,6 +83,7 @@ cmd_find_try_TMUX(struct client *c)
char tmp[256];
long long pid;
u_int session;
struct session *s;
envent = environ_find(c->environ, "TMUX");
if (envent == NULL)
@@ -91,8 +93,13 @@ cmd_find_try_TMUX(struct client *c)
return (NULL);
if (pid != getpid())
return (NULL);
log_debug("client %p TMUX %s (session @%u)", c, envent->value, session);
return (session_find_by_id(session));
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. */
@@ -105,9 +112,11 @@ cmd_find_inside_pane(struct client *c)
return (NULL);
RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
if (strcmp(wp->tty, c->ttyname) == 0)
if (wp->fd != -1 && strcmp(wp->tty, c->ttyname) == 0)
break;
}
if (wp != NULL)
log_debug("%s: got pane %%%u (%s)", __func__, wp->id, wp->tty);
return (wp);
}
@@ -121,7 +130,7 @@ cmd_find_client_better(struct client *c, struct client *than)
}
/* Find best client for session. */
static struct client *
struct client *
cmd_find_best_client(struct session *s)
{
struct client *c_loop, *c;
@@ -166,6 +175,8 @@ cmd_find_best_session(struct session **slist, u_int ssize, int flags)
struct session *s_loop, *s;
u_int i;
log_debug("%s: %u sessions to try", __func__, ssize);
s = NULL;
if (slist != NULL) {
for (i = 0; i < ssize; i++) {
@@ -189,6 +200,8 @@ cmd_find_best_session_with_window(struct cmd_find_state *fs)
u_int ssize;
struct session *s;
log_debug("%s: window is @%u", __func__, fs->w->id);
ssize = 0;
RB_FOREACH(s, sessions, &sessions) {
if (!session_has(s, fs->w))
@@ -210,7 +223,7 @@ fail:
}
/*
* Find the best winlink for a window (the current if it contains the pane,
* Find the best winlink for a window (the current if it contains the window,
* otherwise the first).
*/
static int
@@ -218,6 +231,8 @@ cmd_find_best_winlink_with_window(struct cmd_find_state *fs)
{
struct winlink *wl, *wl_loop;
log_debug("%s: window is @%u", __func__, fs->w->id);
wl = NULL;
if (fs->s->curw != NULL && fs->s->curw->window == fs->w)
wl = fs->s->curw;
@@ -389,7 +404,7 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window)
return (-1);
fs->idx = s->curw->idx + n;
} else {
if (n < s->curw->idx)
if (n > s->curw->idx)
return (-1);
fs->idx = s->curw->idx - n;
}
@@ -436,15 +451,15 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window)
if (window[0] != '+' && window[0] != '-') {
idx = strtonum(window, 0, INT_MAX, &errstr);
if (errstr == NULL) {
if (fs->flags & CMD_FIND_WINDOW_INDEX) {
fs->idx = idx;
return (0);
}
fs->wl = winlink_find_by_index(&fs->s->windows, idx);
if (fs->wl != NULL) {
fs->w = fs->wl->window;
return (0);
}
if (fs->flags & CMD_FIND_WINDOW_INDEX) {
fs->idx = idx;
return (0);
}
}
}
@@ -587,8 +602,6 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
/* Try special characters. */
if (strcmp(pane, "!") == 0) {
if (fs->w->last == NULL)
return (-1);
fs->wp = fs->w->last;
if (fs->wp == NULL)
return (-1);
@@ -703,11 +716,11 @@ cmd_find_copy_state(struct cmd_find_state *dst, struct cmd_find_state *src)
}
/* Log the result. */
void
static void
cmd_find_log_state(const char *prefix, struct cmd_find_state *fs)
{
if (fs->s != NULL)
log_debug("%s: s=$%u", prefix, fs->s->id);
log_debug("%s: s=$%u %s", prefix, fs->s->id, fs->s->name);
else
log_debug("%s: s=none", prefix);
if (fs->wl != NULL) {
@@ -896,6 +909,9 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
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;
@@ -903,6 +919,9 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
cmd_find_log_state(__func__, fs);
return (0);
} else {
log_debug("%s: session $%u does not have pane %%%u",
__func__, s->id, wp->id);
}
}
@@ -912,16 +931,12 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
*/
fs->w = wp->window;
if (cmd_find_best_session_with_window(fs) != 0) {
if (wp != NULL) {
/*
* The window may have been destroyed but the pane
* still on all_window_panes due to something else
* holding a reference.
*/
goto unknown_pane;
}
cmd_find_clear_state(fs, 0);
return (-1);
/*
* The window may have been destroyed but the pane
* still on all_window_panes due to something else
* holding a reference.
*/
goto unknown_pane;
}
fs->wl = fs->s->curw;
fs->w = fs->wl->window;
@@ -1147,7 +1162,8 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
/* This will fill in winlink and window. */
if (cmd_find_get_window_with_session(fs, window) != 0)
goto no_window;
fs->wp = fs->wl->window->active;
if (fs->wl != NULL) /* can be NULL if index only */
fs->wp = fs->wl->window->active;
goto found;
}
@@ -1187,7 +1203,8 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
/* This will fill in session, winlink and window. */
if (cmd_find_get_window(fs, window, window_only) != 0)
goto no_window;
fs->wp = fs->wl->window->active;
if (fs->wl != NULL) /* can be NULL if index only */
fs->wp = fs->wl->window->active;
goto found;
}

View File

@@ -73,14 +73,6 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
const char *cwd;
if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
else if (s != NULL)
cwd = s->cwd;
else
cwd = NULL;
shellcmd = format_single(item, args->argv[0], c, s, wl, wp);
if (args_has(args, 'F')) {
@@ -128,8 +120,8 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->item = NULL;
memcpy(&cdata->mouse, &shared->mouse, sizeof cdata->mouse);
job_run(shellcmd, s, cwd, NULL, cmd_if_shell_callback,
cmd_if_shell_free, cdata);
job_run(shellcmd, s, server_client_get_cwd(item->client, s), NULL,
cmd_if_shell_callback, cmd_if_shell_free, cdata, 0);
free(shellcmd);
if (args_has(args, 'b'))

View File

@@ -47,9 +47,8 @@ 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;
server_unzoom_window(wl->window);
if (args_has(self->args, 'a')) {
server_unzoom_window(wl->window);
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
if (loopwp == wp)
continue;
@@ -60,13 +59,6 @@ cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
if (window_count_panes(wl->window) == 1) {
server_kill_window(wl->window);
recalculate_sizes();
} else {
layout_close_pane(wp);
window_remove_pane(wl->window, wp);
server_redraw_window(wl->window);
}
server_kill_pane(wp);
return (CMD_RETURN_NORMAL);
}

View File

@@ -75,10 +75,14 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
repeat = 0;
tablewidth = keywidth = 0;
RB_FOREACH(table, key_tables, &key_tables) {
if (tablename != NULL && strcmp(table->name, tablename) != 0)
table = key_bindings_first_table ();
while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table);
continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
}
bd = key_bindings_first(table);
while (bd != NULL) {
key = key_string_lookup_key(bd->key);
if (bd->flags & KEY_BINDING_REPEAT)
@@ -90,13 +94,20 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
width = utf8_cstrwidth(key);
if (width > keywidth)
keywidth = width;
bd = key_bindings_next(table, bd);
}
table = key_bindings_next_table(table);
}
RB_FOREACH(table, key_tables, &key_tables) {
if (tablename != NULL && strcmp(table->name, tablename) != 0)
table = key_bindings_first_table ();
while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table);
continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
}
bd = key_bindings_first(table);
while (bd != NULL) {
key = key_string_lookup_key(bd->key);
if (!repeat)
@@ -122,7 +133,9 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
free(cp);
cmdq_print(item, "bind-key %s", tmp);
bd = key_bindings_next(table, bd);
}
table = key_bindings_next_table(table);
}
return (CMD_RETURN_NORMAL);

View File

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

View File

@@ -73,14 +73,15 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
struct environ *env;
struct termios tio, *tiop;
struct session_group *sg;
const char *newname, *errstr, *template, *group, *prefix;
const char *path, *cmd, *cwd;
char **argv, *cause, *cp, *to_free = NULL;
const char *errstr, *template, *group, *prefix;
const char *path, *cmd, *tmp;
char **argv, *cause, *cp, *newname, *cwd = NULL;
int detached, already_attached, idx, argc;
int is_control = 0;
u_int sx, sy;
struct environ_entry *envent;
struct cmd_find_state fs;
enum cmd_retval retval;
if (self->entry == &cmd_has_session_entry) {
/*
@@ -95,20 +96,24 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
newname = args_get(args, 's');
if (newname != NULL) {
newname = NULL;
if (args_has(args, 's')) {
newname = format_single(item, args_get(args, 's'), c, NULL,
NULL, NULL);
if (!session_check_name(newname)) {
cmdq_error(item, "bad session name: %s", newname);
return (CMD_RETURN_ERROR);
goto error;
}
if ((as = session_find(newname)) != NULL) {
if (args_has(args, 'A')) {
return (cmd_attach_session(item,
retval = cmd_attach_session(item,
newname, args_has(args, 'D'),
0, NULL, args_has(args, 'E')));
0, NULL, args_has(args, 'E'));
free(newname);
return (retval);
}
cmdq_error(item, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR);
goto error;
}
}
@@ -149,14 +154,10 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
already_attached = 1;
/* Get the new session working directory. */
if (args_has(args, 'c')) {
cwd = args_get(args, 'c');
to_free = format_single(item, cwd, c, NULL, NULL, NULL);
cwd = to_free;
} else if (c != NULL && c->session == NULL && c->cwd != NULL)
cwd = c->cwd;
if ((tmp = args_get(args, 'c')) != NULL)
cwd = format_single(item, tmp, c, NULL, NULL, NULL);
else
cwd = ".";
cwd = xstrdup(server_client_get_cwd(c, NULL));
/*
* If this is a new client, check for nesting and save the termios
@@ -201,17 +202,29 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
sy = 24;
}
if ((is_control || detached) && args_has(args, 'x')) {
sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "width %s", errstr);
goto error;
tmp = args_get(args, 'x');
if (strcmp(tmp, "-") == 0) {
if (c != NULL)
sx = c->tty.sx;
} else {
sx = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "width %s", errstr);
goto error;
}
}
}
if ((is_control || detached) && args_has(args, 'y')) {
sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
goto error;
tmp = args_get(args, 'y');
if (strcmp(tmp, "-") == 0) {
if (c != NULL)
sy = c->tty.sy;
} else {
sy = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
goto error;
}
}
}
if (sx == 0)
@@ -261,10 +274,12 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
}
/* Set the initial window name if one given. */
if (argc >= 0 && args_has(args, 'n')) {
if (argc >= 0 && (tmp = args_get(args, 'n')) != NULL) {
cp = format_single(item, tmp, c, s, NULL, NULL);
w = s->curw->window;
window_set_name(w, args_get(args, 'n'));
window_set_name(w, cp);
options_set_number(w->options, "automatic-rename", 0);
free(cp);
}
/*
@@ -331,10 +346,12 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
cmd_find_from_session(&fs, s, 0);
hooks_insert(s->hooks, item, &fs, "after-new-session");
free(to_free);
free(cwd);
free(newname);
return (CMD_RETURN_NORMAL);
error:
free(to_free);
free(cwd);
free(newname);
return (CMD_RETURN_ERROR);
}

View File

@@ -57,13 +57,13 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
struct winlink *wl = item->target.wl;
struct client *c = cmd_find_client(item, NULL, 1);
int idx = item->target.idx;
const char *cmd, *path, *template, *cwd;
char **argv, *cause, *cp, *to_free = NULL;
const char *cmd, *path, *template, *tmp;
char **argv, *cause, *cp, *cwd, *name;
int argc, detached;
struct environ_entry *envent;
struct cmd_find_state fs;
if (args_has(args, 'a')) {
if (args_has(args, 'a') && wl != NULL) {
if ((idx = winlink_shuffle_up(s, wl)) == -1) {
cmdq_error(item, "no free window indexes");
return (CMD_RETURN_ERROR);
@@ -93,16 +93,16 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
if (envent != NULL)
path = envent->value;
if (args_has(args, 'c')) {
cwd = args_get(args, 'c');
to_free = format_single(item, cwd, c, s, NULL, NULL);
cwd = to_free;
} else if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
if ((tmp = args_get(args, 'c')) != NULL)
cwd = format_single(item, tmp, c, s, NULL, NULL);
else
cwd = s->cwd;
cwd = xstrdup(server_client_get_cwd(item->client, s));
if ((tmp = args_get(args, 'n')) != NULL)
name = format_single(item, tmp, c, s, NULL, NULL);
else
name = NULL;
wl = NULL;
if (idx != -1)
wl = winlink_find_by_index(&s->windows, idx);
if (wl != NULL && args_has(args, 'k')) {
@@ -124,7 +124,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
if (idx == -1)
idx = -1 - options_get_number(s->options, "base-index");
wl = session_new(s, args_get(args, 'n'), argc, argv, path, cwd, idx,
wl = session_new(s, name, argc, argv, path, cwd, idx,
&cause);
if (wl == NULL) {
cmdq_error(item, "create window failed: %s", cause);
@@ -149,10 +149,12 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
cmd_find_from_winlink(&fs, wl, 0);
hooks_insert(s->hooks, item, &fs, "after-new-window");
free(to_free);
free(name);
free(cwd);
return (CMD_RETURN_NORMAL);
error:
free(to_free);
free(name);
free(cwd);
return (CMD_RETURN_ERROR);
}

View File

@@ -35,6 +35,7 @@
static enum cmd_retval cmd_pipe_pane_exec(struct cmd *, struct cmdq_item *);
static void cmd_pipe_pane_read_callback(struct bufferevent *, void *);
static void cmd_pipe_pane_write_callback(struct bufferevent *, void *);
static void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *);
@@ -42,8 +43,8 @@ const struct cmd_entry cmd_pipe_pane_entry = {
.name = "pipe-pane",
.alias = "pipep",
.args = { "ot:", 0, 1 },
.usage = "[-o] " CMD_TARGET_PANE_USAGE " [command]",
.args = { "IOot:", 0, 1 },
.usage = "[-IOo] " CMD_TARGET_PANE_USAGE " [command]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -60,7 +61,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
char *cmd;
int old_fd, pipe_fd[2], null_fd;
int old_fd, pipe_fd[2], null_fd, in, out;
struct format_tree *ft;
sigset_t set, oldset;
@@ -90,6 +91,15 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(self->args, 'o') && old_fd != -1)
return (CMD_RETURN_NORMAL);
/* What do we want to do? Neither -I or -O is -O. */
if (args_has(self->args, 'I')) {
in = 1;
out = args_has(self->args, 'O');
} else {
in = 0;
out = 1;
}
/* Open the new pipe. */
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) {
cmdq_error(item, "socketpair error: %s", strerror(errno));
@@ -118,19 +128,25 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
sigprocmask(SIG_SETMASK, &oldset, NULL);
close(pipe_fd[0]);
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
_exit(1);
if (pipe_fd[1] != STDIN_FILENO)
close(pipe_fd[1]);
null_fd = open(_PATH_DEVNULL, O_WRONLY, 0);
if (dup2(null_fd, STDOUT_FILENO) == -1)
_exit(1);
if (out) {
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
_exit(1);
} else {
if (dup2(null_fd, STDIN_FILENO) == -1)
_exit(1);
}
if (in) {
if (dup2(pipe_fd[1], STDOUT_FILENO) == -1)
_exit(1);
if (pipe_fd[1] != STDOUT_FILENO)
close(pipe_fd[1]);
} else {
if (dup2(null_fd, STDOUT_FILENO) == -1)
_exit(1);
}
if (dup2(null_fd, STDERR_FILENO) == -1)
_exit(1);
if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO)
close(null_fd);
closefrom(STDERR_FILENO + 1);
execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
@@ -143,24 +159,46 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
wp->pipe_fd = pipe_fd[0];
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
wp->pipe_event = bufferevent_new(wp->pipe_fd, NULL,
cmd_pipe_pane_write_callback, cmd_pipe_pane_error_callback,
wp);
bufferevent_enable(wp->pipe_event, EV_WRITE);
setblocking(wp->pipe_fd, 0);
wp->pipe_event = bufferevent_new(wp->pipe_fd,
cmd_pipe_pane_read_callback,
cmd_pipe_pane_write_callback,
cmd_pipe_pane_error_callback,
wp);
if (out)
bufferevent_enable(wp->pipe_event, EV_WRITE);
if (in)
bufferevent_enable(wp->pipe_event, EV_READ);
free(cmd);
return (CMD_RETURN_NORMAL);
}
}
static void
cmd_pipe_pane_read_callback(__unused struct bufferevent *bufev, void *data)
{
struct window_pane *wp = data;
struct evbuffer *evb = wp->pipe_event->input;
size_t available;
available = EVBUFFER_LENGTH(evb);
log_debug("%%%u pipe read %zu", wp->id, available);
bufferevent_write(wp->event, EVBUFFER_DATA(evb), available);
evbuffer_drain(evb, available);
if (window_pane_destroy_ready(wp))
server_destroy_pane(wp, 1);
}
static void
cmd_pipe_pane_write_callback(__unused struct bufferevent *bufev, void *data)
{
struct window_pane *wp = data;
log_debug("%%%u pipe empty", wp->id);
if (window_pane_destroy_ready(wp))
server_destroy_pane(wp, 1);
}

View File

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

View File

@@ -46,12 +46,17 @@ static enum cmd_retval
cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
char *newname;
window_set_name(wl->window, args->argv[0]);
newname = format_single(item, args->argv[0], c, s, wl, NULL);
window_set_name(wl->window, newname);
options_set_number(wl->window->options, "automatic-rename", 0);
server_status_window(wl->window);
free(newname);
return (CMD_RETURN_NORMAL);
}

View File

@@ -129,14 +129,21 @@ static void
cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m)
{
struct winlink *wl;
struct window_pane *loop, *wp_x, *wp_y;
u_int y, ly, x, lx, sx, sy, ex, ey;
struct window *w;
u_int y, ly, x, lx;
static const int offsets[][2] = {
{ 0, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
};
struct layout_cell *cells[nitems(offsets)], *lc;
u_int ncells = 0, i, j, resizes = 0;
enum layout_type type;
wl = cmd_mouse_window(m, NULL);
if (wl == NULL) {
c->tty.mouse_drag_update = NULL;
return;
}
w = wl->window;
y = m->y; x = m->x;
if (m->statusat == 0 && y > 0)
@@ -149,37 +156,37 @@ cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m)
else if (m->statusat > 0 && ly >= (u_int)m->statusat)
ly = m->statusat - 1;
wp_x = wp_y = NULL;
TAILQ_FOREACH(loop, &wl->window->panes, entry) {
if (!window_pane_visible(loop))
for (i = 0; i < nitems(cells); i++) {
lc = layout_search_by_border(w->layout_root, lx + offsets[i][0],
ly + offsets[i][1]);
if (lc == NULL)
continue;
sx = loop->xoff;
if (sx != 0)
sx--;
ex = loop->xoff + loop->sx;
for (j = 0; j < ncells; j++) {
if (cells[j] == lc) {
lc = NULL;
break;
}
}
if (lc == NULL)
continue;
sy = loop->yoff;
if (sy != 0)
sy--;
ey = loop->yoff + loop->sy;
if ((lx == sx || lx == ex) &&
(ly >= sy && ly <= ey) &&
(wp_x == NULL || loop->sy > wp_x->sy))
wp_x = loop;
if ((ly == sy || ly == ey) &&
(lx >= sx && lx <= ex) &&
(wp_y == NULL || loop->sx > wp_y->sx))
wp_y = loop;
cells[ncells] = lc;
ncells++;
}
if (wp_x == NULL && wp_y == NULL) {
c->tty.mouse_drag_update = NULL;
if (ncells == 0)
return;
for (i = 0; i < ncells; i++) {
type = cells[i]->parent->type;
if (y != ly && type == LAYOUT_TOPBOTTOM) {
layout_resize_layout(w, cells[i], type, y - ly, 0);
resizes++;
} else if (x != lx && type == LAYOUT_LEFTRIGHT) {
layout_resize_layout(w, cells[i], type, x - lx, 0);
resizes++;
}
}
if (wp_x != NULL)
layout_resize_pane(wp_x, LAYOUT_LEFTRIGHT, x - lx, 0);
if (wp_y != NULL)
layout_resize_pane(wp_y, LAYOUT_TOPBOTTOM, y - ly, 0);
server_redraw_window(wl->window);
if (resizes != 0)
server_redraw_window(w);
}

View File

@@ -90,14 +90,6 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
const char *cwd;
if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
else if (s != NULL)
cwd = s->cwd;
else
cwd = NULL;
cdata = xcalloc(1, sizeof *cdata);
cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp);
@@ -110,8 +102,8 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 'b'))
cdata->item = item;
job_run(cdata->cmd, s, cwd, NULL, cmd_run_shell_callback,
cmd_run_shell_free, cdata);
job_run(cdata->cmd, s, server_client_get_cwd(item->client, s), NULL,
cmd_run_shell_callback, cmd_run_shell_free, cdata, 0);
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);

View File

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

View File

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

View File

@@ -18,6 +18,8 @@
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
@@ -57,14 +59,21 @@ 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 window *w = wl->window;
struct session *s = item->target.s;
struct window_pane *wp = item->target.wp, *lastwp, *markedwp;
char *pane_title;
const char *style;
if (self->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);
if (lastwp == NULL)
lastwp = TAILQ_NEXT(w->active, entry);
}
if (lastwp == NULL) {
cmdq_error(item, "no last pane");
return (CMD_RETURN_ERROR);
@@ -148,8 +157,12 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
}
if (args_has(self->args, 'T')) {
screen_set_title(&wp->base, args_get(self->args, 'T'));
server_status_window(wp->window);
pane_title = format_single(item, args_get(self->args, 'T'),
c, s, wl, wp);
screen_set_title(&wp->base, pane_title);
server_status_window(wp->window);
free(pane_title);
return (CMD_RETURN_NORMAL);
}
if (wp == w->active)

View File

@@ -61,7 +61,7 @@ cmd_send_keys_inject(struct client *c, struct cmdq_item *item, key_code key)
struct window_pane *wp = item->target.wp;
struct session *s = item->target.s;
struct key_table *table;
struct key_binding *bd, bd_find;
struct key_binding *bd;
if (wp->mode == NULL || wp->mode->key_table == NULL) {
if (options_get_number(wp->window->options, "xterm-keys"))
@@ -71,8 +71,7 @@ cmd_send_keys_inject(struct client *c, struct cmdq_item *item, key_code key)
}
table = key_bindings_get_table(wp->mode->key_table(wp), 1);
bd_find.key = (key & ~KEYC_XTERM);
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
bd = key_bindings_get(table, key & ~KEYC_XTERM);
if (bd != NULL) {
table->references++;
key_bindings_dispatch(bd, item, c, NULL, &item->target);

View File

@@ -33,8 +33,8 @@ const struct cmd_entry cmd_set_hook_entry = {
.name = "set-hook",
.alias = NULL,
.args = { "gt:u", 1, 2 },
.usage = "[-gu] " CMD_TARGET_SESSION_USAGE " hook-name [command]",
.args = { "gRt:u", 1, 2 },
.usage = "[-gRu] " CMD_TARGET_SESSION_USAGE " hook-name [command]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@@ -101,18 +101,21 @@ cmd_set_hook_exec(struct cmd *self, struct cmdq_item *item)
else
cmd = args->argv[1];
if (cmd != NULL && (args_has(args, 'R') || args_has(args, 'u'))) {
cmdq_error(item, "no command allowed");
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'R')) {
notify_hook(item, name);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'u')) {
if (cmd != NULL) {
cmdq_error(item, "command passed to unset hook: %s",
name);
return (CMD_RETURN_ERROR);
}
hooks_remove(hooks, name);
return (CMD_RETURN_NORMAL);
}
if (cmd == NULL) {
cmdq_error(item, "no command to set hook: %s", name);
cmdq_error(item, "no command given");
return (CMD_RETURN_ERROR);
}
cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);

View File

@@ -192,7 +192,9 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
if (o == NULL)
goto out;
if (idx == -1) {
if (oo == global_options ||
if (*name == '@')
options_remove(o);
else if (oo == global_options ||
oo == global_s_options ||
oo == global_w_options)
options_default(oo, options_table_entry(o));

View File

@@ -60,7 +60,7 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
if (*path == '/')
pattern = xstrdup(path);
else {
utf8_stravis(&tmp, server_client_get_cwd(c), VIS_GLOB);
utf8_stravis(&tmp, server_client_get_cwd(c, NULL), VIS_GLOB);
xasprintf(&pattern, "%s/%s", tmp, path);
free(tmp);
}

View File

@@ -60,10 +60,10 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
struct window *w = wl->window;
struct window_pane *wp = item->target.wp, *new_wp = NULL;
struct environ *env;
const char *cmd, *path, *shell, *template, *cwd;
char **argv, *cause, *new_cause, *cp, *to_free = NULL;
const char *cmd, *path, *shell, *template, *tmp;
char **argv, *cause, *new_cause, *cp, *cwd;
u_int hlimit;
int argc, size, percentage;
int argc, size, percentage, before;
enum layout_type type;
struct layout_cell *lc;
struct environ_entry *envent;
@@ -85,18 +85,15 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
argv = args->argv;
}
if (args_has(args, 'c')) {
cwd = args_get(args, 'c');
to_free = format_single(item, cwd, c, s, NULL, NULL);
cwd = to_free;
} else if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
if ((tmp = args_get(args, 'c')) != NULL)
cwd = format_single(item, tmp, c, s, NULL, NULL);
else
cwd = s->cwd;
cwd = xstrdup(server_client_get_cwd(item->client, s));
type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT;
before = args_has(args, 'b');
size = -1;
if (args_has(args, 'l')) {
@@ -126,13 +123,12 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if (*shell == '\0' || areshell(shell))
shell = _PATH_BSHELL;
lc = layout_split_pane(wp, type, size, args_has(args, 'b'),
args_has(args, 'f'));
lc = layout_split_pane(wp, type, size, before, args_has(args, 'f'));
if (lc == NULL) {
cause = xstrdup("pane too small");
goto error;
}
new_wp = window_add_pane(w, wp, args_has(args, 'b'), hlimit);
new_wp = window_add_pane(w, wp, before, args_has(args, 'f'), hlimit);
layout_make_leaf(lc, new_wp);
path = NULL;
@@ -174,7 +170,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
cmd_find_from_winlink_pane(&fs, wl, new_wp, 0);
hooks_insert(s->hooks, item, &fs, "after-split-window");
free(to_free);
free(cwd);
return (CMD_RETURN_NORMAL);
error:
@@ -185,6 +181,6 @@ error:
cmdq_error(item, "create pane failed: %s", cause);
free(cause);
free(to_free);
free(cwd);
return (CMD_RETURN_ERROR);
}

13
cmd.c
View File

@@ -200,6 +200,15 @@ const struct cmd_entry *cmd_table[] = {
NULL
};
void
cmd_log_argv(int argc, char **argv, const char *prefix)
{
int i;
for (i = 0; i < argc; i++)
log_debug("%s: argv[%d]=%s", prefix, i, argv[i]);
}
int
cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
{
@@ -208,6 +217,7 @@ cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
if (argc == 0)
return (0);
cmd_log_argv(argc, argv, __func__);
*buf = '\0';
for (i = 0; i < argc; i++) {
@@ -240,9 +250,11 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
arglen = strlen(buf) + 1;
(*argv)[i] = xstrdup(buf);
buf += arglen;
len -= arglen;
}
cmd_log_argv(argc, *argv, __func__);
return (0);
}
@@ -401,6 +413,7 @@ retry:
xasprintf(cause, "unknown command: %s", name);
return (NULL);
}
cmd_log_argv(argc, argv, entry->name);
args = args_parse(entry->args.template, argc, argv);
if (args == NULL)

View File

@@ -101,17 +101,17 @@ void warnx(const char *, ...);
#include <paths.h>
#endif
#ifdef HAVE_FORKPTY
#ifdef HAVE_LIBUTIL_H
#include <libutil.h>
#endif
#ifdef HAVE_PTY_H
#include <pty.h>
#endif
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
#endif
#ifdef HAVE_VIS
#include <vis.h>

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
# configure.ac
AC_INIT(tmux, 2.6)
AC_INIT(tmux, 2.8)
AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc)
@@ -285,6 +285,7 @@ if test "x$found_b64_ntop" = xno; then
AC_MSG_RESULT(no)
AC_MSG_CHECKING(for b64_ntop with -lresolv)
OLD_LIBS="$LIBS"
LIBS="$LIBS -lresolv"
AC_TRY_LINK(
[
@@ -297,6 +298,7 @@ if test "x$found_b64_ntop" = xno; then
found_b64_ntop=no
)
if test "x$found_b64_ntop" = xno; then
LIBS="$OLD_LIBS"
AC_MSG_RESULT(no)
fi
fi
@@ -608,13 +610,22 @@ case "$host_os" in
*solaris*)
AC_MSG_RESULT(sunos)
PLATFORM=sunos
MANFORMAT=man
case `/usr/bin/nroff --version 2>&1` in
*GNU*)
# Solaris 11.4 and later use GNU groff.
MANFORMAT=mdoc
;;
*)
# Solaris 2.0 to 11.3 use AT&T nroff.
MANFORMAT=man
;;
esac
;;
*hpux*)
AC_MSG_RESULT(hpux)
PLATFORM=hpux
;;
*cygwin*)
*cygwin*|*msys*)
AC_MSG_RESULT(cygwin)
PLATFORM=cygwin
;;

153
format.c
View File

@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <errno.h>
#include <fnmatch.h>
#include <libgen.h>
@@ -191,10 +192,15 @@ static void
format_job_update(struct job *job)
{
struct format_job *fj = job->data;
char *line;
struct evbuffer *evb = job->event->input;
char *line = NULL, *next;
time_t t;
if ((line = evbuffer_readline(job->event->input)) == NULL)
while ((next = evbuffer_readline(evb)) != NULL) {
free(line);
line = next;
}
if (line == NULL)
return;
fj->updated = 1;
@@ -290,7 +296,7 @@ format_job_get(struct format_tree *ft, const char *cmd)
t = time(NULL);
if (fj->job == NULL && (force || fj->last != t)) {
fj->job = job_run(expanded, NULL, NULL, format_job_update,
format_job_complete, NULL, fj);
format_job_complete, NULL, fj, JOB_NOWAIT);
if (fj->job == NULL) {
free(fj->out);
xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd);
@@ -557,11 +563,11 @@ format_cb_history_bytes(struct format_tree *ft, struct format_entry *fe)
size = 0;
for (i = 0; i < gd->hsize; i++) {
gl = &gd->linedata[i];
gl = grid_get_line(gd, i);
size += gl->cellsize * sizeof *gl->celldata;
size += gl->extdsize * sizeof *gl->extddata;
}
size += gd->hsize * sizeof *gd->linedata;
size += gd->hsize * sizeof *gl;
xasprintf(&fe->value, "%llu", size);
}
@@ -587,8 +593,35 @@ format_cb_pane_tabs(struct format_tree *ft, struct format_entry *fe)
evbuffer_add(buffer, ",", 1);
evbuffer_add_printf(buffer, "%u", i);
}
size = EVBUFFER_LENGTH(buffer);
xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer));
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer));
evbuffer_free(buffer);
}
/* Callback for session_group_list. */
static void
format_cb_session_group_list(struct format_tree *ft, struct format_entry *fe)
{
struct session *s = ft->s;
struct session_group *sg;
struct session *loop;
struct evbuffer *buffer;
int size;
if (s == NULL)
return;
sg = session_group_contains(s);
if (sg == NULL)
return;
buffer = evbuffer_new();
TAILQ_FOREACH(loop, &sg->sessions, gentry) {
if (EVBUFFER_LENGTH(buffer) > 0)
evbuffer_add(buffer, ",", 1);
evbuffer_add_printf(buffer, "%s", loop->name);
}
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer));
evbuffer_free(buffer);
}
@@ -781,8 +814,11 @@ format_find(struct format_tree *ft, const char *key, int modifiers)
found = s;
goto found;
}
if (fe->value == NULL && fe->cb != NULL)
if (fe->value == NULL && fe->cb != NULL) {
fe->cb(ft, fe);
if (fe->value == NULL)
fe->value = xstrdup("");
}
found = fe->value;
goto found;
}
@@ -818,18 +854,22 @@ found:
return (copy);
}
/* Skip until comma. */
static char *
format_skip(char *s)
/* Skip until end. */
static const char *
format_skip(const char *s, char end)
{
int brackets = 0;
for (; *s != '\0'; s++) {
if (*s == '{')
if (*s == '#' && s[1] == '{')
brackets++;
if (*s == '#' && strchr(",#{}", s[1]) != NULL) {
s++;
continue;
}
if (*s == '}')
brackets--;
if (*s == ',' && brackets == 0)
if (*s == end && brackets == 0)
break;
}
if (*s == '\0')
@@ -843,7 +883,7 @@ format_choose(char *s, char **left, char **right)
{
char *cp;
cp = format_skip(s);
cp = (char *)format_skip(s, ',');
if (cp == NULL)
return (-1);
*cp = '\0';
@@ -868,11 +908,12 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
char **buf, size_t *len, size_t *off)
{
struct window_pane *wp = ft->wp;
char *copy, *copy0, *endptr, *ptr, *found, *new;
char *copy, *copy0, *endptr, *ptr, *found, *new, sep;
char *value, *from = NULL, *to = NULL, *left, *right;
size_t valuelen, newlen, fromlen, tolen, used;
long limit = 0;
int modifiers = 0, compare = 0, search = 0;
int literal = 0;
/* Make a copy of the key. */
copy0 = copy = xmalloc(keylen + 1);
@@ -881,6 +922,12 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
/* Is there a length limit or whatnot? */
switch (copy[0]) {
case 'l':
if (copy[1] != ':')
break;
literal = 1;
copy += 2;
break;
case 'm':
if (copy[1] != ':')
break;
@@ -945,20 +992,21 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
copy += 2;
break;
case 's':
if (copy[1] != '/')
sep = copy[1];
if (sep == ':' || !ispunct((u_char)sep))
break;
from = copy + 2;
for (copy = from; *copy != '\0' && *copy != '/'; copy++)
for (copy = from; *copy != '\0' && *copy != sep; copy++)
/* nothing */;
if (copy[0] != '/' || copy == from) {
if (copy[0] != sep || copy == from) {
copy = copy0;
break;
}
copy[0] = '\0';
to = copy + 1;
for (copy = to; *copy != '\0' && *copy != '/'; copy++)
for (copy = to; *copy != '\0' && *copy != sep; copy++)
/* nothing */;
if (copy[0] != '/' || copy[1] != ':') {
if (copy[0] != sep || copy[1] != ':') {
copy = copy0;
break;
}
@@ -969,6 +1017,12 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
break;
}
/* Is this a literal string? */
if (literal) {
value = xstrdup(copy);
goto done;
}
/* Is this a comparison or a conditional? */
if (search) {
/* Search in pane. */
@@ -1000,14 +1054,24 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
free(left);
} else if (*copy == '?') {
/* Conditional: check first and choose second or third. */
ptr = format_skip(copy);
ptr = (char *)format_skip(copy, ',');
if (ptr == NULL)
goto fail;
*ptr = '\0';
found = format_find(ft, copy + 1, modifiers);
if (found == NULL)
if (found == NULL) {
/*
* If the conditional not found, try to expand it. If
* the expansion doesn't have any effect, then assume
* false.
*/
found = format_expand(ft, copy + 1);
if (strcmp(found, copy + 1) == 0) {
free(found);
found = xstrdup("");
}
}
if (format_choose(ptr + 1, &left, &right) != 0)
goto fail;
@@ -1062,6 +1126,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
value = new;
}
done:
/* Expand the buffer and copy in the value. */
valuelen = strlen(value);
while (*len - *off < valuelen + 1) {
@@ -1102,7 +1167,7 @@ format_expand_time(struct format_tree *ft, const char *fmt, time_t t)
char *
format_expand(struct format_tree *ft, const char *fmt)
{
char *buf, *out;
char *buf, *out, *name;
const char *ptr, *s, *saved = fmt;
size_t off, len, n, outlen;
int ch, brackets;
@@ -1141,8 +1206,11 @@ format_expand(struct format_tree *ft, const char *fmt)
if (ft->flags & FORMAT_NOJOBS)
out = xstrdup("");
else
out = format_job_get(ft, xstrndup(fmt, n));
else {
name = xstrndup(fmt, n);
out = format_job_get(ft, name);
free(name);
}
outlen = strlen(out);
while (len - off < outlen + 1) {
@@ -1157,14 +1225,8 @@ format_expand(struct format_tree *ft, const char *fmt)
fmt += n + 1;
continue;
case '{':
brackets = 1;
for (ptr = fmt; *ptr != '\0'; ptr++) {
if (*ptr == '{')
brackets++;
if (*ptr == '}' && --brackets == 0)
break;
}
if (*ptr != '}' || brackets != 0)
ptr = format_skip(fmt - 2, '}');
if (ptr == NULL)
break;
n = ptr - fmt;
@@ -1172,12 +1234,14 @@ format_expand(struct format_tree *ft, const char *fmt)
break;
fmt += n + 1;
continue;
case '}':
case '#':
case ',':
while (len - off < 2) {
buf = xreallocarray(buf, 2, len);
len *= 2;
}
buf[off++] = '#';
buf[off++] = ch;
continue;
default:
s = NULL;
@@ -1232,6 +1296,9 @@ void
format_defaults(struct format_tree *ft, struct client *c, struct session *s,
struct winlink *wl, struct window_pane *wp)
{
if (c != NULL && s != NULL && c->session != s)
log_debug("%s: session does not match", __func__);
format_add(ft, "session_format", "%d", s != NULL);
format_add(ft, "window_format", "%d", wl != NULL);
format_add(ft, "pane_format", "%d", wp != NULL);
@@ -1269,8 +1336,13 @@ format_defaults_session(struct format_tree *ft, struct session *s)
sg = session_group_contains(s);
format_add(ft, "session_grouped", "%d", sg != NULL);
if (sg != NULL)
if (sg != NULL) {
format_add(ft, "session_group", "%s", sg->name);
format_add(ft, "session_group_size", "%u",
session_group_count (sg));
format_add_cb(ft, "session_group_list",
format_cb_session_group_list);
}
format_add_tv(ft, "session_created", &s->creation_time);
format_add_tv(ft, "session_last_attached", &s->last_attached_time);
@@ -1392,8 +1464,8 @@ void
format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
{
struct grid *gd = wp->base.grid;
int status = wp->status;
u_int idx;
int status;
if (ft->w == NULL)
ft->w = wp->window;
@@ -1415,8 +1487,7 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
format_add(ft, "pane_input_off", "%d", !!(wp->flags & PANE_INPUTOFF));
format_add(ft, "pane_pipe", "%d", wp->pipe_fd != -1);
status = wp->status;
if (wp->fd == -1 && WIFEXITED(status))
if ((wp->flags & PANE_STATUSREADY) && WIFEXITED(status))
format_add(ft, "pane_dead_status", "%d", WEXITSTATUS(status));
format_add(ft, "pane_dead", "%d", wp->fd == -1);
@@ -1427,8 +1498,10 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
format_add(ft, "pane_bottom", "%u", wp->yoff + wp->sy - 1);
format_add(ft, "pane_at_left", "%d", wp->xoff == 0);
format_add(ft, "pane_at_top", "%d", wp->yoff == 0);
format_add(ft, "pane_at_right", "%d", wp->xoff + wp->sx == wp->window->sx);
format_add(ft, "pane_at_bottom", "%d", wp->yoff + wp->sy == wp->window->sy);
format_add(ft, "pane_at_right", "%d",
wp->xoff + wp->sx == wp->window->sx);
format_add(ft, "pane_at_bottom", "%d",
wp->yoff + wp->sy == wp->window->sy);
}
format_add(ft, "pane_in_mode", "%d", wp->screen != &wp->base);

View File

@@ -64,7 +64,7 @@ grid_view_clear_history(struct grid *gd, u_int bg)
/* Find the last used line. */
last = 0;
for (yy = 0; yy < gd->sy; yy++) {
gl = &gd->linedata[grid_view_y(gd, yy)];
gl = grid_get_line(gd, grid_view_y(gd, yy));
if (gl->cellused != 0)
last = yy + 1;
}

574
grid.c
View File

@@ -43,22 +43,8 @@ static const struct grid_cell_entry grid_default_entry = {
0, { .data = { 0, 8, 8, ' ' } }
};
static void grid_expand_line(struct grid *, u_int, u_int, u_int);
static void grid_empty_line(struct grid *, u_int, u_int);
static void grid_reflow_copy(struct grid_line *, u_int, struct grid_line *,
u_int, u_int);
static void grid_reflow_join(struct grid *, u_int *, struct grid_line *,
u_int);
static void grid_reflow_split(struct grid *, u_int *, struct grid_line *,
u_int, u_int);
static void grid_reflow_move(struct grid *, u_int *, struct grid_line *);
static size_t grid_string_cells_fg(const struct grid_cell *, int *);
static size_t grid_string_cells_bg(const struct grid_cell *, int *);
static void grid_string_cells_code(const struct grid_cell *,
const struct grid_cell *, char *, size_t, int);
/* Store cell in entry. */
static void
grid_store_cell(struct grid_cell_entry *gce, const struct grid_cell *gc,
@@ -159,6 +145,20 @@ grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
return (gcp);
}
/* Get line data. */
struct grid_line *
grid_get_line(struct grid *gd, u_int line)
{
return (&gd->linedata[line]);
}
/* Adjust number of lines. */
void
grid_adjust_lines(struct grid *gd, u_int lines)
{
gd->linedata = xreallocarray(gd->linedata, lines, sizeof *gd->linedata);
}
/* Copy default into a cell. */
static void
grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg)
@@ -180,10 +180,10 @@ grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg)
/* Check grid y position. */
static int
grid_check_y(struct grid *gd, u_int py)
grid_check_y(struct grid *gd, const char* from, u_int py)
{
if ((py) >= (gd)->hsize + (gd)->sy) {
log_debug("y out of range: %u", py);
if (py >= gd->hsize + gd->sy) {
log_debug("%s: y out of range: %u", from, py);
return (-1);
}
return (0);
@@ -240,7 +240,10 @@ grid_create(u_int sx, u_int sy, u_int hlimit)
gd->hsize = 0;
gd->hlimit = hlimit;
gd->linedata = xcalloc(gd->sy, sizeof *gd->linedata);
if (gd->sy != 0)
gd->linedata = xcalloc(gd->sy, sizeof *gd->linedata);
else
gd->linedata = NULL;
return (gd);
}
@@ -283,6 +286,15 @@ grid_compare(struct grid *ga, struct grid *gb)
return (0);
}
/* Trim lines from the history. */
static void
grid_trim_history(struct grid *gd, u_int ny)
{
grid_free_lines(gd, 0, ny);
memmove(&gd->linedata[0], &gd->linedata[ny],
(gd->hsize + gd->sy - ny) * (sizeof *gd->linedata));
}
/*
* Collect lines from the history if at the limit. Free the top (oldest) 10%
* and shift up.
@@ -305,9 +317,7 @@ grid_collect_history(struct grid *gd)
* Free the lines from 0 to ny then move the remaining lines over
* them.
*/
grid_free_lines(gd, 0, ny);
memmove(&gd->linedata[0], &gd->linedata[ny],
(gd->hsize + gd->sy - ny) * (sizeof *gd->linedata));
grid_trim_history(gd, ny);
gd->hsize -= ny;
if (gd->hscrolled > gd->hsize)
@@ -337,9 +347,7 @@ grid_scroll_history(struct grid *gd, u_int bg)
void
grid_clear_history(struct grid *gd)
{
grid_free_lines(gd, 0, gd->hsize);
memmove(&gd->linedata[0], &gd->linedata[gd->hsize],
gd->sy * (sizeof *gd->linedata));
grid_trim_history(gd, gd->hsize);
gd->hscrolled = 0;
gd->hsize = 0;
@@ -418,25 +426,16 @@ grid_empty_line(struct grid *gd, u_int py, u_int bg)
const struct grid_line *
grid_peek_line(struct grid *gd, u_int py)
{
if (grid_check_y(gd, py) != 0)
if (grid_check_y(gd, __func__, py) != 0)
return (NULL);
return (&gd->linedata[py]);
}
/* Get cell for reading. */
void
grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc)
/* Get cell from line. */
static void
grid_get_cell1(struct grid_line *gl, u_int px, struct grid_cell *gc)
{
struct grid_line *gl;
struct grid_cell_entry *gce;
if (grid_check_y(gd, py) != 0 || px >= gd->linedata[py].cellsize) {
memcpy(gc, &grid_default_cell, sizeof *gc);
return;
}
gl = &gd->linedata[py];
gce = &gl->celldata[px];
struct grid_cell_entry *gce = &gl->celldata[px];
if (gce->flags & GRID_FLAG_EXTENDED) {
if (gce->offset >= gl->extdsize)
@@ -457,6 +456,18 @@ grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc)
utf8_set(&gc->data, gce->data.data);
}
/* Get cell for reading. */
void
grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc)
{
if (grid_check_y(gd, __func__, py) != 0 ||
px >= gd->linedata[py].cellsize) {
memcpy(gc, &grid_default_cell, sizeof *gc);
return;
}
return (grid_get_cell1(&gd->linedata[py], px, gc));
}
/* Set cell at relative position. */
void
grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
@@ -464,7 +475,7 @@ grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
struct grid_line *gl;
struct grid_cell_entry *gce;
if (grid_check_y(gd, py) != 0)
if (grid_check_y(gd, __func__, py) != 0)
return;
grid_expand_line(gd, py, px + 1, 8);
@@ -490,7 +501,7 @@ grid_set_cells(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc,
struct grid_cell *gcp;
u_int i;
if (grid_check_y(gd, py) != 0)
if (grid_check_y(gd, __func__, py) != 0)
return;
grid_expand_line(gd, py, px + slen, 8);
@@ -523,9 +534,9 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, u_int bg)
return;
}
if (grid_check_y(gd, py) != 0)
if (grid_check_y(gd, __func__, py) != 0)
return;
if (grid_check_y(gd, py + ny - 1) != 0)
if (grid_check_y(gd, __func__, py + ny - 1) != 0)
return;
for (yy = py; yy < py + ny; yy++) {
@@ -552,9 +563,9 @@ grid_clear_lines(struct grid *gd, u_int py, u_int ny, u_int bg)
if (ny == 0)
return;
if (grid_check_y(gd, py) != 0)
if (grid_check_y(gd, __func__, py) != 0)
return;
if (grid_check_y(gd, py + ny - 1) != 0)
if (grid_check_y(gd, __func__, py + ny - 1) != 0)
return;
for (yy = py; yy < py + ny; yy++) {
@@ -572,13 +583,13 @@ grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny, u_int bg)
if (ny == 0 || py == dy)
return;
if (grid_check_y(gd, py) != 0)
if (grid_check_y(gd, __func__, py) != 0)
return;
if (grid_check_y(gd, py + ny - 1) != 0)
if (grid_check_y(gd, __func__, py + ny - 1) != 0)
return;
if (grid_check_y(gd, dy) != 0)
if (grid_check_y(gd, __func__, dy) != 0)
return;
if (grid_check_y(gd, dy + ny - 1) != 0)
if (grid_check_y(gd, __func__, dy + ny - 1) != 0)
return;
/* Free any lines which are being replaced. */
@@ -612,7 +623,7 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx,
if (nx == 0 || px == dx)
return;
if (grid_check_y(gd, py) != 0)
if (grid_check_y(gd, __func__, py) != 0)
return;
gl = &gd->linedata[py];
@@ -953,164 +964,327 @@ grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy,
}
}
/* Copy a section of a line. */
/* Mark line as dead. */
static void
grid_reflow_copy(struct grid_line *dst_gl, u_int to, struct grid_line *src_gl,
u_int from, u_int to_copy)
grid_reflow_dead(struct grid_line *gl)
{
struct grid_cell_entry *gce;
u_int i, was;
memset(gl, 0, sizeof *gl);
gl->flags = GRID_LINE_DEAD;
}
memcpy(&dst_gl->celldata[to], &src_gl->celldata[from],
to_copy * sizeof *dst_gl->celldata);
/* Add lines, return the first new one. */
static struct grid_line *
grid_reflow_add(struct grid *gd, u_int n)
{
struct grid_line *gl;
u_int sy = gd->sy + n;
for (i = to; i < to + to_copy; i++) {
gce = &dst_gl->celldata[i];
if (~gce->flags & GRID_FLAG_EXTENDED)
gd->linedata = xreallocarray(gd->linedata, sy, sizeof *gd->linedata);
gl = &gd->linedata[gd->sy];
memset(gl, 0, n * (sizeof *gl));
gd->sy = sy;
return (gl);
}
/* Move a line across. */
static struct grid_line *
grid_reflow_move(struct grid *gd, struct grid_line *from)
{
struct grid_line *to;
to = grid_reflow_add(gd, 1);
memcpy(to, from, sizeof *to);
grid_reflow_dead(from);
return (to);
}
/* Join line below onto this one. */
static void
grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy,
u_int width, u_int *cy, int already)
{
struct grid_line *gl, *from = NULL;
struct grid_cell gc;
u_int lines, left, i, to, line, want = 0;
u_int at;
int wrapped = 1;
/*
* Add a new target line.
*/
if (!already) {
to = target->sy;
gl = grid_reflow_move(target, &gd->linedata[yy]);
} else {
to = target->sy - 1;
gl = &target->linedata[to];
}
at = gl->cellused;
/*
* Loop until no more to consume or the target line is full.
*/
lines = 0;
for (;;) {
/*
* If this is now the last line, there is nothing more to be
* done.
*/
if (yy + 1 + lines == gd->hsize + gd->sy)
break;
line = yy + 1 + lines;
/* If the next line is empty, skip it. */
if (~gd->linedata[line].flags & GRID_LINE_WRAPPED)
wrapped = 0;
if (gd->linedata[line].cellused == 0) {
if (!wrapped)
break;
lines++;
continue;
was = gce->offset;
dst_gl->extddata = xreallocarray(dst_gl->extddata,
dst_gl->extdsize + 1, sizeof *dst_gl->extddata);
gce->offset = dst_gl->extdsize++;
memcpy(&dst_gl->extddata[gce->offset], &src_gl->extddata[was],
sizeof *dst_gl->extddata);
}
}
/* Join line data. */
static void
grid_reflow_join(struct grid *dst, u_int *py, struct grid_line *src_gl,
u_int new_x)
{
struct grid_line *dst_gl = &dst->linedata[(*py) - 1];
u_int left, to_copy, ox, nx;
/* How much is left on the old line? */
left = new_x - dst_gl->cellused;
/* Work out how much to append. */
to_copy = src_gl->cellused;
if (to_copy > left)
to_copy = left;
ox = dst_gl->cellused;
nx = ox + to_copy;
/* Resize the destination line. */
dst_gl->celldata = xreallocarray(dst_gl->celldata, nx,
sizeof *dst_gl->celldata);
dst_gl->cellsize = dst_gl->cellused = nx;
/* Append as much as possible. */
grid_reflow_copy(dst_gl, ox, src_gl, 0, to_copy);
/* If there is any left in the source, split it. */
if (src_gl->cellused > to_copy) {
dst_gl->flags |= GRID_LINE_WRAPPED;
src_gl->cellused -= to_copy;
grid_reflow_split(dst, py, src_gl, new_x, to_copy);
}
}
/* Split line data. */
static void
grid_reflow_split(struct grid *dst, u_int *py, struct grid_line *src_gl,
u_int new_x, u_int offset)
{
struct grid_line *dst_gl = NULL;
u_int to_copy;
/* Loop and copy sections of the source line. */
while (src_gl->cellused > 0) {
/* Create new line. */
if (*py >= dst->hsize + dst->sy)
grid_scroll_history(dst, 8);
dst_gl = &dst->linedata[*py];
(*py)++;
/* How much should we copy? */
to_copy = new_x;
if (to_copy > src_gl->cellused)
to_copy = src_gl->cellused;
/* Expand destination line. */
dst_gl->celldata = xreallocarray(NULL, to_copy,
sizeof *dst_gl->celldata);
dst_gl->cellsize = dst_gl->cellused = to_copy;
dst_gl->flags |= GRID_LINE_WRAPPED;
/* Copy the data. */
grid_reflow_copy(dst_gl, 0, src_gl, offset, to_copy);
/* Move offset and reduce old line size. */
offset += to_copy;
src_gl->cellused -= to_copy;
}
/* Last line is not wrapped. */
if (dst_gl != NULL)
dst_gl->flags &= ~GRID_LINE_WRAPPED;
}
/* Move line data. */
static void
grid_reflow_move(struct grid *dst, u_int *py, struct grid_line *src_gl)
{
struct grid_line *dst_gl;
/* Create new line. */
if (*py >= dst->hsize + dst->sy)
grid_scroll_history(dst, 8);
dst_gl = &dst->linedata[*py];
(*py)++;
/* Copy the old line. */
memcpy(dst_gl, src_gl, sizeof *dst_gl);
dst_gl->flags &= ~GRID_LINE_WRAPPED;
/* Clear old line. */
src_gl->celldata = NULL;
src_gl->extddata = NULL;
}
/*
* Reflow lines from src grid into dst grid of width new_x. Returns number of
* lines fewer in the visible area. The source grid is destroyed.
*/
u_int
grid_reflow(struct grid *dst, struct grid *src, u_int new_x)
{
u_int py, sy, line;
int previous_wrapped;
struct grid_line *src_gl;
py = 0;
sy = src->sy;
previous_wrapped = 0;
for (line = 0; line < sy + src->hsize; line++) {
src_gl = src->linedata + line;
if (!previous_wrapped) {
/* Wasn't wrapped. If smaller, move to destination. */
if (src_gl->cellused <= new_x)
grid_reflow_move(dst, &py, src_gl);
else
grid_reflow_split(dst, &py, src_gl, new_x, 0);
} else {
/* Previous was wrapped. Try to join. */
grid_reflow_join(dst, &py, src_gl, new_x);
}
previous_wrapped = (src_gl->flags & GRID_LINE_WRAPPED);
/* This is where we started scrolling. */
if (line == sy + src->hsize - src->hscrolled - 1)
dst->hscrolled = 0;
/*
* Is the destination line now full? Copy the first character
* separately because we need to leave "from" set to the last
* line if this line is full.
*/
grid_get_cell1(&gd->linedata[line], 0, &gc);
if (width + gc.data.width > sx)
break;
width += gc.data.width;
grid_set_cell(target, at, to, &gc);
at++;
/* Join as much more as possible onto the current line. */
from = &gd->linedata[line];
for (want = 1; want < from->cellused; want++) {
grid_get_cell1(from, want, &gc);
if (width + gc.data.width > sx)
break;
width += gc.data.width;
grid_set_cell(target, at, to, &gc);
at++;
}
lines++;
/*
* If this line wasn't wrapped or we didn't consume the entire
* line, don't try to join any further lines.
*/
if (!wrapped || want != from->cellused || width == sx)
break;
}
if (lines == 0)
return;
/*
* If we didn't consume the entire final line, then remove what we did
* consume. If we consumed the entire line and it wasn't wrapped,
* remove the wrap flag from this line.
*/
left = from->cellused - want;
if (left != 0) {
grid_move_cells(gd, 0, want, yy + lines, left, 8);
from->cellsize = from->cellused = left;
lines--;
} else if (!wrapped)
gl->flags &= ~GRID_LINE_WRAPPED;
/* Remove the lines that were completely consumed. */
for (i = yy + 1; i < yy + 1 + lines; i++) {
free(gd->linedata[i].celldata);
free(gd->linedata[i].extddata);
grid_reflow_dead(&gd->linedata[i]);
}
grid_destroy(src);
if (py > sy)
return (0);
return (sy - py);
/* Adjust cursor and scroll positions. */
if (*cy > to + lines)
*cy -= lines;
else if (*cy > to)
*cy = to;
if (gd->hscrolled > to + lines)
gd->hscrolled -= lines;
else if (gd->hscrolled > to)
gd->hscrolled = to;
}
/* Split this line into several new ones */
static void
grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy,
u_int at, u_int *cy)
{
struct grid_line *gl = &gd->linedata[yy], *first;
struct grid_cell gc;
u_int line, lines, width, i, xx;
u_int used = gl->cellused;
int flags = gl->flags;
/* How many lines do we need to insert? We know we need at least two. */
if (~gl->flags & GRID_LINE_EXTENDED)
lines = 1 + (gl->cellused - 1) / sx;
else {
lines = 2;
width = 0;
for (i = at; i < used; i++) {
grid_get_cell1(gl, i, &gc);
if (width + gc.data.width > sx) {
lines++;
width = 0;
}
width += gc.data.width;
}
}
/* Insert new lines. */
line = target->sy + 1;
first = grid_reflow_add(target, lines);
/* Copy sections from the original line. */
width = 0;
xx = 0;
for (i = at; i < used; i++) {
grid_get_cell1(gl, i, &gc);
if (width + gc.data.width > sx) {
target->linedata[line].flags |= GRID_LINE_WRAPPED;
line++;
width = 0;
xx = 0;
}
width += gc.data.width;
grid_set_cell(target, xx, line, &gc);
xx++;
}
if (flags & GRID_LINE_WRAPPED)
target->linedata[line].flags |= GRID_LINE_WRAPPED;
/* Move the remainder of the original line. */
gl->cellsize = gl->cellused = at;
gl->flags |= GRID_LINE_WRAPPED;
memcpy(first, gl, sizeof *first);
grid_reflow_dead(gl);
/* Adjust the cursor and scroll positions. */
if (yy <= *cy)
(*cy) += lines - 1;
if (yy <= gd->hscrolled)
gd->hscrolled += lines - 1;
/*
* If the original line had the wrapped flag and there is still space
* in the last new line, try to join with the next lines.
*/
if (width < sx && (flags & GRID_LINE_WRAPPED))
grid_reflow_join(target, gd, sx, yy, width, cy, 1);
}
/* Reflow lines on grid to new width. */
void
grid_reflow(struct grid *gd, u_int sx, u_int *cursor)
{
struct grid *target;
struct grid_line *gl;
struct grid_cell gc;
u_int yy, cy, width, i, at, first;
struct timeval start, tv;
gettimeofday(&start, NULL);
log_debug("%s: %u lines, new width %u", __func__, gd->hsize + gd->sy,
sx);
cy = gd->hsize + (*cursor);
/*
* Create a destination grid. This is just used as a container for the
* line data and may not be fully valid.
*/
target = grid_create(gd->sx, 0, 0);
/*
* Loop over each source line.
*/
for (yy = 0; yy < gd->hsize + gd->sy; yy++) {
gl = &gd->linedata[yy];
if (gl->flags & GRID_LINE_DEAD)
continue;
/*
* Work out the width of this line. first is the width of the
* first character, at is the point at which the available
* width is hit, and width is the full line width.
*/
first = at = width = 0;
if (~gl->flags & GRID_LINE_EXTENDED) {
first = 1;
width = gl->cellused;
if (width > sx)
at = sx;
else
at = width;
} else {
for (i = 0; i < gl->cellused; i++) {
grid_get_cell1(gl, i, &gc);
if (i == 0)
first = gc.data.width;
if (at == 0 && width + gc.data.width > sx)
at = i;
width += gc.data.width;
}
}
/*
* If the line is exactly right or the first character is wider
* than the targe width, just move it across unchanged.
*/
if (width == sx || first > sx) {
grid_reflow_move(target, gl);
continue;
}
/*
* If the line is too big, it needs to be split, whether or not
* it was previously wrapped.
*/
if (width > sx) {
grid_reflow_split(target, gd, sx, yy, at, &cy);
continue;
}
/*
* If the line was previously wrapped, join as much as possible
* of the next line.
*/
if (gl->flags & GRID_LINE_WRAPPED)
grid_reflow_join(target, gd, sx, yy, width, &cy, 0);
else
grid_reflow_move(target, gl);
}
/*
* Replace the old grid with the new.
*/
if (target->sy < gd->sy)
grid_reflow_add(target, gd->sy - target->sy);
gd->hsize = target->sy - gd->sy;
free(gd->linedata);
gd->linedata = target->linedata;
free(target);
/*
* Update scrolled and cursor positions.
*/
if (gd->hscrolled > gd->hsize)
gd->hscrolled = gd->hsize;
if (cy < gd->hsize)
*cursor = 0;
else
*cursor = cy - gd->hsize;
gettimeofday(&tv, NULL);
timersub(&tv, &start, &tv);
log_debug("%s: now %u lines (in %llu.%06u seconds)", __func__,
gd->hsize + gd->sy, (unsigned long long)tv.tv_sec,
(u_int)tv.tv_usec);
}

27
hooks.c
View File

@@ -139,33 +139,6 @@ hooks_find(struct hooks *hooks, const char *name)
return (hook);
}
void
hooks_run(struct hooks *hooks, struct client *c, struct cmd_find_state *fs,
const char *fmt, ...)
{
struct hook *hook;
va_list ap;
char *name;
struct cmdq_item *new_item;
va_start(ap, fmt);
xvasprintf(&name, fmt, ap);
va_end(ap);
hook = hooks_find(hooks, name);
if (hook == NULL) {
free(name);
return;
}
log_debug("running hook %s", name);
new_item = cmdq_get_command(hook->cmdlist, fs, NULL, CMDQ_NOHOOKS);
cmdq_format(new_item, "hook", "%s", name);
cmdq_append(c, new_item);
free(name);
}
void
hooks_insert(struct hooks *hooks, struct cmdq_item *item,
struct cmd_find_state *fs, const char *fmt, ...)

469
input.c
View File

@@ -30,7 +30,7 @@
/*
* Based on the description by Paul Williams at:
*
* http://vt100.net/emu/dec_ansi_parser
* https://vt100.net/emu/dec_ansi_parser
*
* With the following changes:
*
@@ -58,6 +58,19 @@ struct input_cell {
int g1set; /* 1 if ACS */
};
/* Input parser argument. */
struct input_param {
enum {
INPUT_MISSING,
INPUT_NUMBER,
INPUT_STRING
} type;
union {
int num;
char *str;
};
};
/* Input parser context. */
struct input_ctx {
struct window_pane *wp;
@@ -81,10 +94,11 @@ struct input_ctx {
size_t input_len;
size_t input_space;
int param_list[24]; /* -1 not present */
struct input_param param_list[24];
u_int param_list_len;
struct utf8_data utf8data;
int utf8started;
int ch;
int last;
@@ -146,9 +160,7 @@ static void input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *);
static void input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *);
static void input_csi_dispatch_sgr(struct input_ctx *);
static int input_dcs_dispatch(struct input_ctx *);
static int input_utf8_open(struct input_ctx *);
static int input_utf8_add(struct input_ctx *);
static int input_utf8_close(struct input_ctx *);
static int input_top_bit_set(struct input_ctx *);
/* Command table comparison function. */
static int input_table_compare(const void *, const void *);
@@ -314,9 +326,6 @@ static const struct input_transition input_state_osc_string_table[];
static const struct input_transition input_state_apc_string_table[];
static const struct input_transition input_state_rename_string_table[];
static const struct input_transition input_state_consume_st_table[];
static const struct input_transition input_state_utf8_three_table[];
static const struct input_transition input_state_utf8_two_table[];
static const struct input_transition input_state_utf8_one_table[];
/* ground state definition. */
static const struct input_state input_state_ground = {
@@ -437,27 +446,6 @@ static const struct input_state input_state_consume_st = {
input_state_consume_st_table
};
/* utf8_three state definition. */
static const struct input_state input_state_utf8_three = {
"utf8_three",
NULL, NULL,
input_state_utf8_three_table
};
/* utf8_two state definition. */
static const struct input_state input_state_utf8_two = {
"utf8_two",
NULL, NULL,
input_state_utf8_two_table
};
/* utf8_one state definition. */
static const struct input_state input_state_utf8_one = {
"utf8_one",
NULL, NULL,
input_state_utf8_one_table
};
/* ground state table. */
static const struct input_transition input_state_ground_table[] = {
INPUT_STATE_ANYWHERE,
@@ -467,11 +455,7 @@ static const struct input_transition input_state_ground_table[] = {
{ 0x1c, 0x1f, input_c0_dispatch, NULL },
{ 0x20, 0x7e, input_print, NULL },
{ 0x7f, 0x7f, NULL, NULL },
{ 0x80, 0xc1, NULL, NULL },
{ 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one },
{ 0xe0, 0xef, input_utf8_open, &input_state_utf8_two },
{ 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three },
{ 0xf5, 0xff, NULL, NULL },
{ 0x80, 0xff, input_top_bit_set, NULL },
{ -1, -1, NULL, NULL }
};
@@ -526,7 +510,7 @@ static const struct input_transition input_state_csi_enter_table[] = {
{ 0x1c, 0x1f, input_c0_dispatch, NULL },
{ 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
{ 0x30, 0x39, input_parameter, &input_state_csi_parameter },
{ 0x3a, 0x3a, NULL, &input_state_csi_ignore },
{ 0x3a, 0x3a, input_parameter, &input_state_csi_parameter },
{ 0x3b, 0x3b, input_parameter, &input_state_csi_parameter },
{ 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
@@ -544,7 +528,7 @@ static const struct input_transition input_state_csi_parameter_table[] = {
{ 0x1c, 0x1f, input_c0_dispatch, NULL },
{ 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
{ 0x30, 0x39, input_parameter, NULL },
{ 0x3a, 0x3a, NULL, &input_state_csi_ignore },
{ 0x3a, 0x3a, input_parameter, NULL },
{ 0x3b, 0x3b, input_parameter, NULL },
{ 0x3c, 0x3f, NULL, &input_state_csi_ignore },
{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
@@ -717,39 +701,6 @@ static const struct input_transition input_state_consume_st_table[] = {
{ -1, -1, NULL, NULL }
};
/* utf8_three state table. */
static const struct input_transition input_state_utf8_three_table[] = {
/* No INPUT_STATE_ANYWHERE */
{ 0x00, 0x7f, NULL, &input_state_ground },
{ 0x80, 0xbf, input_utf8_add, &input_state_utf8_two },
{ 0xc0, 0xff, NULL, &input_state_ground },
{ -1, -1, NULL, NULL }
};
/* utf8_two state table. */
static const struct input_transition input_state_utf8_two_table[] = {
/* No INPUT_STATE_ANYWHERE */
{ 0x00, 0x7f, NULL, &input_state_ground },
{ 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
{ 0xc0, 0xff, NULL, &input_state_ground },
{ -1, -1, NULL, NULL }
};
/* utf8_one state table. */
static const struct input_transition input_state_utf8_one_table[] = {
/* No INPUT_STATE_ANYWHERE */
{ 0x00, 0x7f, NULL, &input_state_ground },
{ 0x80, 0xbf, input_utf8_close, &input_state_ground },
{ 0xc0, 0xff, NULL, &input_state_ground },
{ -1, -1, NULL, NULL }
};
/* Input table compare. */
static int
input_table_compare(const void *key, const void *value)
@@ -822,6 +773,12 @@ void
input_free(struct window_pane *wp)
{
struct input_ctx *ictx = wp->ictx;
u_int i;
for (i = 0; i < ictx->param_list_len; i++) {
if (ictx->param_list[i].type == INPUT_STRING)
free(ictx->param_list[i].str);
}
event_del(&ictx->timer);
@@ -964,29 +921,51 @@ input_parse(struct window_pane *wp)
static int
input_split(struct input_ctx *ictx)
{
const char *errstr;
char *ptr, *out;
int n;
const char *errstr;
char *ptr, *out;
struct input_param *ip;
u_int i;
for (i = 0; i < ictx->param_list_len; i++) {
if (ictx->param_list[i].type == INPUT_STRING)
free(ictx->param_list[i].str);
}
ictx->param_list_len = 0;
if (ictx->param_len == 0)
return (0);
ip = &ictx->param_list[0];
ptr = ictx->param_buf;
while ((out = strsep(&ptr, ";")) != NULL) {
if (*out == '\0')
n = -1;
ip->type = INPUT_MISSING;
else {
n = strtonum(out, 0, INT_MAX, &errstr);
if (errstr != NULL)
return (-1);
if (strchr(out, ':') != NULL) {
ip->type = INPUT_STRING;
ip->str = xstrdup(out);
} else {
ip->type = INPUT_NUMBER;
ip->num = strtonum(out, 0, INT_MAX, &errstr);
if (errstr != NULL)
return (-1);
}
}
ictx->param_list[ictx->param_list_len++] = n;
ip = &ictx->param_list[++ictx->param_list_len];
if (ictx->param_list_len == nitems(ictx->param_list))
return (-1);
}
for (i = 0; i < ictx->param_list_len; i++) {
ip = &ictx->param_list[i];
if (ip->type == INPUT_MISSING)
log_debug("parameter %u: missing", i);
else if (ip->type == INPUT_STRING)
log_debug("parameter %u: string %s", i, ip->str);
else if (ip->type == INPUT_NUMBER)
log_debug("parameter %u: number %d", i, ip->num);
}
return (0);
}
@@ -994,14 +973,17 @@ input_split(struct input_ctx *ictx)
static int
input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
{
int retval;
struct input_param *ip;
int retval;
if (validx >= ictx->param_list_len)
return (defval);
retval = ictx->param_list[validx];
if (retval == -1)
ip = &ictx->param_list[validx];
if (ip->type == INPUT_MISSING)
return (defval);
if (ip->type == INPUT_STRING)
return (-1);
retval = ip->num;
if (retval < minval)
return (minval);
return (retval);
@@ -1059,6 +1041,8 @@ input_print(struct input_ctx *ictx)
{
int set;
ictx->utf8started = 0; /* can't be valid UTF-8 */
set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set;
if (set == 1)
ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
@@ -1132,6 +1116,8 @@ input_c0_dispatch(struct input_ctx *ictx)
struct window_pane *wp = ictx->wp;
struct screen *s = sctx->s;
ictx->utf8started = 0; /* can't be valid UTF-8 */
log_debug("%s: '%c'", __func__, ictx->ch);
switch (ictx->ch) {
@@ -1202,6 +1188,7 @@ input_esc_dispatch(struct input_ctx *ictx)
window_pane_reset_palette(ictx->wp);
input_reset_cell(ictx);
screen_write_reset(sctx);
screen_write_clearhistory(sctx);
break;
case INPUT_ESC_IND:
screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
@@ -1264,7 +1251,7 @@ input_csi_dispatch(struct input_ctx *ictx)
struct screen *s = sctx->s;
struct input_table_entry *entry;
int i, n, m;
u_int cx;
u_int cx, bg = ictx->cell.cell.bg;
if (ictx->flags & INPUT_DISCARD)
return (0);
@@ -1289,6 +1276,8 @@ input_csi_dispatch(struct input_ctx *ictx)
if (cx > screen_size_x(s) - 1)
cx = screen_size_x(s) - 1;
n = input_get(ictx, 0, 1, 1);
if (n == -1)
break;
while (cx > 0 && n-- > 0) {
do
cx--;
@@ -1297,35 +1286,52 @@ input_csi_dispatch(struct input_ctx *ictx)
s->cx = cx;
break;
case INPUT_CSI_CUB:
screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1));
n = input_get(ictx, 0, 1, 1);
if (n != -1)
screen_write_cursorleft(sctx, n);
break;
case INPUT_CSI_CUD:
screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
n = input_get(ictx, 0, 1, 1);
if (n != -1)
screen_write_cursordown(sctx, n);
break;
case INPUT_CSI_CUF:
screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1));
n = input_get(ictx, 0, 1, 1);
if (n != -1)
screen_write_cursorright(sctx, n);
break;
case INPUT_CSI_CUP:
n = input_get(ictx, 0, 1, 1);
m = input_get(ictx, 1, 1, 1);
screen_write_cursormove(sctx, m - 1, n - 1);
if (n != -1 && m != -1)
screen_write_cursormove(sctx, m - 1, n - 1);
break;
case INPUT_CSI_WINOPS:
input_csi_dispatch_winops(ictx);
break;
case INPUT_CSI_CUU:
screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
n = input_get(ictx, 0, 1, 1);
if (n != -1)
screen_write_cursorup(sctx, n);
break;
case INPUT_CSI_CNL:
screen_write_carriagereturn(sctx);
screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
n = input_get(ictx, 0, 1, 1);
if (n != -1) {
screen_write_carriagereturn(sctx);
screen_write_cursordown(sctx, n);
}
break;
case INPUT_CSI_CPL:
screen_write_carriagereturn(sctx);
screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
n = input_get(ictx, 0, 1, 1);
if (n != -1) {
screen_write_carriagereturn(sctx);
screen_write_cursorup(sctx, n);
}
break;
case INPUT_CSI_DA:
switch (input_get(ictx, 0, 0, 0)) {
case -1:
break;
case 0:
input_reply(ictx, "\033[?1;2c");
break;
@@ -1336,6 +1342,8 @@ input_csi_dispatch(struct input_ctx *ictx)
break;
case INPUT_CSI_DA_TWO:
switch (input_get(ictx, 0, 0, 0)) {
case -1:
break;
case 0:
input_reply(ictx, "\033[>84;0;0c");
break;
@@ -1345,24 +1353,30 @@ input_csi_dispatch(struct input_ctx *ictx)
}
break;
case INPUT_CSI_ECH:
screen_write_clearcharacter(sctx, input_get(ictx, 0, 1, 1),
ictx->cell.cell.bg);
n = input_get(ictx, 0, 1, 1);
if (n != -1)
screen_write_clearcharacter(sctx, n, bg);
break;
case INPUT_CSI_DCH:
screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1),
ictx->cell.cell.bg);
n = input_get(ictx, 0, 1, 1);
if (n != -1)
screen_write_deletecharacter(sctx, n, bg);
break;
case INPUT_CSI_DECSTBM:
n = input_get(ictx, 0, 1, 1);
m = input_get(ictx, 1, 1, screen_size_y(s));
screen_write_scrollregion(sctx, n - 1, m - 1);
if (n != -1 && m != -1)
screen_write_scrollregion(sctx, n - 1, m - 1);
break;
case INPUT_CSI_DL:
screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1),
ictx->cell.cell.bg);
n = input_get(ictx, 0, 1, 1);
if (n != -1)
screen_write_deleteline(sctx, n, bg);
break;
case INPUT_CSI_DSR:
switch (input_get(ictx, 0, 0, 0)) {
case -1:
break;
case 5:
input_reply(ictx, "\033[0n");
break;
@@ -1376,24 +1390,24 @@ input_csi_dispatch(struct input_ctx *ictx)
break;
case INPUT_CSI_ED:
switch (input_get(ictx, 0, 0, 0)) {
case -1:
break;
case 0:
screen_write_clearendofscreen(sctx, ictx->cell.cell.bg);
screen_write_clearendofscreen(sctx, bg);
break;
case 1:
screen_write_clearstartofscreen(sctx, ictx->cell.cell.bg);
screen_write_clearstartofscreen(sctx, bg);
break;
case 2:
screen_write_clearscreen(sctx, ictx->cell.cell.bg);
screen_write_clearscreen(sctx, bg);
break;
case 3:
switch (input_get(ictx, 1, 0, 0)) {
case 0:
if (input_get(ictx, 1, 0, 0) == 0) {
/*
* Linux console extension to clear history
* (for example before locking the screen).
*/
screen_write_clearhistory(sctx);
break;
}
break;
default:
@@ -1403,14 +1417,16 @@ input_csi_dispatch(struct input_ctx *ictx)
break;
case INPUT_CSI_EL:
switch (input_get(ictx, 0, 0, 0)) {
case -1:
break;
case 0:
screen_write_clearendofline(sctx, ictx->cell.cell.bg);
screen_write_clearendofline(sctx, bg);
break;
case 1:
screen_write_clearstartofline(sctx, ictx->cell.cell.bg);
screen_write_clearstartofline(sctx, bg);
break;
case 2:
screen_write_clearline(sctx, ictx->cell.cell.bg);
screen_write_clearline(sctx, bg);
break;
default:
log_debug("%s: unknown '%c'", __func__, ictx->ch);
@@ -1419,22 +1435,28 @@ input_csi_dispatch(struct input_ctx *ictx)
break;
case INPUT_CSI_HPA:
n = input_get(ictx, 0, 1, 1);
screen_write_cursormove(sctx, n - 1, s->cy);
if (n != -1)
screen_write_cursormove(sctx, n - 1, s->cy);
break;
case INPUT_CSI_ICH:
screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1),
ictx->cell.cell.bg);
n = input_get(ictx, 0, 1, 1);
if (n != -1)
screen_write_insertcharacter(sctx, n, bg);
break;
case INPUT_CSI_IL:
screen_write_insertline(sctx, input_get(ictx, 0, 1, 1),
ictx->cell.cell.bg);
n = input_get(ictx, 0, 1, 1);
if (n != -1)
screen_write_insertline(sctx, n, bg);
break;
case INPUT_CSI_REP:
n = input_get(ictx, 0, 1, 1);
if (n == -1)
break;
if (ictx->last == -1)
break;
ictx->ch = ictx->last;
n = input_get(ictx, 0, 1, 1);
for (i = 0; i < n; i++)
input_print(ictx);
break;
@@ -1463,11 +1485,14 @@ input_csi_dispatch(struct input_ctx *ictx)
input_csi_dispatch_sm_private(ictx);
break;
case INPUT_CSI_SU:
screen_write_scrollup(sctx, input_get(ictx, 0, 1, 1),
ictx->cell.cell.bg);
n = input_get(ictx, 0, 1, 1);
if (n != -1)
screen_write_scrollup(sctx, n, bg);
break;
case INPUT_CSI_TBC:
switch (input_get(ictx, 0, 0, 0)) {
case -1:
break;
case 0:
if (s->cx < screen_size_x(s))
bit_clear(s->tabs, s->cx);
@@ -1482,11 +1507,13 @@ input_csi_dispatch(struct input_ctx *ictx)
break;
case INPUT_CSI_VPA:
n = input_get(ictx, 0, 1, 1);
screen_write_cursormove(sctx, s->cx, n - 1);
if (n != -1)
screen_write_cursormove(sctx, s->cx, n - 1);
break;
case INPUT_CSI_DECSCUSR:
n = input_get(ictx, 0, 0, 0);
screen_set_cursor_style(s, n);
if (n != -1)
screen_set_cursor_style(s, n);
break;
}
@@ -1502,6 +1529,8 @@ input_csi_dispatch_rm(struct input_ctx *ictx)
for (i = 0; i < ictx->param_list_len; i++) {
switch (input_get(ictx, i, 0, -1)) {
case -1:
break;
case 4: /* IRM */
screen_write_mode_clear(&ictx->ctx, MODE_INSERT);
break;
@@ -1524,6 +1553,8 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
for (i = 0; i < ictx->param_list_len; i++) {
switch (input_get(ictx, i, 0, -1)) {
case -1:
break;
case 1: /* DECCKM */
screen_write_mode_clear(&ictx->ctx, MODE_KCURSOR);
break;
@@ -1581,6 +1612,8 @@ input_csi_dispatch_sm(struct input_ctx *ictx)
for (i = 0; i < ictx->param_list_len; i++) {
switch (input_get(ictx, i, 0, -1)) {
case -1:
break;
case 4: /* IRM */
screen_write_mode_set(&ictx->ctx, MODE_INSERT);
break;
@@ -1603,6 +1636,8 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
for (i = 0; i < ictx->param_list_len; i++) {
switch (input_get(ictx, i, 0, -1)) {
case -1:
break;
case 1: /* DECCKM */
screen_write_mode_set(&ictx->ctx, MODE_KCURSOR);
break;
@@ -1693,12 +1728,33 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
/* FALLTHROUGH */
case 9:
case 10:
case 22:
case 23:
m++;
if (input_get(ictx, m, 0, -1) == -1)
return;
break;
case 22:
m++;
switch (input_get(ictx, m, 0, -1)) {
case -1:
return;
case 0:
case 2:
screen_push_title(ictx->ctx.s);
break;
}
break;
case 23:
m++;
switch (input_get(ictx, m, 0, -1)) {
case -1:
return;
case 0:
case 2:
screen_pop_title(ictx->ctx.s);
server_status_window(ictx->wp->window);
break;
}
break;
case 18:
input_reply(ictx, "\033[8;%u;%ut", wp->sy, wp->sx);
break;
@@ -1710,16 +1766,13 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
}
}
/* Handle CSI SGR for 256 colours. */
static void
input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i)
/* Helper for 256 colour SGR. */
static int
input_csi_dispatch_sgr_256_do(struct input_ctx *ictx, int fgbg, int c)
{
struct grid_cell *gc = &ictx->cell.cell;
int c;
(*i)++;
c = input_get(ictx, *i, 0, -1);
if (c == -1) {
if (c == -1 || c > 255) {
if (fgbg == 38)
gc->fg = 8;
else if (fgbg == 48)
@@ -1730,32 +1783,99 @@ input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i)
else if (fgbg == 48)
gc->bg = c | COLOUR_FLAG_256;
}
return (1);
}
/* Handle CSI SGR for 256 colours. */
static void
input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i)
{
int c;
c = input_get(ictx, (*i) + 1, 0, -1);
if (input_csi_dispatch_sgr_256_do(ictx, fgbg, c))
(*i)++;
}
/* Helper for RGB colour SGR. */
static int
input_csi_dispatch_sgr_rgb_do(struct input_ctx *ictx, int fgbg, int r, int g,
int b)
{
struct grid_cell *gc = &ictx->cell.cell;
if (r == -1 || r > 255)
return (0);
if (g == -1 || g > 255)
return (0);
if (b == -1 || b > 255)
return (0);
if (fgbg == 38)
gc->fg = colour_join_rgb(r, g, b);
else if (fgbg == 48)
gc->bg = colour_join_rgb(r, g, b);
return (1);
}
/* Handle CSI SGR for RGB colours. */
static void
input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i)
{
struct grid_cell *gc = &ictx->cell.cell;
int r, g, b;
int r, g, b;
(*i)++;
r = input_get(ictx, *i, 0, -1);
if (r == -1 || r > 255)
return;
(*i)++;
g = input_get(ictx, *i, 0, -1);
if (g == -1 || g > 255)
return;
(*i)++;
b = input_get(ictx, *i, 0, -1);
if (b == -1 || b > 255)
return;
r = input_get(ictx, (*i) + 1, 0, -1);
g = input_get(ictx, (*i) + 2, 0, -1);
b = input_get(ictx, (*i) + 3, 0, -1);
if (input_csi_dispatch_sgr_rgb_do(ictx, fgbg, r, g, b))
(*i) += 3;
}
if (fgbg == 38)
gc->fg = colour_join_rgb(r, g, b);
else if (fgbg == 48)
gc->bg = colour_join_rgb(r, g, b);
/* Handle CSI SGR with a ISO parameter. */
static void
input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
{
char *s = ictx->param_list[i].str, *copy, *ptr, *out;
int p[8];
u_int n;
const char *errstr;
for (n = 0; n < nitems(p); n++)
p[n] = -1;
n = 0;
ptr = copy = xstrdup(s);
while ((out = strsep(&ptr, ":")) != NULL) {
if (*out != '\0') {
p[n++] = strtonum(out, 0, INT_MAX, &errstr);
if (errstr != NULL || n == nitems(p)) {
free(copy);
return;
}
}
log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]);
}
free(copy);
if (n == 0 || (p[0] != 38 && p[0] != 48))
return;
if (p[1] == -1)
i = 2;
else
i = 1;
switch (p[i]) {
case 2:
if (n < i + 4)
break;
input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[i + 1], p[i + 2],
p[i + 3]);
break;
case 5:
if (n < i + 2)
break;
input_csi_dispatch_sgr_256_do(ictx, p[0], p[i + 1]);
break;
}
}
/* Handle CSI SGR. */
@@ -1772,7 +1892,13 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
}
for (i = 0; i < ictx->param_list_len; i++) {
if (ictx->param_list[i].type == INPUT_STRING) {
input_csi_dispatch_sgr_colon(ictx, i);
continue;
}
n = input_get(ictx, i, 0, 0);
if (n == -1)
continue;
if (n == 38 || n == 48) {
i++;
@@ -1789,7 +1915,6 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
switch (n) {
case 0:
case 10:
memcpy(gc, &grid_default_cell, sizeof *gc);
break;
case 1:
@@ -2043,48 +2168,30 @@ input_exit_rename(struct input_ctx *ictx)
/* Open UTF-8 character. */
static int
input_utf8_open(struct input_ctx *ictx)
input_top_bit_set(struct input_ctx *ictx)
{
struct utf8_data *ud = &ictx->utf8data;
if (utf8_open(ud, ictx->ch) != UTF8_MORE)
fatalx("UTF-8 open invalid %#x", ictx->ch);
log_debug("%s %hhu", __func__, ud->size);
ictx->last = -1;
return (0);
}
/* Append to UTF-8 character. */
static int
input_utf8_add(struct input_ctx *ictx)
{
struct utf8_data *ud = &ictx->utf8data;
if (utf8_append(ud, ictx->ch) != UTF8_MORE)
fatalx("UTF-8 add invalid %#x", ictx->ch);
log_debug("%s", __func__);
return (0);
}
/* Close UTF-8 string. */
static int
input_utf8_close(struct input_ctx *ictx)
{
struct utf8_data *ud = &ictx->utf8data;
if (utf8_append(ud, ictx->ch) != UTF8_DONE) {
/*
* An error here could be invalid UTF-8 or it could be a
* nonprintable character for which we can't get the
* width. Drop it.
*/
if (!ictx->utf8started) {
if (utf8_open(ud, ictx->ch) != UTF8_MORE)
return (0);
ictx->utf8started = 1;
return (0);
}
switch (utf8_append(ud, ictx->ch)) {
case UTF8_MORE:
return (0);
case UTF8_ERROR:
ictx->utf8started = 0;
return (0);
case UTF8_DONE:
break;
}
ictx->utf8started = 0;
log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size,
(int)ud->size, ud->data, ud->width);
@@ -2128,7 +2235,7 @@ bad:
free(copy);
}
/* Handle the OSC 10 sequence for setting background colour. */
/* Handle the OSC 10 sequence for setting foreground colour. */
static void
input_osc_10(struct window_pane *wp, const char *p)
{

3
job.c
View File

@@ -43,7 +43,7 @@ struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
struct job *
job_run(const char *cmd, struct session *s, const char *cwd,
job_update_cb updatecb, job_complete_cb completecb, job_free_cb freecb,
void *data)
void *data, int flags)
{
struct job *job;
struct environ *env;
@@ -110,6 +110,7 @@ job_run(const char *cmd, struct session *s, const char *cwd,
job = xmalloc(sizeof *job);
job->state = JOB_RUNNING;
job->flags = flags;
job->cmd = xstrdup(cmd);
job->pid = pid;

View File

@@ -24,17 +24,19 @@
#include "tmux.h"
RB_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp);
RB_GENERATE(key_tables, key_table, entry, key_table_cmp);
struct key_tables key_tables = RB_INITIALIZER(&key_tables);
static int key_bindings_cmp(struct key_binding *, struct key_binding *);
RB_GENERATE_STATIC(key_bindings, key_binding, entry, key_bindings_cmp);
static int key_table_cmp(struct key_table *, struct key_table *);
RB_GENERATE_STATIC(key_tables, key_table, entry, key_table_cmp);
static struct key_tables key_tables = RB_INITIALIZER(&key_tables);
int
key_table_cmp(struct key_table *e1, struct key_table *e2)
static int
key_table_cmp(struct key_table *table1, struct key_table *table2)
{
return (strcmp(e1->name, e2->name));
return (strcmp(table1->name, table2->name));
}
int
static int
key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2)
{
if (bd1->key < bd2->key)
@@ -64,6 +66,18 @@ key_bindings_get_table(const char *name, int create)
return (table);
}
struct key_table *
key_bindings_first_table(void)
{
return (RB_MIN(key_tables, &key_tables));
}
struct key_table *
key_bindings_next_table(struct key_table *table)
{
return (RB_NEXT(key_tables, &key_tables, table));
}
void
key_bindings_unref_table(struct key_table *table)
{
@@ -83,6 +97,27 @@ key_bindings_unref_table(struct key_table *table)
free(table);
}
struct key_binding *
key_bindings_get(struct key_table *table, key_code key)
{
struct key_binding bd;
bd.key = key;
return (RB_FIND(key_bindings, &table->key_bindings, &bd));
}
struct key_binding *
key_bindings_first(struct key_table *table)
{
return (RB_MIN(key_bindings, &table->key_bindings));
}
struct key_binding *
key_bindings_next(__unused struct key_table *table, struct key_binding *bd)
{
return (RB_NEXT(key_bindings, &table->key_bindings, bd));
}
void
key_bindings_add(const char *name, key_code key, int repeat,
struct cmd_list *cmdlist)
@@ -162,13 +197,13 @@ key_bindings_init(void)
"bind ! break-pane",
"bind '\"' split-window",
"bind '#' list-buffers",
"bind '$' command-prompt -I'#S' \"rename-session '%%'\"",
"bind '$' command-prompt -I'#S' \"rename-session -- '%%'\"",
"bind % split-window -h",
"bind & confirm-before -p\"kill-window #W? (y/n)\" kill-window",
"bind \"'\" command-prompt -pindex \"select-window -t ':%%'\"",
"bind ( switch-client -p",
"bind ) switch-client -n",
"bind , command-prompt -I'#W' \"rename-window '%%'\"",
"bind , command-prompt -I'#W' \"rename-window -- '%%'\"",
"bind - delete-buffer",
"bind . command-prompt \"move-window -t '%%'\"",
"bind 0 select-window -t:=0",
@@ -183,16 +218,17 @@ key_bindings_init(void)
"bind 9 select-window -t:=9",
"bind : command-prompt",
"bind \\; last-pane",
"bind = choose-buffer",
"bind = choose-buffer -Z",
"bind ? list-keys",
"bind D choose-client",
"bind D choose-client -Z",
"bind E select-layout -E",
"bind L switch-client -l",
"bind M select-pane -M",
"bind [ copy-mode",
"bind ] paste-buffer",
"bind c new-window",
"bind d detach-client",
"bind f command-prompt \"find-window '%%'\"",
"bind f command-prompt \"find-window -- '%%'\"",
"bind i display-message",
"bind l last-window",
"bind m select-pane -m",
@@ -201,9 +237,9 @@ key_bindings_init(void)
"bind p previous-window",
"bind q display-panes",
"bind r refresh-client",
"bind s choose-tree -s",
"bind s choose-tree -Zs",
"bind t clock-mode",
"bind w choose-tree -w",
"bind w choose-tree -Zw",
"bind x confirm-before -p\"kill-pane #P? (y/n)\" kill-pane",
"bind z resize-pane -Z",
"bind { swap-pane -U",

View File

@@ -166,9 +166,11 @@ key_string_lookup_string(const char *string)
enum utf8_state more;
wchar_t wc;
/* Is this no key? */
/* Is this no key or any key? */
if (strcasecmp(string, "None") == 0)
return (KEYC_NONE);
if (strcasecmp(string, "Any") == 0)
return (KEYC_ANY);
/* Is this a hexadecimal value? */
if (string[0] == '0' && string[1] == 'x') {
@@ -251,6 +253,8 @@ key_string_lookup_key(key_code key)
/* Handle special keys. */
if (key == KEYC_UNKNOWN)
return ("Unknown");
if (key == KEYC_ANY)
return ("Any");
if (key == KEYC_FOCUS_IN)
return ("FocusIn");
if (key == KEYC_FOCUS_OUT)

View File

@@ -115,11 +115,11 @@ layout_set_previous(struct window *w)
}
static void
layout_set_even_h(struct window *w)
layout_set_even(struct window *w, enum layout_type type)
{
struct window_pane *wp;
struct layout_cell *lc, *lcnew;
u_int i, n, width, xoff;
u_int n;
layout_print_cell(w->layout_root, __func__, 1);
@@ -128,36 +128,23 @@ layout_set_even_h(struct window *w)
if (n <= 1)
return;
/* How many can we fit? */
width = (w->sx - (n - 1)) / n;
if (width < PANE_MINIMUM)
width = PANE_MINIMUM;
/* Free the old root and construct a new. */
layout_free(w);
lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, w->sx, w->sy, 0, 0);
layout_make_node(lc, LAYOUT_LEFTRIGHT);
layout_make_node(lc, type);
/* Build new leaf cells. */
i = xoff = 0;
TAILQ_FOREACH(wp, &w->panes, entry) {
/* Create child cell. */
lcnew = layout_create_cell(lc);
layout_set_size(lcnew, width, w->sy, xoff, 0);
layout_make_leaf(lcnew, wp);
lcnew->sx = w->sx;
lcnew->sy = w->sy;
TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
i++;
xoff += width + 1;
}
/* Allocate any remaining space. */
if (w->sx > xoff - 1) {
lc = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT,
w->sx - (xoff - 1));
}
/* Spread out cells. */
layout_spread_cell(w, lc);
/* Fix cell offsets. */
layout_fix_offsets(lc);
@@ -169,59 +156,16 @@ layout_set_even_h(struct window *w)
server_redraw_window(w);
}
static void
layout_set_even_h(struct window *w)
{
layout_set_even(w, LAYOUT_LEFTRIGHT);
}
static void
layout_set_even_v(struct window *w)
{
struct window_pane *wp;
struct layout_cell *lc, *lcnew;
u_int i, n, height, yoff;
layout_print_cell(w->layout_root, __func__, 1);
/* Get number of panes. */
n = window_count_panes(w);
if (n <= 1)
return;
/* How many can we fit? */
height = (w->sy - (n - 1)) / n;
if (height < PANE_MINIMUM)
height = PANE_MINIMUM;
/* Free the old root and construct a new. */
layout_free(w);
lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, w->sx, w->sy, 0, 0);
layout_make_node(lc, LAYOUT_TOPBOTTOM);
/* Build new leaf cells. */
i = yoff = 0;
TAILQ_FOREACH(wp, &w->panes, entry) {
/* Create child cell. */
lcnew = layout_create_cell(lc);
layout_set_size(lcnew, w->sx, height, 0, yoff);
layout_make_leaf(lcnew, wp);
TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
i++;
yoff += height + 1;
}
/* Allocate any remaining space. */
if (w->sy > yoff - 1) {
lc = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM,
w->sy - (yoff - 1));
}
/* Fix cell offsets. */
layout_fix_offsets(lc);
layout_fix_panes(w, w->sx, w->sy);
layout_print_cell(w->layout_root, __func__, 1);
notify_window("window-layout-changed", w);
server_redraw_window(w);
layout_set_even(w, LAYOUT_TOPBOTTOM);
}
static void

168
layout.c
View File

@@ -97,9 +97,24 @@ void
layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
{
struct layout_cell *lcchild;
const char *type;
log_debug("%s:%*s%p type %u [parent %p] wp=%p [%u,%u %ux%u]", hdr, n,
" ", lc, lc->type, lc->parent, lc->wp, lc->xoff, lc->yoff, lc->sx,
switch (lc->type) {
case LAYOUT_LEFTRIGHT:
type = "LEFTRIGHT";
break;
case LAYOUT_TOPBOTTOM:
type = "TOPBOTTOM";
break;
case LAYOUT_WINDOWPANE:
type = "WINDOWPANE";
break;
default:
type = "UNKNOWN";
break;
}
log_debug("%s:%*s%p type %s [parent %p] wp=%p [%u,%u %ux%u]", hdr, n,
" ", lc, type, lc->parent, lc->wp, lc->xoff, lc->yoff, lc->sx,
lc->sy);
switch (lc->type) {
case LAYOUT_LEFTRIGHT:
@@ -112,6 +127,42 @@ layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
}
}
struct layout_cell *
layout_search_by_border(struct layout_cell *lc, u_int x, u_int y)
{
struct layout_cell *lcchild, *last = NULL;
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
if (x >= lcchild->xoff && x < lcchild->xoff + lcchild->sx &&
y >= lcchild->yoff && y < lcchild->yoff + lcchild->sy) {
/* Inside the cell - recurse. */
return (layout_search_by_border(lcchild, x, y));
}
if (last == NULL) {
last = lcchild;
continue;
}
switch (lc->type) {
case LAYOUT_LEFTRIGHT:
if (x < lcchild->xoff && x >= last->xoff + last->sx)
return (last);
break;
case LAYOUT_TOPBOTTOM:
if (y < lcchild->yoff && y >= last->yoff + last->sy)
return (last);
break;
case LAYOUT_WINDOWPANE:
break;
}
last = lcchild;
}
return (NULL);
}
void
layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, u_int xoff,
u_int yoff)
@@ -535,29 +586,11 @@ layout_resize_pane_to(struct window_pane *wp, enum layout_type type,
layout_resize_pane(wp, type, change, 1);
}
/* Resize a single pane within the layout. */
void
layout_resize_pane(struct window_pane *wp, enum layout_type type, int change,
int opposite)
layout_resize_layout(struct window *w, struct layout_cell *lc,
enum layout_type type, int change, int opposite)
{
struct window *w = wp->window;
struct layout_cell *lc, *lcparent;
int needed, size;
lc = wp->layout_cell;
/* Find next parent of the same type. */
lcparent = lc->parent;
while (lcparent != NULL && lcparent->type != type) {
lc = lcparent;
lcparent = lc->parent;
}
if (lcparent == NULL)
return;
/* If this is the last cell, move back one. */
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
lc = TAILQ_PREV(lc, layout_cells, entry);
int needed, size;
/* Grow or shrink the cell. */
needed = change;
@@ -576,9 +609,34 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change,
}
/* Fix cell offsets. */
layout_fix_offsets(wp->window->layout_root);
layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
notify_window("window-layout-changed", wp->window);
layout_fix_offsets(w->layout_root);
layout_fix_panes(w, w->sx, w->sy);
notify_window("window-layout-changed", w);
}
/* Resize a single pane within the layout. */
void
layout_resize_pane(struct window_pane *wp, enum layout_type type, int change,
int opposite)
{
struct layout_cell *lc, *lcparent;
lc = wp->layout_cell;
/* Find next parent of the same type. */
lcparent = lc->parent;
while (lcparent != NULL && lcparent->type != type) {
lc = lcparent;
lcparent = lc->parent;
}
if (lcparent == NULL)
return;
/* If this is the last cell, move back one. */
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
lc = TAILQ_PREV(lc, layout_cells, entry);
layout_resize_layout(wp->window, lc, type, change, opposite);
}
/* Helper function to grow pane. */
@@ -983,3 +1041,61 @@ layout_close_pane(struct window_pane *wp)
}
notify_window("window-layout-changed", w);
}
int
layout_spread_cell(struct window *w, struct layout_cell *parent)
{
struct layout_cell *lc;
u_int number, each, size;
int change, changed;
number = 0;
TAILQ_FOREACH (lc, &parent->cells, entry)
number++;
if (number <= 1)
return (0);
if (parent->type == LAYOUT_LEFTRIGHT)
size = parent->sx;
else if (parent->type == LAYOUT_TOPBOTTOM)
size = parent->sy;
else
return (0);
each = (size - (number - 1)) / number;
changed = 0;
TAILQ_FOREACH (lc, &parent->cells, entry) {
if (TAILQ_NEXT(lc, entry) == NULL)
each = size - ((each + 1) * (number - 1));
change = 0;
if (parent->type == LAYOUT_LEFTRIGHT) {
change = each - (int)lc->sx;
layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, change);
} else if (parent->type == LAYOUT_TOPBOTTOM) {
change = each - (int)lc->sy;
layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, change);
}
if (change != 0)
changed = 1;
}
return (changed);
}
void
layout_spread_out(struct window_pane *wp)
{
struct layout_cell *parent;
struct window *w = wp->window;
parent = wp->layout_cell->parent;
if (parent == NULL)
return;
do {
if (layout_spread_cell(w, parent)) {
layout_fix_offsets(parent);
layout_fix_panes(w, w->sx, w->sy);
break;
}
} while ((parent = parent->parent) != NULL);
}

View File

@@ -31,6 +31,7 @@ TAILQ_HEAD(mode_tree_list, mode_tree_item);
struct mode_tree_data {
int dead;
u_int references;
int zoomed;
struct window_pane *wp;
void *modedata;
@@ -39,10 +40,9 @@ struct mode_tree_data {
u_int sort_size;
u_int sort_type;
void (*buildcb)(void *, u_int, uint64_t *,
const char *);
struct screen *(*drawcb)(void *, void *, u_int, u_int);
int (*searchcb)(void*, void *, const char *);
mode_tree_build_cb buildcb;
mode_tree_draw_cb drawcb;
mode_tree_search_cb searchcb;
struct mode_tree_list children;
struct mode_tree_list saved;
@@ -63,6 +63,7 @@ struct mode_tree_data {
int preview;
char *search;
char *filter;
int no_matches;
};
struct mode_tree_item {
@@ -192,27 +193,6 @@ mode_tree_clear_tagged(struct mode_tree_list *mtl)
}
static void
mode_tree_set_current(struct mode_tree_data *mtd, uint64_t tag)
{
u_int i;
for (i = 0; i < mtd->line_size; i++) {
if (mtd->line_list[i].item->tag == tag)
break;
}
if (i != mtd->line_size) {
mtd->current = i;
if (mtd->current > mtd->height - 1)
mtd->offset = mtd->current - mtd->height + 1;
else
mtd->offset = 0;
} else {
mtd->current = 0;
mtd->offset = 0;
}
}
void
mode_tree_up(struct mode_tree_data *mtd, int wrap)
{
if (mtd->current == 0) {
@@ -249,6 +229,36 @@ mode_tree_get_current(struct mode_tree_data *mtd)
return (mtd->line_list[mtd->current].item->itemdata);
}
void
mode_tree_expand_current(struct mode_tree_data *mtd)
{
if (!mtd->line_list[mtd->current].item->expanded) {
mtd->line_list[mtd->current].item->expanded = 1;
mode_tree_build(mtd);
}
}
void
mode_tree_set_current(struct mode_tree_data *mtd, uint64_t tag)
{
u_int i;
for (i = 0; i < mtd->line_size; i++) {
if (mtd->line_list[i].item->tag == tag)
break;
}
if (i != mtd->line_size) {
mtd->current = i;
if (mtd->current > mtd->height - 1)
mtd->offset = mtd->current - mtd->height + 1;
else
mtd->offset = 0;
} else {
mtd->current = 0;
mtd->offset = 0;
}
}
u_int
mode_tree_count_tagged(struct mode_tree_data *mtd)
{
@@ -265,8 +275,8 @@ mode_tree_count_tagged(struct mode_tree_data *mtd)
}
void
mode_tree_each_tagged(struct mode_tree_data *mtd, void (*cb)(void *, void *,
key_code), key_code key, int current)
mode_tree_each_tagged(struct mode_tree_data *mtd, mode_tree_each_cb cb,
struct client *c, key_code key, int current)
{
struct mode_tree_item *mti;
u_int i;
@@ -277,21 +287,20 @@ mode_tree_each_tagged(struct mode_tree_data *mtd, void (*cb)(void *, void *,
mti = mtd->line_list[i].item;
if (mti->tagged) {
fired = 1;
cb(mtd->modedata, mti->itemdata, key);
cb(mtd->modedata, mti->itemdata, c, key);
}
}
if (!fired && current) {
mti = mtd->line_list[mtd->current].item;
cb(mtd->modedata, mti->itemdata, key);
cb(mtd->modedata, mti->itemdata, c, key);
}
}
struct mode_tree_data *
mode_tree_start(struct window_pane *wp, struct args *args,
void (*buildcb)(void *, u_int, uint64_t *, const char *),
struct screen *(*drawcb)(void *, void *, u_int, u_int),
int (*searchcb)(void *, void *, const char *), void *modedata,
const char **sort_list, u_int sort_size, struct screen **s)
mode_tree_build_cb buildcb, mode_tree_draw_cb drawcb,
mode_tree_search_cb searchcb, void *modedata, const char **sort_list,
u_int sort_size, struct screen **s)
{
struct mode_tree_data *mtd;
const char *sort;
@@ -335,6 +344,19 @@ mode_tree_start(struct window_pane *wp, struct args *args,
return (mtd);
}
void
mode_tree_zoom(struct mode_tree_data *mtd, struct args *args)
{
struct window_pane *wp = mtd->wp;
if (args_has(args, 'Z')) {
mtd->zoomed = (wp->window->flags & WINDOW_ZOOMED);
if (!mtd->zoomed && window_zoom(wp) == 0)
server_redraw_window(wp->window);
} else
mtd->zoomed = -1;
}
void
mode_tree_build(struct mode_tree_data *mtd)
{
@@ -350,7 +372,8 @@ mode_tree_build(struct mode_tree_data *mtd)
TAILQ_INIT(&mtd->children);
mtd->buildcb(mtd->modedata, mtd->sort_type, &tag, mtd->filter);
if (TAILQ_EMPTY(&mtd->children))
mtd->no_matches = TAILQ_EMPTY(&mtd->children);
if (mtd->no_matches)
mtd->buildcb(mtd->modedata, mtd->sort_type, &tag, NULL);
mode_tree_free_items(&mtd->saved);
@@ -385,6 +408,11 @@ mode_tree_remove_ref(struct mode_tree_data *mtd)
void
mode_tree_free(struct mode_tree_data *mtd)
{
struct window_pane *wp = mtd->wp;
if (mtd->zoomed == 0)
server_unzoom_window(wp->window);
mode_tree_free_items(&mtd->children);
mode_tree_clear_lines(mtd);
screen_free(&mtd->screen);
@@ -463,7 +491,7 @@ void
mode_tree_draw(struct mode_tree_data *mtd)
{
struct window_pane *wp = mtd->wp;
struct screen *s = &mtd->screen, *box = NULL;
struct screen *s = &mtd->screen;
struct mode_tree_line *line;
struct mode_tree_item *mti;
struct options *oo = wp->window->options;
@@ -472,7 +500,7 @@ mode_tree_draw(struct mode_tree_data *mtd)
u_int w, h, i, j, sy, box_x, box_y;
char *text, *start, key[7];
const char *tag, *symbol;
size_t size;
size_t size, n;
int keylen;
if (mtd->line_size == 0)
@@ -554,10 +582,12 @@ mode_tree_draw(struct mode_tree_data *mtd)
}
if (i != mtd->current) {
screen_write_puts(&ctx, &gc0, "%.*s", w, text);
screen_write_nputs(&ctx, w, &gc0, "%s", text);
screen_write_clearendofline(&ctx, 8);
} else
screen_write_puts(&ctx, &gc, "%-*.*s", w, w, text);
} else {
screen_write_nputs(&ctx, w, &gc, "%s", text);
screen_write_clearendofline(&ctx, gc.bg);
}
free(text);
if (mti->tagged) {
@@ -578,24 +608,33 @@ mode_tree_draw(struct mode_tree_data *mtd)
screen_write_cursormove(&ctx, 0, h);
screen_write_box(&ctx, w, sy - h);
xasprintf(&text, " %s (sort: %s) ", mti->name,
xasprintf(&text, " %s (sort: %s)", mti->name,
mtd->sort_list[mtd->sort_type]);
if (w - 2 >= strlen(text)) {
screen_write_cursormove(&ctx, 1, h);
screen_write_puts(&ctx, &gc0, "%s", text);
if (mtd->no_matches)
n = (sizeof "no matches") - 1;
else
n = (sizeof "active") - 1;
if (mtd->filter != NULL && w - 2 >= strlen(text) + 10 + n + 2) {
screen_write_puts(&ctx, &gc0, " (filter: ");
if (mtd->no_matches)
screen_write_puts(&ctx, &gc, "no matches");
else
screen_write_puts(&ctx, &gc0, "active");
screen_write_puts(&ctx, &gc0, ") ");
}
}
free(text);
box_x = w - 4;
box_y = sy - h - 2;
if (box_x != 0 && box_y != 0)
box = mtd->drawcb(mtd->modedata, mti->itemdata, box_x, box_y);
if (box != NULL) {
if (box_x != 0 && box_y != 0) {
screen_write_cursormove(&ctx, 2, h + 1);
screen_write_copy(&ctx, box, 0, 0, box_x, box_y, NULL, NULL);
screen_free(box);
mtd->drawcb(mtd->modedata, mti->itemdata, &ctx, box_x, box_y);
}
screen_write_stop(&ctx);
@@ -722,7 +761,7 @@ mode_tree_filter_free(void *data)
int
mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
struct mouse_event *m)
struct mouse_event *m, u_int *xp, u_int *yp)
{
struct mode_tree_line *line;
struct mode_tree_item *current, *parent;
@@ -730,20 +769,31 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
int choice;
key_code tmp;
if (*key == KEYC_MOUSEDOWN1_PANE) {
if (KEYC_IS_MOUSE(*key)) {
if (cmd_mouse_at(mtd->wp, m, &x, &y, 0) != 0) {
*key = KEYC_NONE;
return (0);
}
if (xp != NULL)
*xp = x;
if (yp != NULL)
*yp = y;
if (x > mtd->width || y > mtd->height) {
*key = KEYC_NONE;
if (!mtd->preview)
*key = KEYC_NONE;
return (0);
}
if (mtd->offset + y < mtd->line_size) {
mtd->current = mtd->offset + y;
*key = '\r';
return (0);
}
if (*key == KEYC_MOUSEDOWN1_PANE ||
*key == KEYC_DOUBLECLICK1_PANE)
mtd->current = mtd->offset + y;
if (*key == KEYC_DOUBLECLICK1_PANE)
*key = '\r';
else
*key = KEYC_NONE;
} else
*key = KEYC_NONE;
return (0);
}
line = &mtd->line_list[mtd->current];
@@ -770,15 +820,18 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
switch (*key) {
case 'q':
case '\033': /* Escape */
case '\007': /* C-g */
return (1);
case KEYC_UP:
case 'k':
case KEYC_WHEELUP_PANE:
case '\020': /* C-p */
mode_tree_up(mtd, 1);
break;
case KEYC_DOWN:
case 'j':
case KEYC_WHEELDOWN_PANE:
case '\016': /* C-n */
mode_tree_down(mtd, 1);
break;
case KEYC_PPAGE:
@@ -844,6 +897,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
mode_tree_build(mtd);
break;
case KEYC_LEFT:
case 'h':
case '-':
if (line->flat || !current->expanded)
current = current->parent;
@@ -856,6 +910,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
}
break;
case KEYC_RIGHT:
case 'l':
case '+':
if (line->flat || current->expanded)
mode_tree_down(mtd, 0);

View File

@@ -35,7 +35,7 @@ struct notify_entry {
};
static void
notify_hook(struct cmdq_item *item, struct notify_entry *ne)
notify_hook1(struct cmdq_item *item, struct notify_entry *ne)
{
struct cmd_find_state fs;
struct hook *hook;
@@ -101,7 +101,7 @@ notify_callback(struct cmdq_item *item, void *data)
if (strcmp(ne->name, "session-window-changed") == 0)
control_notify_session_window_changed(ne->session);
notify_hook(item, ne);
notify_hook1(item, ne);
if (ne->client != NULL)
server_client_unref(ne->client);
@@ -153,6 +153,24 @@ notify_add(const char *name, struct cmd_find_state *fs, struct client *c,
cmdq_append(NULL, new_item);
}
void
notify_hook(struct cmdq_item *item, const char *name)
{
struct notify_entry ne;
memset(&ne, 0, sizeof ne);
ne.name = name;
cmd_find_copy_state(&ne.fs, &item->target);
ne.client = item->client;
ne.session = item->target.s;
ne.window = item->target.w;
ne.pane = item->target.wp->id;
notify_hook1(item, &ne);
}
void
notify_input(struct window_pane *wp, struct evbuffer *input)
{

View File

@@ -96,6 +96,12 @@ const struct options_table_entry options_table[] = {
.default_num = 500
},
{ .name = "exit-empty",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SERVER,
.default_num = 1
},
{ .name = "exit-unattached",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SERVER,
@@ -507,8 +513,8 @@ const struct options_table_entry options_table[] = {
{ .name = "update-environment",
.type = OPTIONS_TABLE_ARRAY,
.scope = OPTIONS_TABLE_SESSION,
.default_str = "DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID "
"SSH_CONNECTION WINDOWID XAUTHORITY"
.default_str = "DISPLAY KRB5CCNAME SSH_ASKPASS SSH_AUTH_SOCK "
"SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY"
},
{ .name = "visual-activity",
@@ -547,7 +553,7 @@ const struct options_table_entry options_table[] = {
{ .name = "allow-rename",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 1
.default_num = 0
},
{ .name = "alternate-screen",

View File

@@ -88,11 +88,17 @@ osdep_get_cwd(int fd)
struct event_base *
osdep_event_init(void)
{
struct event_base *base;
/*
* On OS X, kqueue and poll are both completely broken and don't
* work on anything except socket file descriptors (yes, really).
*/
setenv("EVENT_NOKQUEUE", "1", 1);
setenv("EVENT_NOPOLL", "1", 1);
return (event_init());
base = event_init();
unsetenv("EVENT_NOKQUEUE");
unsetenv("EVENT_NOPOLL");
return (base);
}

View File

@@ -193,10 +193,15 @@ osdep_get_cwd(int fd)
struct event_base *
osdep_event_init(void)
{
struct event_base *base;
/*
* On some versions of FreeBSD, kqueue doesn't work properly on tty
* file descriptors. This is fixed in recent FreeBSD versions.
*/
setenv("EVENT_NOKQUEUE", "1", 1);
return (event_init());
base = event_init();
unsetenv("EVENT_NOKQUEUE");
return (base);
}

View File

@@ -92,7 +92,12 @@ osdep_get_cwd(int fd)
struct event_base *
osdep_event_init(void)
{
struct event_base *base;
/* On Linux, epoll doesn't work on /dev/null (yes, really). */
setenv("EVENT_NOEPOLL", "1", 1);
return (event_init());
base = event_init();
unsetenv("EVENT_NOEPOLL");
return (base);
}

View File

@@ -13,7 +13,7 @@ $TMUX kill-server 2>/dev/null
TMP=$(mktemp)
OUT=$(mktemp)
trap "rm -f $TMP $OUT" 0 1 15
#trap "rm -f $TMP $OUT" 0 1 15
$TMUX -f/dev/null new -d || exit 1
sleep 1
@@ -23,7 +23,7 @@ refresh -C 100,50
ls -F':#{session_width} #{session_height}'
EOF
grep ^: $TMP >$OUT
printf ":80 24\n:100 50\n"|cmp -s $OUT || exit 1
printf ":80 24\n:100 50\n"|cmp -s $OUT - || exit 1
$TMUX kill-server 2>/dev/null
$TMUX -f/dev/null new -d || exit 1
@@ -34,7 +34,7 @@ refresh -C 80,24
ls -F':#{session_width} #{session_height}'
EOF
grep ^: $TMP >$OUT
printf ":80 24\n:80 24\n"|cmp -s $OUT || exit 1
printf ":80 24\n:80 24\n"|cmp -s $OUT - || exit 1
$TMUX kill-server 2>/dev/null
cat <<EOF|$TMUX -C new -x 100 -y 50 >$TMP
@@ -43,7 +43,7 @@ refresh -C 80,24
ls -F':#{session_width} #{session_height}'
EOF
grep ^: $TMP >$OUT
printf ":100 50\n:80 24\n"|cmp -s $OUT || exit 1
printf ":100 50\n:80 24\n"|cmp -s $OUT - || exit 1
$TMUX kill-server 2>/dev/null
exit 0

183
regress/format-strings.sh Normal file
View File

@@ -0,0 +1,183 @@
#!/bin/sh
# Tests of formats as described in tmux(1) FORMATS
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
# test_format $format $expected_result
test_format()
{
fmt="$1"
exp="$2"
out=$($TMUX display-message -p "$fmt")
if [ "$out" != "$exp" ]; then
echo "Format test failed for '$fmt'."
echo "Expected: '$exp'"
echo "But got '$out'"
exit 1
fi
}
# test_conditional_with_pane_in_mode $format $exp1 $exp2
#
# Tests the format string $format to yield $exp1 if #{pane_in_mode} is true and
# $exp2 when #{pane_in_mode} is false.
test_conditional_with_pane_in_mode()
{
fmt="$1"
exp_true="$2"
exp_false="$3"
$TMUX copy-mode # enter copy mode
test_format "$fmt" "$exp_true"
$TMUX send-keys -X cancel # leave copy mode
test_format "$fmt" "$exp_false"
}
# test_conditional_with_session_name #format $exp_summer $exp_winter
#
# Tests the format string $format to yield $exp_summer if the session name is
# 'Summer' and $exp_winter if the session name is 'Winter'.
test_conditional_with_session_name()
{
fmt="$1"
exp_summer="$2"
exp_winter="$3"
$TMUX rename-session "Summer"
test_format "$fmt" "$exp_summer"
$TMUX rename-session "Winter"
test_format "$fmt" "$exp_winter"
$TMUX rename-session "Summer" # restore default
}
$TMUX kill-server 2>/dev/null
$TMUX -f/dev/null new-session -d || exit 1
$TMUX rename-session "Summer" || exit 1 # used later in conditionals
# Plain string without substitutions et al
test_format "abc xyz" "abc xyz"
# Test basic escapes for "#", "{", "#{" "}", "#}", ","
test_format "##" "#"
test_format "#," ","
test_format "{" "{"
test_format "##{" "#{"
test_format "#}" "}"
test_format "###}" "#}" # not a "basic" one but interesting nevertheless
# Simple expansion
test_format "#{pane_in_mode}" "0"
# Simple conditionals
test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,xyz}" "abc" "xyz"
# Expansion in conditionals
test_conditional_with_pane_in_mode "#{?pane_in_mode,#{session_name},xyz}" "Summer" "xyz"
# Basic escapes in conditionals
# First argument
test_conditional_with_pane_in_mode "#{?pane_in_mode,##,xyz}" "#" "xyz"
test_conditional_with_pane_in_mode "#{?pane_in_mode,#,,xyz}" "," "xyz"
test_conditional_with_pane_in_mode "#{?pane_in_mode,{,xyz}" "{" "xyz"
test_conditional_with_pane_in_mode "#{?pane_in_mode,##{,xyz}" "#{" "xyz"
test_conditional_with_pane_in_mode "#{?pane_in_mode,#},xyz}" "}" "xyz"
# not a "basic" one but interesting nevertheless
test_conditional_with_pane_in_mode "#{?pane_in_mode,###},xyz}" "#}" "xyz"
# Second argument
test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,##}" "abc" "#"
test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,#,}" "abc" ","
test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,{}" "abc" "{"
test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,##{}" "abc" "#{"
test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,#}}" "abc" "}"
# not a "basic" one but interesting nevertheless
test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,###}}" "abc" "#}"
# mixed
test_conditional_with_pane_in_mode "#{?pane_in_mode,{,#}}" "{" "}"
test_conditional_with_pane_in_mode "#{?pane_in_mode,#},{}" "}" "{"
test_conditional_with_pane_in_mode "#{?pane_in_mode,##{,###}}" "#{" "#}"
test_conditional_with_pane_in_mode "#{?pane_in_mode,###},##{}" "#}" "#{"
# Conditionals split on the second comma (this is not documented)
test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,xyz,bonus}" "abc" "xyz,bonus"
# Curly brackets {...} do not capture a comma inside of conditionals as the
# conditional ends on the first '}'
test_conditional_with_pane_in_mode "#{?pane_in_mode,{abc,xyz},bonus}" "{abc,bonus}" "xyz,bonus}"
# Substitutions '#{...}' capture the comma
# invalid format: #{abc,xyz} is not a known variable name.
#test_conditional_with_pane_in_mode "#{?pane_in_mode,#{abc,xyz},bonus}" "" "bonus"
# Parenthesis (...) do not captura a comma
test_conditional_with_pane_in_mode "#{?pane_in_mode,(abc,xyz),bonus}" "(abc" "xyz),bonus"
test_conditional_with_pane_in_mode "#{?pane_in_mode,(abc#,xyz),bonus}" "(abc,xyz)" "bonus"
# Brackets [...] do not captura a comma
test_conditional_with_pane_in_mode "#{?pane_in_mode,[abc,xyz],bonus}" "[abc" "xyz],bonus"
test_conditional_with_pane_in_mode "#{?pane_in_mode,[abc#,xyz],bonus}" "[abc,xyz]" "bonus"
# Escape comma inside of #(...)
# Note: #() commands are run asynchronous and are substituted with result of the
# *previous* run or a placeholder (like "<'echo ,' not ready") if the command
# has not been run before. The format is updated as soon as the command
# finishes. As we are printing the message only once it never gets updated
# and the displayed message is "<'echo ,' not ready>"
test_format "#{?pane_in_mode,#(echo #,),xyz}" "xyz"
test_conditional_with_pane_in_mode "#{?pane_in_mode,#(echo #,),xyz}" "<'echo ,' not ready>" "xyz"
# This caching does not work :-(
#$TMUX display-message -p "#(echo #,)" > /dev/null
#test_conditional_with_pane_in_mode "#{?pane_in_mode,#(echo #,),xyz}" "," "xyz"
#test_conditional_with_pane_in_mode "#{?pane_in_mode,#(echo #,),xyz}" "," "xyz"
# invalid format: '#(' is not closed in the first argument of #{?,,}.
#test_conditional_with_pane_in_mode "#{?pane_in_mode,#(echo ,),xyz}" "" "),xyz"
# Escape comma inside of #[...]
test_conditional_with_pane_in_mode "#{?pane_in_mode,#[fg=default#,bg=default]abc,xyz}" "#[fg=default,bg=default]abc" "xyz"
# invalid format: '#[' is not closed in the first argument of #{?,,}
#test_conditional_with_pane_in_mode "#{?pane_in_mode,#[fg=default,bg=default]abc,xyz}" "" "bg=default]abc,xyz"
# Conditionals with comparison
test_conditional_with_session_name "#{?#{==:#{session_name},Summer},abc,xyz}" "abc" "xyz"
# Conditionals with comparison and escaped commas
$TMUX rename-session ","
test_format "#{?#{==:#,,#{session_name}},abc,xyz}" "abc"
$TMUX rename-session "Summer" # reset to default
# Conditional in conditional
test_conditional_with_pane_in_mode "#{?pane_in_mode,#{?#{==:#{session_name},Summer},ABC,XYZ},xyz}" "ABC" "xyz"
test_conditional_with_session_name "#{?pane_in_mode,#{?#{==:#{session_name},Summer},ABC,XYZ},xyz}" "xyz" "xyz"
test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,#{?#{==:#{session_name},Summer},ABC,XYZ}}" "abc" "ABC"
test_conditional_with_session_name "#{?pane_in_mode,abc,#{?#{==:#{session_name},Summer},ABC,XYZ}}" "ABC" "XYZ"
# Some fancy stackings
test_conditional_with_pane_in_mode "#{?#{==:#{?pane_in_mode,#{session_name},#(echo Spring)},Summer},abc,xyz}" "abc" "xyz"
# Format test for the literal option
# Note: The behavior for #{l:...} with escapes is sometimes weird as #{l:...}
# respects the escapes.
test_format "#{l:#{}}" "#{}"
test_format "#{l:#{pane_in_mode}}" "#{pane_in_mode}"
test_format "#{l:#{?pane_in_mode,#{?#{==:#{session_name},Summer},ABC,XYZ},xyz}}" "#{?pane_in_mode,#{?#{==:#{session_name},Summer},ABC,XYZ},xyz}"
# With escapes (which escape but are returned literally)
test_format "#{l:##{}" "##{"
test_format "#{l:#{#}}}" "#{#}}"
# Invalid formats:
#test_format "#{l:#{}" ""
#test_format "#{l:#{#}}" ""
exit 0

View File

@@ -15,13 +15,13 @@ trap "rm -f $TMP" 0 1 15
$TMUX -f/dev/null new -d </dev/null || exit 1
sleep 1
$TMUX ls -F "#{session_width} #{session_height}" >$TMP
printf "80 24\n"|cmp -s $TMP || exit 1
printf "80 24\n"|cmp -s $TMP - || exit 1
$TMUX kill-server 2>/dev/null
$TMUX -f/dev/null new -d -x 100 -y 50 </dev/null || exit 1
sleep 1
$TMUX ls -F "#{session_width} #{session_height}" >$TMP
printf "100 50\n"|cmp -s $TMP || exit 1
printf "100 50\n"|cmp -s $TMP - || exit 1
$TMUX kill-server 2>/dev/null
exit 0

View File

@@ -49,11 +49,11 @@ recalculate_sizes(void)
struct client *c;
struct window *w;
struct window_pane *wp;
u_int ssx, ssy, has, limit;
int flag, has_status, is_zoomed, forced;
u_int ssx, ssy, has, limit, lines;
int flag, is_zoomed, forced;
RB_FOREACH(s, sessions, &sessions) {
has_status = options_get_number(s->options, "status");
lines = status_line_size(s);
s->attached = 0;
ssx = ssy = UINT_MAX;
@@ -66,10 +66,14 @@ recalculate_sizes(void)
if (c->session == s) {
if (c->tty.sx < ssx)
ssx = c->tty.sx;
if (has_status &&
c->flags &= ~CLIENT_STATUSOFF;
if (lines != 0 && lines + PANE_MINIMUM > c->tty.sy)
c->flags |= CLIENT_STATUSOFF;
if ((~c->flags & CLIENT_STATUSOFF) &&
!(c->flags & CLIENT_CONTROL) &&
c->tty.sy > 1 && c->tty.sy - 1 < ssy)
ssy = c->tty.sy - 1;
c->tty.sy > lines &&
c->tty.sy - lines < ssy)
ssy = c->tty.sy - lines;
else if (c->tty.sy < ssy)
ssy = c->tty.sy;
s->attached++;
@@ -81,8 +85,8 @@ recalculate_sizes(void)
}
s->flags &= ~SESSION_UNATTACHED;
if (has_status && ssy == 0)
ssy = 1;
if (lines != 0 && ssy == 0)
ssy = lines;
if (s->sx == ssx && s->sy == ssy)
continue;

View File

@@ -18,10 +18,23 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
struct screen_redraw_ctx {
struct client *c;
u_int lines;
int top;
int pane_status;
u_int sx;
u_int sy;
};
static int screen_redraw_cell_border1(struct window_pane *, u_int, u_int);
static int screen_redraw_cell_border(struct client *, u_int, u_int);
static int screen_redraw_check_cell(struct client *, u_int, u_int, int,
@@ -33,11 +46,11 @@ static int screen_redraw_make_pane_status(struct client *, struct window *,
struct window_pane *);
static void screen_redraw_draw_pane_status(struct client *, int);
static void screen_redraw_draw_borders(struct client *, int, int, u_int);
static void screen_redraw_draw_panes(struct client *, u_int);
static void screen_redraw_draw_status(struct client *, u_int);
static void screen_redraw_draw_number(struct client *, struct window_pane *,
u_int);
static void screen_redraw_draw_borders(struct screen_redraw_ctx *);
static void screen_redraw_draw_panes(struct screen_redraw_ctx *);
static void screen_redraw_draw_status(struct screen_redraw_ctx *);
static void screen_redraw_draw_number(struct screen_redraw_ctx *,
struct window_pane *);
#define CELL_INSIDE 0
#define CELL_LEFTRIGHT 1
@@ -299,6 +312,7 @@ screen_redraw_make_pane_status(struct client *c, struct window *w,
screen_write_cnputs(&ctx, outlen, &gc, "%s", out);
screen_write_stop(&ctx);
free(out);
format_free(ft);
wp->status_size = outlen;
@@ -373,40 +387,44 @@ void
screen_redraw_screen(struct client *c, int draw_panes, int draw_status,
int draw_borders)
{
struct options *oo = c->session->options;
struct tty *tty = &c->tty;
struct window *w = c->session->curw->window;
struct options *wo = w->options;
u_int top;
int status, pane_status, spos;
struct options *oo = c->session->options;
struct tty *tty = &c->tty;
struct window *w = c->session->curw->window;
struct options *wo = w->options;
struct screen_redraw_ctx ctx;
/* Suspended clients should not be updated. */
if (c->flags & CLIENT_SUSPENDED)
return;
/* Get status line, er, status. */
spos = options_get_number(oo, "status-position");
if (c->message_string != NULL || c->prompt_string != NULL)
status = 1;
memset(&ctx, 0, sizeof ctx);
ctx.c = c;
if (c->flags & CLIENT_STATUSOFF)
ctx.lines = 0;
else
status = options_get_number(oo, "status");
top = 0;
if (status && spos == 0)
top = 1;
if (!status)
ctx.lines = status_line_size(c->session);
if (c->message_string != NULL || c->prompt_string != NULL)
ctx.lines = (ctx.lines == 0) ? 1 : ctx.lines;
if (ctx.lines != 0 && options_get_number(oo, "status-position") == 0)
ctx.top = 1;
ctx.pane_status = options_get_number(wo, "pane-border-status");
ctx.sx = tty->sx;
ctx.sy = tty->sy - ctx.lines;
if (ctx.lines == 0)
draw_status = 0;
/* Draw the elements. */
if (draw_borders) {
pane_status = options_get_number(wo, "pane-border-status");
screen_redraw_draw_borders(c, status, pane_status, top);
if (pane_status != CELL_STATUS_OFF)
screen_redraw_draw_pane_status(c, pane_status);
if (ctx.pane_status != CELL_STATUS_OFF)
screen_redraw_draw_pane_status(c, ctx.pane_status);
screen_redraw_draw_borders(&ctx);
}
if (draw_panes)
screen_redraw_draw_panes(c, top);
screen_redraw_draw_panes(&ctx);
if (draw_status)
screen_redraw_draw_status(c, top);
screen_redraw_draw_status(&ctx);
tty_reset(tty);
}
@@ -421,7 +439,7 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
yoff = wp->yoff;
if (status_at_line(c) == 0)
yoff++;
yoff += status_line_size(c->session);
log_debug("%s: redraw pane %%%u (at %u,%u)", c->name, wp->id,
wp->xoff, yoff);
@@ -431,25 +449,65 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
tty_reset(&c->tty);
}
/* Draw a border cell. */
static void
screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int x, u_int y,
int small, u_int msgx, u_int msgy, struct grid_cell *m_active_gc,
struct grid_cell *active_gc, struct grid_cell *m_other_gc,
struct grid_cell *other_gc)
{
struct client *c = ctx->c;
struct session *s = c->session;
struct window *w = s->curw->window;
struct tty *tty = &c->tty;
struct window_pane *wp;
struct window_pane *active = w->active;
struct window_pane *marked = marked_pane.wp;
u_int type;
int flag, pane_status = ctx->pane_status;
type = screen_redraw_check_cell(c, x, y, pane_status, &wp);
if (type == CELL_INSIDE)
return;
if (type == CELL_OUTSIDE && small && x > msgx && y == msgy)
return;
flag = screen_redraw_check_is(x, y, type, pane_status, w, active, wp);
if (server_is_marked(s, s->curw, marked_pane.wp) &&
screen_redraw_check_is(x, y, type, pane_status, w, marked, wp)) {
if (flag)
tty_attributes(tty, m_active_gc, NULL);
else
tty_attributes(tty, m_other_gc, NULL);
} else if (flag)
tty_attributes(tty, active_gc, NULL);
else
tty_attributes(tty, other_gc, NULL);
if (ctx->top)
tty_cursor(tty, x, ctx->lines + y);
else
tty_cursor(tty, x, y);
tty_putc(tty, CELL_BORDERS[type]);
}
/* Draw the borders. */
static void
screen_redraw_draw_borders(struct client *c, int status, int pane_status,
u_int top)
screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
{
struct client *c = ctx->c;
struct session *s = c->session;
struct window *w = s->curw->window;
struct options *oo = w->options;
struct tty *tty = &c->tty;
struct window_pane *wp;
struct grid_cell m_active_gc, active_gc, m_other_gc, other_gc;
struct grid_cell msg_gc;
u_int i, j, type, msgx = 0, msgy = 0;
int active, small, flags;
u_int i, j, msgx = 0, msgy = 0;
int small, flags;
char msg[256];
const char *tmp;
size_t msglen = 0;
small = (tty->sy - status + top > w->sy) || (tty->sx > w->sx);
small = (ctx->sy + ctx->top > w->sy) || (ctx->sx > w->sx);
if (small) {
flags = w->flags & (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT);
if (flags == (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT))
@@ -458,18 +516,20 @@ screen_redraw_draw_borders(struct client *c, int status, int pane_status,
tmp = "force-width";
else if (flags == WINDOW_FORCEHEIGHT)
tmp = "force-height";
else if (c->flags & CLIENT_STATUSOFF)
tmp = "status line";
else
tmp = "a smaller client";
xsnprintf(msg, sizeof msg, "(size %ux%u from %s)",
w->sx, w->sy, tmp);
msglen = strlen(msg);
if (tty->sy - 1 - status + top > w->sy && tty->sx >= msglen) {
msgx = tty->sx - msglen;
msgy = tty->sy - 1 - status + top;
} else if (tty->sx - w->sx > msglen) {
msgx = tty->sx - msglen;
msgy = tty->sy - 1 - status + top;
if (ctx->sy - 1 + ctx->top > w->sy && ctx->sx >= msglen) {
msgx = ctx->sx - msglen;
msgy = ctx->sy - 1 + ctx->top;
} else if (ctx->sx - w->sx > msglen) {
msgx = ctx->sx - msglen;
msgy = ctx->sy - 1 + ctx->top;
} else
small = 0;
}
@@ -483,30 +543,11 @@ screen_redraw_draw_borders(struct client *c, int status, int pane_status,
memcpy(&m_active_gc, &active_gc, sizeof m_active_gc);
m_active_gc.attr ^= GRID_ATTR_REVERSE;
for (j = 0; j < tty->sy - status; j++) {
for (i = 0; i < tty->sx; i++) {
type = screen_redraw_check_cell(c, i, j, pane_status,
&wp);
if (type == CELL_INSIDE)
continue;
if (type == CELL_OUTSIDE && small &&
i > msgx && j == msgy)
continue;
active = screen_redraw_check_is(i, j, type, pane_status,
w, w->active, wp);
if (server_is_marked(s, s->curw, marked_pane.wp) &&
screen_redraw_check_is(i, j, type, pane_status, w,
marked_pane.wp, wp)) {
if (active)
tty_attributes(tty, &m_active_gc, NULL);
else
tty_attributes(tty, &m_other_gc, NULL);
} else if (active)
tty_attributes(tty, &active_gc, NULL);
else
tty_attributes(tty, &other_gc, NULL);
tty_cursor(tty, i, top + j);
tty_putc(tty, CELL_BORDERS[type]);
for (j = 0; j < ctx->sy; j++) {
for (i = 0; i < ctx->sx; i++) {
screen_redraw_draw_borders_cell(ctx, i, j, small,
msgx, msgy, &m_active_gc, &active_gc, &m_other_gc,
&other_gc);
}
}
@@ -520,39 +561,49 @@ screen_redraw_draw_borders(struct client *c, int status, int pane_status,
/* Draw the panes. */
static void
screen_redraw_draw_panes(struct client *c, u_int top)
screen_redraw_draw_panes(struct screen_redraw_ctx *ctx)
{
struct client *c = ctx->c;
struct window *w = c->session->curw->window;
struct tty *tty = &c->tty;
struct window_pane *wp;
u_int i;
u_int i, y;
if (ctx->top)
y = ctx->lines;
else
y = 0;
TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp))
continue;
for (i = 0; i < wp->sy; i++)
tty_draw_pane(tty, wp, i, wp->xoff, top + wp->yoff);
tty_draw_pane(tty, wp, i, wp->xoff, y + wp->yoff);
if (c->flags & CLIENT_IDENTIFY)
screen_redraw_draw_number(c, wp, top);
screen_redraw_draw_number(ctx, wp);
}
}
/* Draw the status line. */
static void
screen_redraw_draw_status(struct client *c, u_int top)
screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
{
struct client *c = ctx->c;
struct tty *tty = &c->tty;
u_int i, y;
if (top)
tty_draw_line(tty, NULL, &c->status, 0, 0, 0);
if (ctx->top)
y = 0;
else
tty_draw_line(tty, NULL, &c->status, 0, 0, tty->sy - 1);
y = ctx->sy;
for (i = 0; i < ctx->lines; i++)
tty_draw_line(tty, NULL, &c->status.status, i, 0, y);
}
/* Draw number on a pane. */
static void
screen_redraw_draw_number(struct client *c, struct window_pane *wp, u_int top)
screen_redraw_draw_number(struct screen_redraw_ctx *ctx, struct window_pane *wp)
{
struct client *c = ctx->c;
struct tty *tty = &c->tty;
struct session *s = c->session;
struct options *oo = s->options;
@@ -575,8 +626,8 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp, u_int top)
px = wp->sx / 2; py = wp->sy / 2;
xoff = wp->xoff; yoff = wp->yoff;
if (top)
yoff++;
if (ctx->top)
yoff += ctx->lines;
if (wp->sx < len * 6 || wp->sy < 5) {
tty_cursor(tty, xoff + px - len / 2, yoff + py);

View File

@@ -351,11 +351,10 @@ screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
free(msg);
}
/* Copy from another screen. */
/* Copy from another screen. Assumes target region is big enough. */
void
screen_write_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px,
u_int py, u_int nx, u_int ny, bitstr_t *markbs,
const struct grid_cell *markgc)
u_int py, u_int nx, u_int ny, bitstr_t *mbs, const struct grid_cell *mgc)
{
struct screen *s = ctx->s;
struct grid *gd = src->grid;
@@ -371,22 +370,57 @@ screen_write_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px,
for (yy = py; yy < py + ny; yy++) {
for (xx = px; xx < px + nx; xx++) {
grid_get_cell(gd, xx, yy, &gc);
if (markbs != NULL) {
if (mbs != NULL) {
b = (yy * screen_size_x(src)) + xx;
if (bit_test(markbs, b)) {
gc.attr = markgc->attr;
gc.fg = markgc->fg;
gc.bg = markgc->bg;
if (bit_test(mbs, b)) {
gc.attr = mgc->attr;
gc.fg = mgc->fg;
gc.bg = mgc->bg;
}
}
screen_write_cell(ctx, &gc);
if (xx + gc.data.width <= px + nx)
screen_write_cell(ctx, &gc);
}
cy++;
screen_write_cursormove(ctx, cx, cy);
}
}
/*
* Copy from another screen but without the selection stuff. Also assumes the
* target region is already big enough and already cleared.
*/
void
screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
u_int px, u_int py, u_int nx, u_int ny)
{
struct screen *s = ctx->s;
struct grid *gd = src->grid;
struct grid_cell gc;
u_int xx, yy, cx, cy;
if (nx == 0 || ny == 0)
return;
cy = s->cy;
for (yy = py; yy < py + ny; yy++) {
if (yy >= gd->hsize + gd->sy)
break;
cx = s->cx;
for (xx = px; xx < px + nx; xx++) {
if (xx >= grid_get_line(gd, yy)->cellsize)
break;
grid_get_cell(gd, xx, yy, &gc);
if (xx + gc.data.width > px + nx)
break;
if (!grid_cells_equal(&gc, &grid_default_cell))
grid_view_set_cell(ctx->s->grid, cx, cy, &gc);
cx++;
}
cy++;
}
}
/* Draw a horizontal line on screen. */
void
screen_write_hline(struct screen_write_ctx *ctx, u_int nx, int left, int right)
@@ -428,7 +462,7 @@ screen_write_vline(struct screen_write_ctx *ctx, u_int ny, int top, int bottom)
screen_write_cursormove(ctx, cx, cy + i);
screen_write_putc(ctx, &gc, 'x');
}
screen_write_cursormove(ctx, cx, cy + ny);
screen_write_cursormove(ctx, cx, cy + ny - 1);
screen_write_putc(ctx, &gc, bottom ? 'v' : 'x');
screen_write_cursormove(ctx, cx, cy);
@@ -471,7 +505,10 @@ screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny)
screen_write_cursormove(ctx, cx, cy);
}
/* Write a preview version of a window. */
/*
* Write a preview version of a window. Assumes target area is big enough and
* already cleared.
*/
void
screen_write_preview(struct screen_write_ctx *ctx, struct screen *src, u_int nx,
u_int ny)
@@ -515,8 +552,7 @@ screen_write_preview(struct screen_write_ctx *ctx, struct screen *src, u_int nx,
py = 0;
}
screen_write_copy(ctx, src, px, src->grid->hsize + py, nx, ny, NULL,
NULL);
screen_write_fast_copy(ctx, src, px, src->grid->hsize + py, nx, ny);
if (src->mode & MODE_CURSOR) {
grid_view_get_cell(src->grid, src->cx, src->cy, &gc);
@@ -658,7 +694,7 @@ screen_write_backspace(struct screen_write_ctx *ctx)
if (s->cx == 0) {
if (s->cy == 0)
return;
gl = &s->grid->linedata[s->grid->hsize + s->cy - 1];
gl = grid_get_line(s->grid, s->grid->hsize + s->cy - 1);
if (gl->flags & GRID_LINE_WRAPPED) {
s->cy--;
s->cx = screen_size_x(s) - 1;
@@ -881,7 +917,7 @@ screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
struct tty_ctx ttyctx;
u_int sx = screen_size_x(s);
gl = &s->grid->linedata[s->grid->hsize + s->cy];
gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
if (gl->cellsize == 0 && bg == 8)
return;
@@ -904,7 +940,7 @@ screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg)
struct tty_ctx ttyctx;
u_int sx = screen_size_x(s);
gl = &s->grid->linedata[s->grid->hsize + s->cy];
gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
if (s->cx > sx - 1 || (s->cx >= gl->cellsize && bg == 8))
return;
@@ -1007,7 +1043,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg)
struct grid *gd = s->grid;
struct grid_line *gl;
gl = &gd->linedata[gd->hsize + s->cy];
gl = grid_get_line(gd, gd->hsize + s->cy);
if (wrapped)
gl->flags |= GRID_LINE_WRAPPED;
else
@@ -1243,6 +1279,7 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
struct screen *s = ctx->s;
struct screen_write_collect_item *ci = ctx->item;
struct grid_cell gc;
u_int xx;
if (ci->used == 0)
return;
@@ -1255,9 +1292,29 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
log_debug("%s: %u %s (at %u,%u)", __func__, ci->used, ci->data, s->cx,
s->cy);
if (s->cx != 0) {
for (xx = s->cx; xx > 0; xx--) {
grid_view_get_cell(s->grid, xx, s->cy, &gc);
if (~gc.flags & GRID_FLAG_PADDING)
break;
grid_view_set_cell(s->grid, xx, s->cy,
&grid_default_cell);
}
if (gc.data.width > 1)
grid_view_set_cell(s->grid, xx, s->cy,
&grid_default_cell);
}
memcpy(&gc, &ci->gc, sizeof gc);
grid_view_set_cells(s->grid, s->cx, s->cy, &gc, ci->data, ci->used);
s->cx += ci->used;
for (xx = s->cx; xx < screen_size_x(s); xx++) {
grid_view_get_cell(s->grid, xx, s->cy, &gc);
if (~gc.flags & GRID_FLAG_PADDING)
break;
grid_view_set_cell(s->grid, xx, s->cy, &grid_default_cell);
}
}
/* Write cell data, collecting if necessary. */
@@ -1278,7 +1335,7 @@ screen_write_collect_add(struct screen_write_ctx *ctx,
*/
collect = 1;
if (gc->data.width != 1 || gc->data.size != 1)
if (gc->data.width != 1 || gc->data.size != 1 || *gc->data.data >= 0x7f)
collect = 0;
else if (gc->attr & GRID_ATTR_CHARSET)
collect = 0;
@@ -1286,7 +1343,7 @@ screen_write_collect_add(struct screen_write_ctx *ctx,
collect = 0;
else if (s->mode & MODE_INSERT)
collect = 0;
else if (s->sel.flag)
else if (s->sel != NULL)
collect = 0;
if (!collect) {
screen_write_collect_end(ctx);
@@ -1376,7 +1433,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
screen_write_initctx(ctx, &ttyctx);
/* Handle overwriting of UTF-8 characters. */
gl = &s->grid->linedata[s->grid->hsize + s->cy];
gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
if (gl->flags & GRID_LINE_EXTENDED) {
grid_view_get_cell(gd, s->cx, s->cy, &now_gc);
if (screen_write_overwrite(ctx, &now_gc, width))
@@ -1388,6 +1445,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
* already ensured there is enough room.
*/
for (xx = s->cx + 1; xx < s->cx + width; xx++) {
log_debug("%s: new padding at %u,%u", __func__, xx, s->cy);
grid_view_set_cell(gd, xx, s->cy, &screen_write_pad_cell);
skip = 0;
}
@@ -1537,10 +1595,12 @@ screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc,
grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
if (~tmp_gc.flags & GRID_FLAG_PADDING)
break;
log_debug("%s: padding at %u,%u", __func__, xx, s->cy);
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
}
/* Overwrite the character at the start of this padding. */
log_debug("%s: character at %u,%u", __func__, xx, s->cy);
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
done = 1;
}
@@ -1557,6 +1617,7 @@ screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc,
grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
if (~tmp_gc.flags & GRID_FLAG_PADDING)
break;
log_debug("%s: overwrite at %u,%u", __func__, xx, s->cy);
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
done = 1;
}

149
screen.c
View File

@@ -24,21 +24,65 @@
#include "tmux.h"
/* Selected area in screen. */
struct screen_sel {
int hidden;
int rectangle;
int modekeys;
u_int sx;
u_int sy;
u_int ex;
u_int ey;
struct grid_cell cell;
};
/* Entry on title stack. */
struct screen_title_entry {
char *text;
TAILQ_ENTRY(screen_title_entry) entry;
};
TAILQ_HEAD(screen_titles, screen_title_entry);
static void screen_resize_x(struct screen *, u_int);
static void screen_resize_y(struct screen *, u_int);
static void screen_reflow(struct screen *, u_int);
/* Free titles stack. */
static void
screen_free_titles(struct screen *s)
{
struct screen_title_entry *title_entry;
if (s->titles == NULL)
return;
while ((title_entry = TAILQ_FIRST(s->titles)) != NULL) {
TAILQ_REMOVE(s->titles, title_entry, entry);
free(title_entry->text);
free(title_entry);
}
free(s->titles);
s->titles = NULL;
}
/* Create a new screen. */
void
screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
{
s->grid = grid_create(sx, sy, hlimit);
s->title = xstrdup("");
s->titles = NULL;
s->cstyle = 0;
s->ccolour = xstrdup("");
s->tabs = NULL;
s->sel = NULL;
screen_reinit(s);
}
@@ -60,16 +104,21 @@ screen_reinit(struct screen *s)
grid_clear_lines(s->grid, s->grid->hsize, s->grid->sy, 8);
screen_clear_selection(s);
screen_free_titles(s);
}
/* Destroy a screen. */
void
screen_free(struct screen *s)
{
free(s->sel);
free(s->tabs);
free(s->title);
free(s->ccolour);
grid_destroy(s->grid);
screen_free_titles(s);
}
/* Reset tabs to default, eight spaces apart. */
@@ -110,6 +159,43 @@ screen_set_title(struct screen *s, const char *title)
utf8_stravis(&s->title, title, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL);
}
/* Push the current title onto the stack. */
void
screen_push_title(struct screen *s)
{
struct screen_title_entry *title_entry;
if (s->titles == NULL) {
s->titles = xmalloc(sizeof *s->titles);
TAILQ_INIT(s->titles);
}
title_entry = xmalloc(sizeof *title_entry);
title_entry->text = xstrdup(s->title);
TAILQ_INSERT_HEAD(s->titles, title_entry, entry);
}
/*
* Pop a title from the stack and set it as the screen title. If the stack is
* empty, do nothing.
*/
void
screen_pop_title(struct screen *s)
{
struct screen_title_entry *title_entry;
if (s->titles == NULL)
return;
title_entry = TAILQ_FIRST(s->titles);
if (title_entry != NULL) {
screen_set_title(s, title_entry->text);
TAILQ_REMOVE(s->titles, title_entry, entry);
free(title_entry->text);
free(title_entry);
}
}
/* Resize screen. */
void
screen_resize(struct screen *s, u_int sx, u_int sy, int reflow)
@@ -128,7 +214,8 @@ screen_resize(struct screen *s, u_int sx, u_int sy, int reflow)
* is simpler and more reliable so let's do that.
*/
screen_reset_tabs(s);
}
} else
reflow = 0;
if (sy != screen_size_y(s))
screen_resize_y(s, sy);
@@ -211,9 +298,8 @@ screen_resize_y(struct screen *s, u_int sy)
s->cy -= needed;
}
/* Resize line arrays. */
gd->linedata = xreallocarray(gd->linedata, gd->hsize + sy,
sizeof *gd->linedata);
/* Resize line array. */
grid_adjust_lines(gd, gd->hsize + sy);
/* Size increasing. */
if (sy > oldy) {
@@ -236,7 +322,7 @@ screen_resize_y(struct screen *s, u_int sy)
/* Then fill the rest in with blanks. */
for (i = gd->hsize + sy - needed; i < gd->hsize + sy; i++)
memset(&gd->linedata[i], 0, sizeof gd->linedata[i]);
memset(grid_get_line(gd, i), 0, sizeof(struct grid_line));
}
/* Set the new size, and reset the scroll region. */
@@ -248,51 +334,49 @@ screen_resize_y(struct screen *s, u_int sy)
/* Set selection. */
void
screen_set_selection(struct screen *s, u_int sx, u_int sy,
u_int ex, u_int ey, u_int rectflag, struct grid_cell *gc)
u_int ex, u_int ey, u_int rectangle, int modekeys, struct grid_cell *gc)
{
struct screen_sel *sel = &s->sel;
if (s->sel == NULL)
s->sel = xcalloc(1, sizeof *s->sel);
memcpy(&sel->cell, gc, sizeof sel->cell);
sel->flag = 1;
sel->hidden = 0;
memcpy(&s->sel->cell, gc, sizeof s->sel->cell);
s->sel->hidden = 0;
s->sel->rectangle = rectangle;
s->sel->modekeys = modekeys;
sel->rectflag = rectflag;
sel->sx = sx; sel->sy = sy;
sel->ex = ex; sel->ey = ey;
s->sel->sx = sx;
s->sel->sy = sy;
s->sel->ex = ex;
s->sel->ey = ey;
}
/* Clear selection. */
void
screen_clear_selection(struct screen *s)
{
struct screen_sel *sel = &s->sel;
sel->flag = 0;
sel->hidden = 0;
sel->lineflag = LINE_SEL_NONE;
free(s->sel);
s->sel = NULL;
}
/* Hide selection. */
void
screen_hide_selection(struct screen *s)
{
struct screen_sel *sel = &s->sel;
sel->hidden = 1;
if (s->sel != NULL)
s->sel->hidden = 1;
}
/* Check if cell in selection. */
int
screen_check_selection(struct screen *s, u_int px, u_int py)
{
struct screen_sel *sel = &s->sel;
struct screen_sel *sel = s->sel;
u_int xx;
if (!sel->flag || sel->hidden)
if (sel == NULL || sel->hidden)
return (0);
if (sel->rectflag) {
if (sel->rectangle) {
if (sel->sy < sel->ey) {
/* start line < end line -- downward selection. */
if (py < sel->sy || py > sel->ey)
@@ -385,10 +469,10 @@ void
screen_select_cell(struct screen *s, struct grid_cell *dst,
const struct grid_cell *src)
{
if (!s->sel.flag || s->sel.hidden)
if (s->sel == NULL || s->sel->hidden)
return;
memcpy(dst, &s->sel.cell, sizeof *dst);
memcpy(dst, &s->sel->cell, sizeof *dst);
utf8_copy(&dst->data, &src->data);
dst->attr = dst->attr & ~GRID_ATTR_CHARSET;
@@ -400,14 +484,5 @@ screen_select_cell(struct screen *s, struct grid_cell *dst,
static void
screen_reflow(struct screen *s, u_int new_x)
{
struct grid *old = s->grid;
u_int change;
s->grid = grid_create(old->sx, old->sy, old->hlimit);
change = grid_reflow(s->grid, old, new_x);
if (change < s->cy)
s->cy -= change;
else
s->cy = 0;
grid_reflow(s->grid, new_x, &s->cy);
}

View File

@@ -41,6 +41,8 @@ static void server_client_check_redraw(struct client *);
static void server_client_set_title(struct client *);
static void server_client_reset_state(struct client *);
static int server_client_assume_paste(struct session *);
static void server_client_clear_identify(struct client *,
struct window_pane *);
static void server_client_dispatch(struct imsg *, void *);
static void server_client_dispatch_command(struct client *, struct imsg *);
@@ -91,7 +93,7 @@ server_client_set_identify(struct client *c, u_int delay)
}
/* Clear identify mode on client. */
void
static void
server_client_clear_identify(struct client *c, struct window_pane *wp)
{
if (~c->flags & CLIENT_IDENTIFY)
@@ -159,7 +161,7 @@ server_client_is_default_key_table(struct client *c, struct key_table *table)
}
/* Create a new client. */
void
struct client *
server_client_create(int fd)
{
struct client *c;
@@ -193,7 +195,7 @@ server_client_create(int fd)
c->tty.sx = 80;
c->tty.sy = 24;
screen_init(&c->status, c->tty.sx, 1, 0);
screen_init(&c->status.status, c->tty.sx, 1, 0);
c->message_string = NULL;
TAILQ_INIT(&c->message_log);
@@ -212,6 +214,7 @@ server_client_create(int fd)
TAILQ_INSERT_TAIL(&clients, c, entry);
log_debug("new client %p", c);
return (c);
}
/* Open client terminal if needed. */
@@ -269,12 +272,12 @@ server_client_lost(struct client *c)
if (c->stderr_data != c->stdout_data)
evbuffer_free(c->stderr_data);
if (event_initialized(&c->status_timer))
evtimer_del(&c->status_timer);
screen_free(&c->status);
if (c->old_status != NULL) {
screen_free(c->old_status);
free(c->old_status);
if (event_initialized(&c->status.timer))
evtimer_del(&c->status.timer);
screen_free(&c->status.status);
if (c->status.old_status != NULL) {
screen_free(c->status.old_status);
free(c->status.old_status);
}
free(c->title);
@@ -812,7 +815,7 @@ server_client_handle_key(struct client *c, key_code key)
struct window_pane *wp;
struct timeval tv;
struct key_table *table, *first;
struct key_binding bd_find, *bd;
struct key_binding *bd;
int xtimeout, flags;
struct cmd_find_state fs;
key_code key0;
@@ -881,11 +884,11 @@ server_client_handle_key(struct client *c, key_code key)
/* Forward mouse keys if disabled. */
if (KEYC_IS_MOUSE(key) && !options_get_number(s->options, "mouse"))
goto forward;
goto forward_key;
/* Treat everything as a regular key when pasting is detected. */
if (!KEYC_IS_MOUSE(key) && server_client_assume_paste(s))
goto forward;
goto forward_key;
/*
* Work out the current key table. If the pane is in a mode, use
@@ -900,6 +903,7 @@ server_client_handle_key(struct client *c, key_code key)
table = c->keytable;
first = table;
table_changed:
/*
* The prefix always takes precedence and forces a switch to the prefix
* table, unless we are already there.
@@ -914,7 +918,6 @@ server_client_handle_key(struct client *c, key_code key)
}
flags = c->flags;
retry:
/* Log key table. */
if (wp == NULL)
log_debug("key table %s (no pane)", table->name);
@@ -923,9 +926,9 @@ retry:
if (c->flags & CLIENT_REPEAT)
log_debug("currently repeating");
try_again:
/* Try to see if there is a key binding in the current table. */
bd_find.key = key0;
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
bd = key_bindings_get(table, key0);
if (bd != NULL) {
/*
* Key was matched in this table. If currently repeating but a
@@ -938,7 +941,7 @@ retry:
c->flags &= ~CLIENT_REPEAT;
server_status_client(c);
table = c->keytable;
goto retry;
goto table_changed;
}
log_debug("found in key table %s", table->name);
@@ -972,6 +975,14 @@ retry:
return;
}
/*
* No match, try the ANY key.
*/
if (key0 != KEYC_ANY) {
key0 = KEYC_ANY;
goto try_again;
}
/*
* No match in this table. If not in the root table or if repeating,
* switch the client back to the root table and try again.
@@ -983,7 +994,7 @@ retry:
c->flags &= ~CLIENT_REPEAT;
server_status_client(c);
table = c->keytable;
goto retry;
goto table_changed;
}
/*
@@ -996,7 +1007,7 @@ retry:
return;
}
forward:
forward_key:
if (c->flags & CLIENT_READONLY)
return;
if (wp != NULL)
@@ -1067,7 +1078,7 @@ server_client_resize_force(struct window_pane *wp)
memset(&ws, 0, sizeof ws);
ws.ws_col = wp->sx;
ws.ws_row = wp->sy - 1;
if (ioctl(wp->fd, TIOCSWINSZ, &ws) == -1)
if (wp->fd != -1 && ioctl(wp->fd, TIOCSWINSZ, &ws) == -1)
#ifdef __sun
if (errno != EINVAL && errno != ENXIO)
#endif
@@ -1096,7 +1107,7 @@ server_client_resize_event(__unused int fd, __unused short events, void *data)
memset(&ws, 0, sizeof ws);
ws.ws_col = wp->sx;
ws.ws_row = wp->sy;
if (ioctl(wp->fd, TIOCSWINSZ, &ws) == -1)
if (wp->fd != -1 && ioctl(wp->fd, TIOCSWINSZ, &ws) == -1)
#ifdef __sun
/*
* Some versions of Solaris apparently can return an error when
@@ -1157,10 +1168,6 @@ server_client_check_focus(struct window_pane *wp)
push = wp->flags & PANE_FOCUSPUSH;
wp->flags &= ~PANE_FOCUSPUSH;
/* If we don't care about focus, forget it. */
if (!(wp->base.mode & MODE_FOCUSON))
return;
/* If we're not the active pane in our window, we're not focused. */
if (wp->window->active != wp)
goto not_focused;
@@ -1184,14 +1191,20 @@ server_client_check_focus(struct window_pane *wp)
}
not_focused:
if (push || (wp->flags & PANE_FOCUSED))
bufferevent_write(wp->event, "\033[O", 3);
if (push || (wp->flags & PANE_FOCUSED)) {
if (wp->base.mode & MODE_FOCUSON)
bufferevent_write(wp->event, "\033[O", 3);
notify_pane("pane-focus-out", wp);
}
wp->flags &= ~PANE_FOCUSED;
return;
focused:
if (push || !(wp->flags & PANE_FOCUSED))
bufferevent_write(wp->event, "\033[I", 3);
if (push || !(wp->flags & PANE_FOCUSED)) {
if (wp->base.mode & MODE_FOCUSON)
bufferevent_write(wp->event, "\033[I", 3);
notify_pane("pane-focus-in", wp);
}
wp->flags |= PANE_FOCUSED;
}
@@ -1211,7 +1224,7 @@ server_client_reset_state(struct client *c)
struct window_pane *wp = w->active, *loop;
struct screen *s = wp->screen;
struct options *oo = c->session->options;
int status, mode, o;
int lines, mode;
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
return;
@@ -1219,13 +1232,14 @@ server_client_reset_state(struct client *c)
tty_region_off(&c->tty);
tty_margin_off(&c->tty);
status = options_get_number(oo, "status");
if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status)
if (status_at_line(c) != 0)
lines = 0;
else
lines = status_line_size(c->session);
if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - lines)
tty_cursor(&c->tty, 0, 0);
else {
o = status && options_get_number(oo, "status-position") == 0;
tty_cursor(&c->tty, wp->xoff + s->cx, o + wp->yoff + s->cy);
}
else
tty_cursor(&c->tty, wp->xoff + s->cx, lines + wp->yoff + s->cy);
/*
* Set mouse mode if requested. To support dragging, always use button
@@ -1287,6 +1301,8 @@ server_client_check_exit(struct client *c)
if (EVBUFFER_LENGTH(c->stderr_data) != 0)
return;
if (c->flags & CLIENT_ATTACHED)
notify_client("client-detached", c);
proc_send(c->peer, MSG_EXIT, -1, &c->retval, sizeof c->retval);
c->flags &= ~CLIENT_EXIT;
}
@@ -1559,6 +1575,9 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg)
int argc;
char **argv, *cause;
if (c->flags & CLIENT_EXIT)
return;
if (imsg->hdr.len - IMSG_HEADER_SIZE < sizeof data)
fatalx("bad MSG_COMMAND size");
memcpy(&data, imsg->data, sizeof data);
@@ -1854,15 +1873,19 @@ server_client_add_message(struct client *c, const char *fmt, ...)
/* Get client working directory. */
const char *
server_client_get_cwd(struct client *c)
server_client_get_cwd(struct client *c, struct session *s)
{
struct session *s;
const char *home;
if (c != NULL && c->session == NULL && c->cwd != NULL)
return (c->cwd);
if (s != NULL && s->cwd != NULL)
return (s->cwd);
if (c != NULL && (s = c->session) != NULL && s->cwd != NULL)
return (s->cwd);
return (".");
if ((home = find_home()) != NULL)
return (home);
return ("/");
}
/* Resolve an absolute path or relative to client working directory. */
@@ -1874,7 +1897,7 @@ server_client_get_path(struct client *c, const char *file)
if (*file == '/')
path = xstrdup(file);
else
xasprintf(&path, "%s/%s", server_client_get_cwd(c), file);
xasprintf(&path, "%s/%s", server_client_get_cwd(c, NULL), file);
if (realpath(path, resolved) == NULL)
return (path);
free(path);

View File

@@ -17,6 +17,7 @@
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/uio.h>
#include <stdlib.h>
@@ -174,6 +175,22 @@ server_lock_client(struct client *c)
proc_send(c->peer, MSG_LOCK, -1, cmd, strlen(cmd) + 1);
}
void
server_kill_pane(struct window_pane *wp)
{
struct window *w = wp->window;
if (window_count_panes(w) == 1) {
server_kill_window(w);
recalculate_sizes();
} else {
server_unzoom_window(w);
layout_close_pane(wp);
window_remove_pane(w, wp);
server_redraw_window(w);
}
}
void
server_kill_window(struct window *w)
{
@@ -276,11 +293,11 @@ void
server_destroy_pane(struct window_pane *wp, int notify)
{
struct window *w = wp->window;
int old_fd;
struct screen_write_ctx ctx;
struct grid_cell gc;
time_t t;
char tim[26];
old_fd = wp->fd;
if (wp->fd != -1) {
#ifdef HAVE_UTEMPTER
utempter_remove_record(wp->fd);
@@ -291,9 +308,13 @@ server_destroy_pane(struct window_pane *wp, int notify)
}
if (options_get_number(w->options, "remain-on-exit")) {
if (old_fd == -1)
if (~wp->flags & PANE_STATUSREADY)
return;
if (wp->flags & PANE_STATUSDRAWN)
return;
wp->flags |= PANE_STATUSDRAWN;
if (notify)
notify_pane("pane-died", wp);
@@ -302,11 +323,24 @@ server_destroy_pane(struct window_pane *wp, int notify)
screen_write_cursormove(&ctx, 0, screen_size_y(ctx.s) - 1);
screen_write_linefeed(&ctx, 1, 8);
memcpy(&gc, &grid_default_cell, sizeof gc);
gc.attr |= GRID_ATTR_BRIGHT;
screen_write_puts(&ctx, &gc, "Pane is dead");
time(&t);
ctime_r(&t, tim);
if (WIFEXITED(wp->status)) {
screen_write_nputs(&ctx, -1, &gc,
"Pane is dead (status %d, %s)",
WEXITSTATUS(wp->status),
tim);
} else if (WIFSIGNALED(wp->status)) {
screen_write_nputs(&ctx, -1, &gc,
"Pane is dead (signal %d, %s)",
WTERMSIG(wp->status),
tim);
}
screen_write_stop(&ctx);
wp->flags |= PANE_REDRAW;
return;
}
@@ -438,8 +472,6 @@ server_set_stdin_callback(struct client *c, void (*cb)(struct client *, int,
void
server_unzoom_window(struct window *w)
{
if (window_unzoom(w) == 0) {
if (window_unzoom(w) == 0)
server_redraw_window(w);
server_status_window(w);
}
}

View File

@@ -49,7 +49,6 @@ static struct event server_ev_accept;
struct cmd_find_state marked_pane;
static int server_create_socket(void);
static int server_loop(void);
static void server_send_exit(void);
static void server_accept(int, short, void *);
@@ -98,39 +97,62 @@ server_check_marked(void)
/* Create server socket. */
static int
server_create_socket(void)
server_create_socket(char **cause)
{
struct sockaddr_un sa;
size_t size;
mode_t mask;
int fd;
int fd, saved_errno;
memset(&sa, 0, sizeof sa);
sa.sun_family = AF_UNIX;
size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path);
if (size >= sizeof sa.sun_path) {
errno = ENAMETOOLONG;
return (-1);
goto fail;
}
unlink(sa.sun_path);
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
return (-1);
goto fail;
mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
if (bind(fd, (struct sockaddr *)&sa, sizeof sa) == -1) {
saved_errno = errno;
close(fd);
return (-1);
errno = saved_errno;
goto fail;
}
umask(mask);
if (listen(fd, 128) == -1) {
saved_errno = errno;
close(fd);
return (-1);
errno = saved_errno;
goto fail;
}
setblocking(fd, 0);
return (fd);
fail:
if (cause != NULL) {
xasprintf(cause, "error creating %s (%s)", socket_path,
strerror(errno));
}
return (-1);
}
/* Server error callback. */
static enum cmd_retval
server_start_error(struct cmdq_item *item, void *data)
{
char *error = data;
cmdq_error(item, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
/* Fork new server. */
@@ -141,6 +163,8 @@ server_start(struct tmuxproc *client, struct event_base *base, int lockfd,
int pair[2];
struct job *job;
sigset_t set, oldset;
struct client *c;
char *cause = NULL;
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
fatal("socketpair failed");
@@ -177,16 +201,14 @@ server_start(struct tmuxproc *client, struct event_base *base, int lockfd,
RB_INIT(&all_window_panes);
TAILQ_INIT(&clients);
RB_INIT(&sessions);
RB_INIT(&session_groups);
key_bindings_init();
gettimeofday(&start_time, NULL);
server_fd = server_create_socket();
if (server_fd == -1)
fatal("couldn't create socket");
server_update_socket();
server_client_create(pair[1]);
server_fd = server_create_socket(&cause);
if (server_fd != -1)
server_update_socket();
c = server_client_create(pair[1]);
if (lockfd >= 0) {
unlink(lockfile);
@@ -194,6 +216,11 @@ server_start(struct tmuxproc *client, struct event_base *base, int lockfd,
close(lockfd);
}
if (cause != NULL) {
cmdq_append(c, cmdq_get_callback(server_start_error, cause));
c->flags |= CLIENT_EXIT;
}
start_cfg();
server_add_accept(0);
@@ -215,6 +242,7 @@ server_loop(void)
{
struct client *c;
u_int items;
struct job *job;
do {
items = cmdq_next(NULL);
@@ -226,6 +254,9 @@ server_loop(void)
server_client_loop();
if (!options_get_number(global_options, "exit-empty") && !server_exit)
return (0);
if (!options_get_number(global_options, "exit-unattached")) {
if (!RB_EMPTY(&sessions))
return (0);
@@ -244,6 +275,11 @@ server_loop(void)
if (!TAILQ_EMPTY(&clients))
return (0);
LIST_FOREACH(job, &all_jobs, entry) {
if ((~job->flags & JOB_NOWAIT) && job->state == JOB_RUNNING)
return (0);
}
return (1);
}
@@ -259,8 +295,11 @@ server_send_exit(void)
TAILQ_FOREACH_SAFE(c, &clients, entry, c1) {
if (c->flags & CLIENT_SUSPENDED)
server_client_lost(c);
else
else {
if (c->flags & CLIENT_ATTACHED)
notify_client("client-detached", c);
proc_send(c->peer, MSG_SHUTDOWN, -1, NULL, 0);
}
c->session = NULL;
}
@@ -374,7 +413,7 @@ server_signal(int sig)
break;
case SIGUSR1:
event_del(&server_ev_accept);
fd = server_create_socket();
fd = server_create_socket(NULL);
if (fd != -1) {
close(server_fd);
server_fd = fd;
@@ -423,6 +462,7 @@ server_child_exited(pid_t pid, int status)
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->pid == pid) {
wp->status = status;
wp->flags |= PANE_STATUSREADY;
log_debug("%%%u exited", wp->id);
wp->flags |= PANE_EXITED;

View File

@@ -28,7 +28,7 @@
struct sessions sessions;
static u_int next_session_id;
struct session_groups session_groups;
struct session_groups session_groups = RB_INITIALIZER(&session_groups);
static void session_free(int, short, void *);
@@ -38,27 +38,21 @@ static struct winlink *session_next_alert(struct winlink *);
static struct winlink *session_previous_alert(struct winlink *);
static void session_group_remove(struct session *);
static u_int session_group_count(struct session_group *);
static void session_group_synchronize1(struct session *, struct session *);
static u_int session_group_count(struct session_group *);
static void session_group_synchronize1(struct session *, struct session *);
RB_GENERATE(sessions, session, entry, session_cmp);
int
session_cmp(struct session *s1, struct session *s2)
{
return (strcmp(s1->name, s2->name));
}
RB_GENERATE(sessions, session, entry, session_cmp);
RB_GENERATE(session_groups, session_group, entry, session_group_cmp);
int
static int
session_group_cmp(struct session_group *s1, struct session_group *s2)
{
return (strcmp(s1->name, s2->name));
}
RB_GENERATE_STATIC(session_groups, session_group, entry, session_group_cmp);
/*
* Find if session is still alive. This is true if it is still on the global
@@ -294,9 +288,10 @@ session_update_activity(struct session *s, struct timeval *from)
else
memcpy(&s->activity_time, from, sizeof s->activity_time);
log_debug("session %s activity %lld.%06d (last %lld.%06d)", s->name,
(long long)s->activity_time.tv_sec, (int)s->activity_time.tv_usec,
(long long)last->tv_sec, (int)last->tv_usec);
log_debug("session $%u %s activity %lld.%06d (last %lld.%06d)", s->id,
s->name, (long long)s->activity_time.tv_sec,
(int)s->activity_time.tv_usec, (long long)last->tv_sec,
(int)last->tv_usec);
if (evtimer_initialized(&s->lock_timer))
evtimer_del(&s->lock_timer);
@@ -623,7 +618,7 @@ session_group_remove(struct session *s)
}
/* Count number of sessions in session group. */
static u_int
u_int
session_group_count(struct session_group *sg)
{
struct session *s;

127
status.c
View File

@@ -151,7 +151,7 @@ status_timer_callback(__unused int fd, __unused short events, void *arg)
struct session *s = c->session;
struct timeval tv;
evtimer_del(&c->status_timer);
evtimer_del(&c->status.timer);
if (s == NULL)
return;
@@ -163,7 +163,7 @@ status_timer_callback(__unused int fd, __unused short events, void *arg)
tv.tv_sec = options_get_number(s->options, "status-interval");
if (tv.tv_sec != 0)
evtimer_add(&c->status_timer, &tv);
evtimer_add(&c->status.timer, &tv);
log_debug("client %p, status interval %d", c, (int)tv.tv_sec);
}
@@ -173,10 +173,10 @@ status_timer_start(struct client *c)
{
struct session *s = c->session;
if (event_initialized(&c->status_timer))
evtimer_del(&c->status_timer);
if (event_initialized(&c->status.timer))
evtimer_del(&c->status.timer);
else
evtimer_set(&c->status_timer, status_timer_callback, c);
evtimer_set(&c->status.timer, status_timer_callback, c);
if (s != NULL && options_get_number(s->options, "status"))
status_timer_callback(-1, 0, c);
@@ -210,9 +210,24 @@ status_at_line(struct client *c)
{
struct session *s = c->session;
if (c->flags & CLIENT_STATUSOFF)
return (-1);
if (s->statusat != 1)
return (s->statusat);
return (c->tty.sy - 1);
return (c->tty.sy - status_line_size(s));
}
/*
* Get size of status line for session. 0 means off. Note that status line may
* be forced off for an individual client if it is too small (the
* CLIENT_STATUSOFF flag is set for this).
*/
u_int
status_line_size(struct session *s)
{
if (s->statusat == -1)
return (0);
return (1);
}
/* Retrieve options for left string. */
@@ -296,20 +311,21 @@ status_redraw(struct client *c)
time_t t;
char *left, *right;
const char *sep;
u_int offset, needed;
u_int offset, needed, lines;
u_int wlstart, wlwidth, wlavailable, wloffset, wlsize;
size_t llen, rlen, seplen;
int larrow, rarrow;
/* Delete the saved status line, if any. */
if (c->old_status != NULL) {
screen_free(c->old_status);
free(c->old_status);
c->old_status = NULL;
if (c->status.old_status != NULL) {
screen_free(c->status.old_status);
free(c->status.old_status);
c->status.old_status = NULL;
}
/* No status line? */
if (c->tty.sy == 0 || !options_get_number(s->options, "status"))
lines = status_line_size(s);
if (c->tty.sy == 0 || lines == 0)
return (1);
left = right = NULL;
larrow = rarrow = 0;
@@ -321,15 +337,15 @@ status_redraw(struct client *c)
style_apply(&stdgc, s->options, "status-style");
/* Create the target screen. */
memcpy(&old_status, &c->status, sizeof old_status);
screen_init(&c->status, c->tty.sx, 1, 0);
screen_write_start(&ctx, NULL, &c->status);
for (offset = 0; offset < c->tty.sx; offset++)
memcpy(&old_status, &c->status.status, sizeof old_status);
screen_init(&c->status.status, c->tty.sx, lines, 0);
screen_write_start(&ctx, NULL, &c->status.status);
for (offset = 0; offset < lines * c->tty.sx; offset++)
screen_write_putc(&ctx, &stdgc, ' ');
screen_write_stop(&ctx);
/* If the height is one line, blank status line. */
if (c->tty.sy <= 1)
/* If the height is too small, blank status line. */
if (c->tty.sy < lines)
goto out;
/* Work out left and right strings. */
@@ -446,7 +462,7 @@ status_redraw(struct client *c)
draw:
/* Begin drawing. */
screen_write_start(&ctx, NULL, &c->status);
screen_write_start(&ctx, NULL, &c->status.status);
/* Draw the left string and arrow. */
screen_write_cursormove(&ctx, 0, 0);
@@ -492,8 +508,7 @@ draw:
/* Copy the window list. */
c->wlmouse = -wloffset + wlstart;
screen_write_cursormove(&ctx, wloffset, 0);
screen_write_copy(&ctx, &window_list, wlstart, 0, wlwidth, 1, NULL,
NULL);
screen_write_fast_copy(&ctx, &window_list, wlstart, 0, wlwidth, 1);
screen_free(&window_list);
screen_write_stop(&ctx);
@@ -502,7 +517,7 @@ out:
free(left);
free(right);
if (grid_compare(c->status.grid, old_status.grid) == 0) {
if (grid_compare(c->status.status.grid, old_status.grid) == 0) {
screen_free(&old_status);
return (0);
}
@@ -575,10 +590,11 @@ status_message_set(struct client *c, const char *fmt, ...)
status_message_clear(c);
if (c->old_status == NULL) {
c->old_status = xmalloc(sizeof *c->old_status);
memcpy(c->old_status, &c->status, sizeof *c->old_status);
screen_init(&c->status, c->tty.sx, 1, 0);
if (c->status.old_status == NULL) {
c->status.old_status = xmalloc(sizeof *c->status.old_status);
memcpy(c->status.old_status, &c->status.status,
sizeof *c->status.old_status);
screen_init(&c->status.status, c->tty.sx, 1, 0);
}
va_start(ap, fmt);
@@ -616,7 +632,7 @@ status_message_clear(struct client *c)
c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE);
c->flags |= CLIENT_REDRAW; /* screen was frozen and may have changed */
screen_reinit(&c->status);
screen_reinit(&c->status.status);
}
/* Clear status line message after timer expires. */
@@ -637,11 +653,18 @@ status_message_redraw(struct client *c)
struct screen old_status;
size_t len;
struct grid_cell gc;
u_int lines, offset;
if (c->tty.sx == 0 || c->tty.sy == 0)
return (0);
memcpy(&old_status, &c->status, sizeof old_status);
screen_init(&c->status, c->tty.sx, 1, 0);
memcpy(&old_status, &c->status.status, sizeof old_status);
lines = status_line_size(c->session);
if (lines <= 1) {
lines = 1;
screen_init(&c->status.status, c->tty.sx, 1, 0);
} else
screen_init(&c->status.status, c->tty.sx, lines, 0);
len = screen_write_strlen("%s", c->message_string);
if (len > c->tty.sx)
@@ -649,16 +672,15 @@ status_message_redraw(struct client *c)
style_apply(&gc, s->options, "message-style");
screen_write_start(&ctx, NULL, &c->status);
screen_write_start(&ctx, NULL, &c->status.status);
screen_write_cursormove(&ctx, 0, 0);
screen_write_nputs(&ctx, len, &gc, "%s", c->message_string);
for (; len < c->tty.sx; len++)
for (offset = 0; offset < lines * c->tty.sx; offset++)
screen_write_putc(&ctx, &gc, ' ');
screen_write_cursormove(&ctx, 0, lines - 1);
screen_write_nputs(&ctx, len, &gc, "%s", c->message_string);
screen_write_stop(&ctx);
if (grid_compare(c->status.grid, old_status.grid) == 0) {
if (grid_compare(c->status.status.grid, old_status.grid) == 0) {
screen_free(&old_status);
return (0);
}
@@ -689,10 +711,11 @@ status_prompt_set(struct client *c, const char *msg, const char *input,
status_message_clear(c);
status_prompt_clear(c);
if (c->old_status == NULL) {
c->old_status = xmalloc(sizeof *c->old_status);
memcpy(c->old_status, &c->status, sizeof *c->old_status);
screen_init(&c->status, c->tty.sx, 1, 0);
if (c->status.old_status == NULL) {
c->status.old_status = xmalloc(sizeof *c->status.old_status);
memcpy(c->status.old_status, &c->status.status,
sizeof *c->status.old_status);
screen_init(&c->status.status, c->tty.sx, 1, 0);
}
c->prompt_string = format_expand_time(ft, msg, t);
@@ -742,7 +765,7 @@ status_prompt_clear(struct client *c)
c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE);
c->flags |= CLIENT_REDRAW; /* screen was frozen and may have changed */
screen_reinit(&c->status);
screen_reinit(&c->status.status);
}
/* Update status line prompt with a new prompt string. */
@@ -782,12 +805,19 @@ status_prompt_redraw(struct client *c)
struct session *s = c->session;
struct screen old_status;
u_int i, offset, left, start, pcursor, pwidth, width;
u_int lines;
struct grid_cell gc, cursorgc;
if (c->tty.sx == 0 || c->tty.sy == 0)
return (0);
memcpy(&old_status, &c->status, sizeof old_status);
screen_init(&c->status, c->tty.sx, 1, 0);
memcpy(&old_status, &c->status.status, sizeof old_status);
lines = status_line_size(c->session);
if (lines <= 1) {
lines = 1;
screen_init(&c->status.status, c->tty.sx, 1, 0);
} else
screen_init(&c->status.status, c->tty.sx, lines, 0);
if (c->prompt_mode == PROMPT_COMMAND)
style_apply(&gc, s->options, "message-command-style");
@@ -801,11 +831,12 @@ status_prompt_redraw(struct client *c)
if (start > c->tty.sx)
start = c->tty.sx;
screen_write_start(&ctx, NULL, &c->status);
screen_write_start(&ctx, NULL, &c->status.status);
screen_write_cursormove(&ctx, 0, 0);
for (offset = 0; offset < lines * c->tty.sx; offset++)
screen_write_putc(&ctx, &gc, ' ');
screen_write_cursormove(&ctx, 0, 0);
screen_write_nputs(&ctx, start, &gc, "%s", c->prompt_string);
while (c->status.cx < screen_size_x(&c->status))
screen_write_putc(&ctx, &gc, ' ');
screen_write_cursormove(&ctx, start, 0);
left = c->tty.sx - start;
@@ -846,13 +877,14 @@ status_prompt_redraw(struct client *c)
screen_write_cell(&ctx, &cursorgc);
}
}
if (c->status.cx < screen_size_x(&c->status) && c->prompt_index >= i)
if (c->status.status.cx < screen_size_x(&c->status.status) &&
c->prompt_index >= i)
screen_write_putc(&ctx, &cursorgc, ' ');
finished:
screen_write_stop(&ctx);
if (grid_compare(c->status.grid, old_status.grid) == 0) {
if (grid_compare(c->status.status.grid, old_status.grid) == 0) {
screen_free(&old_status);
return (0);
}
@@ -1305,6 +1337,7 @@ process_key:
break;
case '\033': /* Escape */
case '\003': /* C-c */
case '\007': /* C-g */
if (c->prompt_inputcb(c, c->prompt_data, NULL, 1) == 0)
status_prompt_clear(c);
break;

174
tmux.1
View File

@@ -855,6 +855,8 @@ the initial size is 80 x 24;
and
.Fl y
can be used to specify a different size.
.Ql -
uses the size of the current client if any.
.Pp
If run from a terminal, any
.Xr termios 4
@@ -966,7 +968,7 @@ show debugging information about jobs and terminals.
Execute commands from
.Ar path
(which may be a
.Xr glob 3
.Xr glob 7
pattern).
If
.Fl q
@@ -980,22 +982,37 @@ them with
and
.Em %endif
lines.
Additional
.Em %elif
and
.Em %else
lines may also be used.
The argument to
.Em %if
is expanded as a format and if it evaluates to false
(zero or empty), subsequent lines are ignored until
and
.Em %elif
is expanded as a format and if it evaluates to false (zero or empty),
subsequent lines are ignored until the next
.Em %elif ,
.Em %else
or
.Em %endif .
For example:
.Bd -literal -offset indent
%if #{==:#{host},myhost}
set -g status-style bg=red
%elif #{==:#{host},myotherhost}
set -g status-style bg=green
%else
set -g status-style bg=blue
%endif
.Ed
.Pp
Will change the status line to red if running on
.Ql myhost .
.Em %if
may not be nested.
.Ql myhost ,
green if running on
.Ql myotherhost ,
or blue if running on another host.
.It Ic start-server
.D1 (alias: Ic start )
Start the
@@ -1111,9 +1128,10 @@ The following commands are supported in copy mode:
.It Li "end-of-line" Ta "$" Ta "C-e"
.It Li "goto-line <line>" Ta ":" Ta "g"
.It Li "halfpage-down" Ta "C-d" Ta "M-Down"
.It Li "halfpage-down-and-cancel" Ta "" Ta ""
.It Li "halfpage-up" Ta "C-u" Ta "M-Up"
.It Li "history-bottom" Ta "G" Ta "M-<"
.It Li "history-top" Ta "g" Ta "M->"
.It Li "history-bottom" Ta "G" Ta "M->"
.It Li "history-top" Ta "g" Ta "M-<"
.It Li "jump-again" Ta ";" Ta ";"
.It Li "jump-backward <to>" Ta "F" Ta "F"
.It Li "jump-forward <to>" Ta "f" Ta "f"
@@ -1128,12 +1146,14 @@ The following commands are supported in copy mode:
.It Li "next-word-end" Ta "e" Ta "M-f"
.It Li "other-end" Ta "o" Ta ""
.It Li "page-down" Ta "C-f" Ta "PageDown"
.It Li "page-down-and-cancel" Ta "" Ta ""
.It Li "page-up" Ta "C-b" Ta "PageUp"
.It Li "previous-paragraph" Ta "{" Ta "M-{"
.It Li "previous-space" Ta "B" Ta ""
.It Li "previous-word" Ta "b" Ta "M-b"
.It Li "rectangle-toggle" Ta "v" Ta "R"
.It Li "scroll-down" Ta "C-e" Ta "C-Down"
.It Li "scroll-down-and-cancel" Ta "" Ta ""
.It Li "scroll-up" Ta "C-y" Ta "C-Up"
.It Li "search-again" Ta "n" Ta "n"
.It Li "search-backward <for>" Ta "?" Ta ""
@@ -1147,6 +1167,11 @@ The following commands are supported in copy mode:
.It Li "top-line" Ta "H" Ta "M-R"
.El
.Pp
The
.Ql -and-cancel
variants of some commands exit copy mode after they have completed (for copy
commands) or when the cursor reaches the bottom (for scrolling commands).
.Pp
The next and previous word keys use space and the
.Ql - ,
.Ql _
@@ -1358,7 +1383,7 @@ the end of the visible pane.
The default is to capture only the visible contents of the pane.
.It Xo
.Ic choose-client
.Op Fl N
.Op Fl NZ
.Op Fl F Ar format
.Op Fl f Ar filter
.Op Fl O Ar sort-order
@@ -1367,6 +1392,8 @@ The default is to capture only the visible contents of the pane.
.Xc
Put a pane into client mode, allowing a client to be selected interactively from
a list.
.Fl Z
zooms the pane.
The following keys may be used in client mode:
.Bl -column "Key" "Function" -offset indent
.It Sy "Key" Ta Sy "Function"
@@ -1417,7 +1444,7 @@ starts without the preview.
This command works only if at least one client is attached.
.It Xo
.Ic choose-tree
.Op Fl Nsw
.Op Fl GNswZ
.Op Fl F Ar format
.Op Fl f Ar filter
.Op Fl O Ar sort-order
@@ -1430,12 +1457,16 @@ interactively from a list.
starts with sessions collapsed and
.Fl w
with windows collapsed.
.Fl Z
zooms the pane.
The following keys may be used in tree mode:
.Bl -column "Key" "Function" -offset indent
.It Sy "Key" Ta Sy "Function"
.It Li "Enter" Ta "Choose selected item"
.It Li "Up" Ta "Select previous item"
.It Li "Down" Ta "Select next item"
.It Li "x" Ta "Kill selected item"
.It Li "X" Ta "Kill tagged items"
.It Li "<" Ta "Scroll list of previews left"
.It Li ">" Ta "Scroll list of previews right"
.It Li "C-s" Ta "Search by name"
@@ -1473,6 +1504,9 @@ If a filter would lead to an empty list, it is ignored.
specifies the format for each item in the tree.
.Fl N
starts without the preview.
.Fl G
includes all sessions in any session groups in the tree rather than only the
first.
This command works only if at least one client is attached.
.It Xo
.Ic display-panes
@@ -1778,15 +1812,15 @@ If
.Fl a
is used, move to the next window with an alert.
.It Xo Ic pipe-pane
.Op Fl o
.Op Fl IOo
.Op Fl t Ar target-pane
.Op Ar shell-command
.Xc
.D1 (alias: Ic pipep )
Pipe any output sent by the program in
Pipe output sent by the program in
.Ar target-pane
to a shell command.
A pane may only be piped to one command at a time, any existing pipe is
to a shell command or vice versa.
A pane may only be connected to one command at a time, any existing pipe is
closed before
.Ar shell-command
is executed.
@@ -1799,6 +1833,25 @@ If no
.Ar shell-command
is given, the current pipe (if any) is closed.
.Pp
.Fl I
and
.Fl O
specify which of the
.Ar shell-command
output streams are connected to the pane:
with
.Fl I
stdout is connected (so anything
.Ar shell-command
prints is written to the pane as if it were typed);
with
.Fl O
stdin is connected (so any output in the pane is piped to
.Ar shell-command ) .
Both may be used together and if neither are specified,
.Fl O
is used.
.Pp
The
.Fl o
option only opens a new pipe if no previous pipe exists, allowing a pipe to
@@ -1909,8 +1962,8 @@ lower) with
.Fl U
or downward (numerically higher).
.It Xo Ic select-layout
.Op Fl nop
.Op Fl t Ar target-window
.Op Fl Enop
.Op Fl t Ar target-pane
.Op Ar layout-name
.Xc
.D1 (alias: Ic selectl )
@@ -1928,6 +1981,8 @@ and
commands.
.Fl o
applies the last set layout if possible (undoes the most recent layout change).
.Fl E
spreads the current pane and any panes next to it out evenly.
.It Xo Ic select-pane
.Op Fl DdegLlMmRU
.Op Fl P Ar style
@@ -2460,6 +2515,11 @@ Set the time in milliseconds for which
waits after an escape is input to determine if it is part of a function or meta
key sequences.
The default is 500 milliseconds.
.It Xo Ic exit-empty
.Op Ic on | off
.Xc
If enabled (the default), the server will exit when there are no active
sessions.
.It Xo Ic exit-unattached
.Op Ic on | off
.Xc
@@ -2697,8 +2757,7 @@ to
from the 256-colour set,
.Ic default ,
or a hexadecimal RGB string such as
.Ql #ffffff ,
which chooses the closest match from the default 256-colour set.
.Ql #ffffff .
.Pp
The attributes is either
.Ic none
@@ -3008,7 +3067,7 @@ and poor for interactive programs such as shells.
.Xc
Allow programs to change the window name using a terminal escape
sequence (\eek...\ee\e\e).
The default is on.
The default is off.
.Pp
.It Xo Ic alternate-screen
.Op Ic on | off
@@ -3336,7 +3395,11 @@ layout after every
set-hook after-split-window "selectl even-vertical"
.Ed
.Pp
In addition, the following hooks are available:
All the notifications listed in the
.Sx CONTROL MODE
section are hooks (without any arguments), except
.Ic %exit .
The following additional hooks are available:
.Bl -tag -width "XXXXXXXXXXXXXXXXXXXXXX"
.It alert-activity
Run when a window has activity.
@@ -3364,6 +3427,14 @@ Run when the program running in a pane exits, but
is on so the pane has not closed.
.It pane-exited
Run when the program running in a pane exits.
.It pane-focus-in
Run when the focus enters a pane, if the
.Ic focus-events
option is on.
.It pane-focus-out
Run when the focus exits a pane, if the
.Ic focus-events
option is on.
.It pane-set-clipboard
Run when the terminal clipboard is set using the
.Xr xterm 1
@@ -3385,12 +3456,14 @@ Run when a window is unlinked from a session.
Hooks are managed with these commands:
.Bl -tag -width Ds
.It Xo Ic set-hook
.Op Fl gu
.Op Fl gRu
.Op Fl t Ar target-session
.Ar hook-name
.Ar command
.Xc
Sets (or with
Without
.Fl R ,
sets (or with
.Fl u
unsets) hook
.Ar hook-name
@@ -3406,6 +3479,12 @@ hooks (for
with
.Fl t ) .
Like options, session hooks inherit from the global ones.
.Pp
With
.Fl R ,
run
.Ar hook-name
immediately.
.It Xo Ic show-hooks
.Op Fl g
.Op Fl t Ar target-session
@@ -3435,8 +3514,8 @@ The following mouse events are available:
.It Li "MouseDown1" Ta "MouseUp1" Ta "MouseDrag1" Ta "MouseDragEnd1"
.It Li "MouseDown2" Ta "MouseUp2" Ta "MouseDrag2" Ta "MouseDragEnd2"
.It Li "MouseDown3" Ta "MouseUp3" Ta "MouseDrag3" Ta "MouseDragEnd3"
.It Li "DoubleClick1" Ta "DoubleClick2" Ta "DoubleClick3" Ta "WheelUp"
.It Li "TripleClick1" Ta "TripleClick2" Ta "TripleClick3" Ta "WheelDown"
.It Li "DoubleClick1" Ta "DoubleClick2" Ta "DoubleClick3"
.It Li "TripleClick1" Ta "TripleClick2" Ta "TripleClick3"
.El
.Pp
Each should be suffixed with a location, for example
@@ -3485,11 +3564,17 @@ The possible variables are listed in the table below, or the name of a
.Nm
option may be used for an option's value.
Some variables have a shorter alias such as
.Ql #S ,
and
.Ql #S ;
.Ql ##
is replaced by a single
.Ql # .
.Ql # ,
.Ql #,
by a
.Ql \&,
and
.Ql #}
by a
.Ql } .
.Pp
Conditionals are available by prefixing with
.Ql \&?
@@ -3511,6 +3596,22 @@ if
is enabled, or
.Ql no
if not.
Conditionals can be nested arbitrarily.
Inside a conditional,
.Ql \&,
and
.Ql }
must be escaped as
.Ql #,
and
.Ql #} ,
unless they are part of a
.Ql #{...}
replacement.
For example:
.Bd -literal -offset indent
#{?pane_in_mode,#[fg=white#,bg=red],#[fg=red#,bg=white]}#W .
.Ed
.Pp
Comparisons may be expressed by prefixing two comma-separated
alternatives by
@@ -3538,7 +3639,7 @@ and
.Ql &&
evaluate to true if either or both of two comma-separated alternatives are
true, for example
.Ql #{||,#{pane_in_mode},#{alternate_on}} .
.Ql #{||:#{pane_in_mode},#{alternate_on}} .
A
.Ql C
performs a search for an
@@ -3638,7 +3739,7 @@ The following variables are available, where appropriate:
.It Li "cursor_y" Ta "" Ta "Cursor Y position in pane"
.It Li "history_bytes" Ta "" Ta "Number of bytes in window history"
.It Li "history_limit" Ta "" Ta "Maximum window history lines"
.It Li "history_size" Ta "" Ta "Size of history in bytes"
.It Li "history_size" Ta "" Ta "Size of history in lines"
.It Li "hook" Ta "" Ta "Name of running hook, if any"
.It Li "hook_pane" Ta "" Ta "ID of pane where hook was run, if any"
.It Li "hook_session" Ta "" Ta "ID of session where hook was run, if any"
@@ -3685,6 +3786,7 @@ The following variables are available, where appropriate:
.It Li "pane_tty" Ta "" Ta "Pseudo terminal of pane"
.It Li "pane_width" Ta "" Ta "Width of pane"
.It Li "pid" Ta "" Ta "Server PID"
.It Li "rectangle_toggle" Ta "" Ta "1 if rectangle selection is activated"
.It Li "scroll_region_lower" Ta "" Ta "Bottom of scroll region in pane"
.It Li "scroll_region_upper" Ta "" Ta "Top of scroll region in pane"
.It Li "scroll_position" Ta "" Ta "Scroll position in copy mode"
@@ -3696,6 +3798,8 @@ The following variables are available, where appropriate:
.It Li "session_format" Ta "" Ta "1 if format is for a session (not assuming the current)"
.It Li "session_last_attached" Ta "" Ta "Time session last attached"
.It Li "session_group" Ta "" Ta "Name of session group"
.It Li "session_group_size" Ta "" Ta "Size of session group"
.It Li "session_group_list" Ta "" Ta "List of sessions in group"
.It Li "session_grouped" Ta "" Ta "1 if session in a group"
.It Li "session_height" Ta "" Ta "Height of session"
.It Li "session_id" Ta "" Ta "Unique session ID"
@@ -3764,7 +3868,9 @@ for
or
.Ic new-session ) .
.It
An escape sequence:
An escape sequence (if the
.Ic allow-rename
option is turned on):
.Bd -literal -offset indent
$ printf '\e033kWINDOW_NAME\e033\e\e'
.Ed
@@ -4077,7 +4183,7 @@ The buffer commands are as follows:
.Bl -tag -width Ds
.It Xo
.Ic choose-buffer
.Op Fl N
.Op Fl NZ
.Op Fl F Ar format
.Op Fl f Ar filter
.Op Fl O Ar sort-order
@@ -4086,10 +4192,12 @@ The buffer commands are as follows:
.Xc
Put a pane into buffer mode, where a buffer may be chosen interactively from
a list.
.Fl Z
zooms the pane.
The following keys may be used in buffer mode:
.Bl -column "Key" "Function" -offset indent
.It Sy "Key" Ta Sy "Function"
.It Li "Enter" Ta "Choose selected buffer"
.It Li "Enter" Ta "Paste selected buffer"
.It Li "Up" Ta "Select previous buffer"
.It Li "Down" Ta "Select next buffer"
.It Li "C-s" Ta "Search by name or content"
@@ -4097,6 +4205,8 @@ The following keys may be used in buffer mode:
.It Li "t" Ta "Toggle if buffer is tagged"
.It Li "T" Ta "Tag no buffers"
.It Li "C-t" Ta "Tag all buffers"
.It Li "p" Ta "Paste selected buffer"
.It Li "P" Ta "Paste tagged buffers"
.It Li "d" Ta "Delete selected buffer"
.It Li "D" Ta "Delete tagged buffers"
.It Li "f" Ta "Enter a format to filter items"

43
tmux.c
View File

@@ -44,7 +44,7 @@ int ptm_fd = -1;
const char *shell_command;
static __dead void usage(void);
static char *make_label(const char *);
static char *make_label(const char *, char **);
static const char *getshell(void);
static int checkshell(const char *);
@@ -106,12 +106,13 @@ areshell(const char *shell)
}
static char *
make_label(const char *label)
make_label(const char *label, char **cause)
{
char *base, resolved[PATH_MAX], *path, *s;
struct stat sb;
uid_t uid;
int saved_errno;
*cause = NULL;
if (label == NULL)
label = "default";
@@ -121,11 +122,16 @@ make_label(const char *label)
xasprintf(&base, "%s/tmux-%ld", s, (long)uid);
else
xasprintf(&base, "%s/tmux-%ld", _PATH_TMP, (long)uid);
if (mkdir(base, S_IRWXU) != 0 && errno != EEXIST)
if (realpath(base, resolved) == NULL &&
strlcpy(resolved, base, sizeof resolved) >= sizeof resolved) {
errno = ERANGE;
free(base);
goto fail;
}
if (lstat(base, &sb) != 0)
if (mkdir(resolved, S_IRWXU) != 0 && errno != EEXIST)
goto fail;
if (lstat(resolved, &sb) != 0)
goto fail;
if (!S_ISDIR(sb.st_mode)) {
errno = ENOTDIR;
@@ -135,18 +141,11 @@ make_label(const char *label)
errno = EACCES;
goto fail;
}
if (realpath(base, resolved) == NULL)
strlcpy(resolved, base, sizeof resolved);
xasprintf(&path, "%s/%s", resolved, label);
free(base);
return (path);
fail:
saved_errno = errno;
free(base);
errno = saved_errno;
xasprintf(cause, "error creating %s (%s)", resolved, strerror(errno));
return (NULL);
}
@@ -188,9 +187,9 @@ find_home(void)
int
main(int argc, char **argv)
{
char *path, *label, **var;
char *path, *label, *cause, **var;
char tmp[PATH_MAX];
const char *s, *shell;
const char *s, *shell, *cwd;
int opt, flags, keys;
const struct options_table_entry *oe;
@@ -294,8 +293,9 @@ main(int argc, char **argv)
global_environ = environ_create();
for (var = environ; *var != NULL; var++)
environ_put(global_environ, *var);
if (getcwd(tmp, sizeof tmp) != NULL)
environ_set(global_environ, "PWD", "%s", tmp);
if ((cwd = getenv("PWD")) == NULL &&
(cwd = getcwd(tmp, sizeof tmp)) != NULL)
environ_set(global_environ, "PWD", "%s", cwd);
global_options = options_create(NULL);
global_s_options = options_create(NULL);
@@ -340,8 +340,11 @@ main(int argc, char **argv)
path[strcspn(path, ",")] = '\0';
}
}
if (path == NULL && (path = make_label(label)) == NULL) {
fprintf(stderr, "can't create socket: %s\n", strerror(errno));
if (path == NULL && (path = make_label(label, &cause)) == NULL) {
if (cause != NULL) {
fprintf(stderr, "%s\n", cause);
free(cause);
}
exit(1);
}
socket_path = path;

169
tmux.h
View File

@@ -19,8 +19,6 @@
#ifndef TMUX_H
#define TMUX_H
#define PROTOCOL_VERSION 8
#include <sys/time.h>
#include <sys/uio.h>
@@ -56,6 +54,9 @@ struct session;
struct tmuxpeer;
struct tmuxproc;
/* Client-server protocol version. */
#define PROTOCOL_VERSION 8
/* Default global configuration file. */
#ifndef TMUX_CONF
#define TMUX_CONF "/etc/tmux.conf"
@@ -140,6 +141,9 @@ enum {
KEYC_FOCUS_IN = KEYC_BASE,
KEYC_FOCUS_OUT,
/* "Any" key, used if not found in key table. */
KEYC_ANY,
/* Paste brackets. */
KEYC_PASTE_START,
KEYC_PASTE_END,
@@ -403,6 +407,7 @@ enum tty_code_code {
TTYC_MS,
TTYC_OP,
TTYC_REV,
TTYC_RGB,
TTYC_RI,
TTYC_RMACS,
TTYC_RMCUP,
@@ -510,10 +515,11 @@ struct msg_stderr_data {
#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
/*
* A single UTF-8 character. UTF8_SIZE must be big enough to hold at least one
* combining character as well.
* A single UTF-8 character. UTF8_SIZE must be big enough to hold
* combining characters as well, currently at most five (of three
* bytes) are supported.
*/
#define UTF8_SIZE 9
#define UTF8_SIZE 18
struct utf8_data {
u_char data[UTF8_SIZE];
@@ -554,6 +560,7 @@ enum utf8_state {
/* Grid line flags. */
#define GRID_LINE_WRAPPED 0x1
#define GRID_LINE_EXTENDED 0x2
#define GRID_LINE_DEAD 0x4
/* Grid cell data. */
struct grid_cell {
@@ -624,6 +631,9 @@ struct job {
JOB_CLOSED
} state;
int flags;
#define JOB_NOWAIT 0x1
char *cmd;
pid_t pid;
int status;
@@ -640,32 +650,12 @@ struct job {
};
LIST_HEAD(joblist, job);
/* Screen selection. */
struct screen_sel {
int flag;
int hidden;
int rectflag;
enum {
LINE_SEL_NONE,
LINE_SEL_LEFT_RIGHT,
LINE_SEL_RIGHT_LEFT,
} lineflag;
int modekeys;
u_int sx;
u_int sy;
u_int ex;
u_int ey;
struct grid_cell cell;
};
/* Virtual screen. */
struct screen_sel;
struct screen_titles;
struct screen {
char *title;
struct screen_titles *titles;
struct grid *grid; /* grid data */
@@ -682,7 +672,7 @@ struct screen {
bitstr_t *tabs;
struct screen_sel sel;
struct screen_sel *sel;
};
/* Screen write context. */
@@ -729,28 +719,6 @@ struct window_mode {
};
#define WINDOW_MODE_TIMEOUT 180
/* Structures for choose mode. */
struct window_choose_data {
struct client *start_client;
struct session *start_session;
u_int idx;
int type;
#define TREE_OTHER 0x0
#define TREE_WINDOW 0x1
#define TREE_SESSION 0x2
struct session *tree_session; /* session of items in tree */
struct winlink *wl;
int pane_id;
char *ft_template;
struct format_tree *ft;
char *command;
};
/* Child window structure. */
struct window_pane {
u_int id;
@@ -780,6 +748,8 @@ struct window_pane {
#define PANE_INPUTOFF 0x40
#define PANE_CHANGED 0x80
#define PANE_EXITED 0x100
#define PANE_STATUSREADY 0x200
#define PANE_STATUSDRAWN 0x400
int argc;
char **argv;
@@ -857,12 +827,11 @@ struct window {
int flags;
#define WINDOW_BELL 0x1
#define WINDOW_ACTIVITY 0x2
/* 0x4 unused */
#define WINDOW_SILENCE 0x8
#define WINDOW_ZOOMED 0x1000
#define WINDOW_FORCEWIDTH 0x2000
#define WINDOW_FORCEHEIGHT 0x4000
#define WINDOW_STYLECHANGED 0x8000
#define WINDOW_SILENCE 0x4
#define WINDOW_ZOOMED 0x8
#define WINDOW_FORCEWIDTH 0x10
#define WINDOW_FORCEHEIGHT 0x20
#define WINDOW_STYLECHANGED 0x40
#define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE)
int alerts_queued;
@@ -1311,6 +1280,13 @@ struct cmd_entry {
enum cmd_retval (*exec)(struct cmd *, struct cmdq_item *);
};
/* Status line. */
struct status_line {
struct event timer;
struct screen status;
struct screen *old_status;
};
/* Client connection. */
typedef int (*prompt_input_cb)(struct client *, void *, const char *, int);
typedef void (*prompt_free_cb)(void *);
@@ -1353,10 +1329,7 @@ struct client {
struct event click_timer;
u_int click_button;
struct event status_timer;
struct screen status;
struct screen *old_status;
struct status_line status;
#define CLIENT_TERMINAL 0x1
#define CLIENT_LOGIN 0x2
@@ -1381,6 +1354,7 @@ struct client {
#define CLIENT_DOUBLECLICK 0x100000
#define CLIENT_TRIPLECLICK 0x200000
#define CLIENT_SIZECHANGED 0x400000
#define CLIENT_STATUSOFF 0x800000
int flags;
struct key_table *keytable;
@@ -1388,6 +1362,7 @@ struct client {
void (*identify_callback)(struct client *,
struct window_pane *);
void *identify_callback_data;
struct cmdq_item *identify_callback_item;
char *message_string;
struct event message_timer;
@@ -1433,7 +1408,7 @@ struct key_binding {
RB_HEAD(key_bindings, key_binding);
struct key_table {
const char *name;
const char *name;
struct key_bindings key_bindings;
u_int references;
@@ -1454,6 +1429,7 @@ enum options_table_type {
OPTIONS_TABLE_STYLE,
OPTIONS_TABLE_ARRAY,
};
enum options_table_scope {
OPTIONS_TABLE_NONE,
OPTIONS_TABLE_SERVER,
@@ -1580,12 +1556,11 @@ void hooks_add(struct hooks *, const char *, struct cmd_list *);
void hooks_copy(struct hooks *, struct hooks *);
void hooks_remove(struct hooks *, const char *);
struct hook *hooks_find(struct hooks *, const char *);
void printflike(4, 5) hooks_run(struct hooks *, struct client *,
struct cmd_find_state *, const char *, ...);
void printflike(4, 5) hooks_insert(struct hooks *, struct cmdq_item *,
struct cmd_find_state *, const char *, ...);
/* notify.c */
void notify_hook(struct cmdq_item *, const char *);
void notify_input(struct window_pane *, struct evbuffer *);
void notify_client(const char *, struct client *);
void notify_session(const char *, struct session *);
@@ -1644,7 +1619,7 @@ extern const struct options_table_entry options_table[];
/* job.c */
extern struct joblist all_jobs;
struct job *job_run(const char *, struct session *, const char *,
job_update_cb, job_complete_cb, job_free_cb, void *);
job_update_cb, job_complete_cb, job_free_cb, void *, int);
void job_free(struct job *);
void job_died(struct job *, int);
@@ -1764,13 +1739,13 @@ long long args_strtonum(struct args *, u_char, long long, long long,
/* cmd-find.c */
int cmd_find_target(struct cmd_find_state *, struct cmdq_item *,
const char *, enum cmd_find_type, int);
struct client *cmd_find_best_client(struct session *);
struct client *cmd_find_client(struct cmdq_item *, const char *, int);
void cmd_find_clear_state(struct cmd_find_state *, int);
int cmd_find_empty_state(struct cmd_find_state *);
int cmd_find_valid_state(struct cmd_find_state *);
void cmd_find_copy_state(struct cmd_find_state *,
struct cmd_find_state *);
void cmd_find_log_state(const char *, struct cmd_find_state *);
void cmd_find_from_session(struct cmd_find_state *,
struct session *, int);
void cmd_find_from_winlink(struct cmd_find_state *,
@@ -1790,6 +1765,7 @@ int cmd_find_from_mouse(struct cmd_find_state *,
int cmd_find_from_nothing(struct cmd_find_state *, int);
/* cmd.c */
void cmd_log_argv(int, char **, const char *);
int cmd_pack_argv(int, char **, char *, size_t);
int cmd_unpack_argv(char *, size_t, int, char ***);
char **cmd_copy_argv(int, char **);
@@ -1839,13 +1815,13 @@ void cmd_wait_for_flush(void);
int client_main(struct event_base *, int, char **, int);
/* key-bindings.c */
RB_PROTOTYPE(key_bindings, key_binding, entry, key_bindings_cmp);
RB_PROTOTYPE(key_tables, key_table, entry, key_table_cmp);
extern struct key_tables key_tables;
int key_table_cmp(struct key_table *, struct key_table *);
int key_bindings_cmp(struct key_binding *, struct key_binding *);
struct key_table *key_bindings_get_table(const char *, int);
struct key_table *key_bindings_first_table(void);
struct key_table *key_bindings_next_table(struct key_table *);
void key_bindings_unref_table(struct key_table *);
struct key_binding *key_bindings_get(struct key_table *, key_code);
struct key_binding *key_bindings_first(struct key_table *);
struct key_binding *key_bindings_next(struct key_table *, struct key_binding *);
void key_bindings_add(const char *, key_code, int, struct cmd_list *);
void key_bindings_remove(const char *, key_code);
void key_bindings_remove_table(const char *);
@@ -1879,12 +1855,11 @@ void server_add_accept(int);
/* server-client.c */
u_int server_client_how_many(void);
void server_client_set_identify(struct client *, u_int);
void server_client_clear_identify(struct client *, struct window_pane *);
void server_client_set_key_table(struct client *, const char *);
const char *server_client_get_key_table(struct client *);
int server_client_check_nested(struct client *);
void server_client_handle_key(struct client *, key_code);
void server_client_create(int);
struct client *server_client_create(int);
int server_client_open(struct client *, char **);
void server_client_unref(struct client *);
void server_client_lost(struct client *);
@@ -1897,7 +1872,7 @@ void server_client_push_stderr(struct client *);
void printflike(2, 3) server_client_add_message(struct client *, const char *,
...);
char *server_client_get_path(struct client *, const char *);
const char *server_client_get_cwd(struct client *);
const char *server_client_get_cwd(struct client *, struct session *);
/* server-fn.c */
void server_redraw_client(struct client *);
@@ -1912,6 +1887,7 @@ void server_status_window(struct window *);
void server_lock(void);
void server_lock_session(struct session *);
void server_lock_client(struct client *);
void server_kill_pane(struct window_pane *);
void server_kill_window(struct window *);
int server_link_window(struct session *,
struct winlink *, struct session *, int, int, int, char **);
@@ -1928,6 +1904,7 @@ void status_timer_start(struct client *);
void status_timer_start_all(void);
void status_update_saved(struct session *s);
int status_at_line(struct client *);
u_int status_line_size(struct session *);
struct window *status_get_window_at(struct client *, u_int);
int status_redraw(struct client *);
void printflike(2, 3) status_message_set(struct client *, const char *, ...);
@@ -1994,7 +1971,9 @@ char *grid_string_cells(struct grid *, u_int, u_int, u_int,
struct grid_cell **, int, int, int);
void grid_duplicate_lines(struct grid *, u_int, struct grid *, u_int,
u_int);
u_int grid_reflow(struct grid *, struct grid *, u_int);
void grid_reflow(struct grid *, u_int, u_int *);
struct grid_line *grid_get_line(struct grid *, u_int);
void grid_adjust_lines(struct grid *, u_int);
/* grid-view.c */
void grid_view_get_cell(struct grid *, u_int, u_int, struct grid_cell *);
@@ -2035,6 +2014,8 @@ void screen_write_putc(struct screen_write_ctx *, const struct grid_cell *,
u_char);
void screen_write_copy(struct screen_write_ctx *, struct screen *, u_int,
u_int, u_int, u_int, bitstr_t *, const struct grid_cell *);
void screen_write_fast_copy(struct screen_write_ctx *, struct screen *,
u_int, u_int, u_int, u_int);
void screen_write_hline(struct screen_write_ctx *, u_int, int, int);
void screen_write_vline(struct screen_write_ctx *, u_int, int, int);
void screen_write_box(struct screen_write_ctx *, u_int, u_int);
@@ -2086,9 +2067,11 @@ void screen_reset_tabs(struct screen *);
void screen_set_cursor_style(struct screen *, u_int);
void screen_set_cursor_colour(struct screen *, const char *);
void screen_set_title(struct screen *, const char *);
void screen_push_title(struct screen *);
void screen_pop_title(struct screen *);
void screen_resize(struct screen *, u_int, u_int, int);
void screen_set_selection(struct screen *,
u_int, u_int, u_int, u_int, u_int, struct grid_cell *);
void screen_set_selection(struct screen *, u_int, u_int, u_int, u_int,
u_int, int, struct grid_cell *);
void screen_clear_selection(struct screen *);
void screen_hide_selection(struct screen *);
int screen_check_selection(struct screen *, u_int, u_int);
@@ -2132,7 +2115,7 @@ int window_has_pane(struct window *, struct window_pane *);
int window_set_active_pane(struct window *, struct window_pane *);
void window_redraw_active_switch(struct window *,
struct window_pane *);
struct window_pane *window_add_pane(struct window *, struct window_pane *,
struct window_pane *window_add_pane(struct window *, struct window_pane *, int,
int, u_int);
void window_resize(struct window *, u_int, u_int);
int window_zoom(struct window_pane *);
@@ -2188,6 +2171,9 @@ void layout_free_cell(struct layout_cell *);
void layout_print_cell(struct layout_cell *, const char *, u_int);
void layout_destroy_cell(struct window *, struct layout_cell *,
struct layout_cell **);
void layout_resize_layout(struct window *, struct layout_cell *,
enum layout_type, int, int);
struct layout_cell *layout_search_by_border(struct layout_cell *, u_int, u_int);
void layout_set_size(struct layout_cell *, u_int, u_int, u_int,
u_int);
void layout_make_leaf(struct layout_cell *, struct window_pane *);
@@ -2207,6 +2193,8 @@ void layout_assign_pane(struct layout_cell *, struct window_pane *);
struct layout_cell *layout_split_pane(struct window_pane *, enum layout_type,
int, int, int);
void layout_close_pane(struct window_pane *);
int layout_spread_cell(struct window *, struct layout_cell *);
void layout_spread_out(struct window_pane *);
/* layout-custom.c */
char *layout_dump(struct layout_cell *);
@@ -2219,17 +2207,22 @@ u_int layout_set_next(struct window *);
u_int layout_set_previous(struct window *);
/* mode-tree.c */
typedef void (*mode_tree_build_cb)(void *, u_int, uint64_t *, const char *);
typedef void (*mode_tree_draw_cb)(void *, void *, struct screen_write_ctx *,
u_int, u_int);
typedef int (*mode_tree_search_cb)(void *, void *, const char *);
typedef void (*mode_tree_each_cb)(void *, void *, struct client *, key_code);
u_int mode_tree_count_tagged(struct mode_tree_data *);
void *mode_tree_get_current(struct mode_tree_data *);
void mode_tree_each_tagged(struct mode_tree_data *, void (*)(void *, void *,
key_code), key_code, int);
void mode_tree_up(struct mode_tree_data *, int);
void mode_tree_expand_current(struct mode_tree_data *);
void mode_tree_set_current(struct mode_tree_data *, uint64_t);
void mode_tree_each_tagged(struct mode_tree_data *, mode_tree_each_cb,
struct client *, key_code, int);
void mode_tree_down(struct mode_tree_data *, int);
struct mode_tree_data *mode_tree_start(struct window_pane *, struct args *,
void (*)(void *, u_int, uint64_t *, const char *),
struct screen *(*)(void *, void *, u_int, u_int),
int (*)(void *, void *, const char *), void *, const char **,
u_int, struct screen **);
mode_tree_build_cb, mode_tree_draw_cb, mode_tree_search_cb,
void *, const char **, u_int, struct screen **);
void mode_tree_zoom(struct mode_tree_data *, struct args *);
void mode_tree_build(struct mode_tree_data *);
void mode_tree_free(struct mode_tree_data *);
void mode_tree_resize(struct mode_tree_data *, u_int, u_int);
@@ -2239,7 +2232,7 @@ struct mode_tree_item *mode_tree_add(struct mode_tree_data *,
void mode_tree_remove(struct mode_tree_data *, struct mode_tree_item *);
void mode_tree_draw(struct mode_tree_data *);
int mode_tree_key(struct mode_tree_data *, struct client *, key_code *,
struct mouse_event *);
struct mouse_event *, u_int *, u_int *);
void mode_tree_run_command(struct client *, struct cmd_find_state *,
const char *, const char *);
@@ -2294,11 +2287,8 @@ void control_notify_session_window_changed(struct session *);
/* session.c */
extern struct sessions sessions;
extern struct session_groups session_groups;
int session_cmp(struct session *, struct session *);
RB_PROTOTYPE(sessions, session, entry, session_cmp);
int session_group_cmp(struct session_group *, struct session_group *);
RB_PROTOTYPE(session_groups, session_group, entry, session_group_cmp);
int session_alive(struct session *);
struct session *session_find(const char *);
struct session *session_find_by_id_str(const char *);
@@ -2331,6 +2321,7 @@ struct session_group *session_group_new(const char *);
void session_group_add(struct session_group *, struct session *);
void session_group_synchronize_to(struct session *);
void session_group_synchronize_from(struct session *);
u_int session_group_count(struct session_group *);
void session_renumber_windows(struct session *);
/* utf8.c */

View File

@@ -20,7 +20,7 @@ then
else
SEQ=seq
fi
SEPARATOR=';'
SEPARATOR=':'
setBackgroundColor()
{

View File

@@ -171,7 +171,12 @@ static const struct tty_default_key_raw tty_default_raw_keys[] = {
{ "\033[201~", KEYC_PASTE_END },
};
/* Default terminfo(5) keys. */
/*
* Default terminfo(5) keys. Any keys that have builtin modifiers
* (that is, where the key itself contains the modifiers) has the
* KEYC_XTERM flag set so a leading escape is not treated as meta (and
* probably removed).
*/
struct tty_default_key_code {
enum tty_code_code code;
key_code key;
@@ -191,61 +196,61 @@ static const struct tty_default_key_code tty_default_code_keys[] = {
{ TTYC_KF11, KEYC_F11 },
{ TTYC_KF12, KEYC_F12 },
{ TTYC_KF13, KEYC_F1|KEYC_SHIFT },
{ TTYC_KF14, KEYC_F2|KEYC_SHIFT },
{ TTYC_KF15, KEYC_F3|KEYC_SHIFT },
{ TTYC_KF16, KEYC_F4|KEYC_SHIFT },
{ TTYC_KF17, KEYC_F5|KEYC_SHIFT },
{ TTYC_KF18, KEYC_F6|KEYC_SHIFT },
{ TTYC_KF19, KEYC_F7|KEYC_SHIFT },
{ TTYC_KF20, KEYC_F8|KEYC_SHIFT },
{ TTYC_KF21, KEYC_F9|KEYC_SHIFT },
{ TTYC_KF22, KEYC_F10|KEYC_SHIFT },
{ TTYC_KF23, KEYC_F11|KEYC_SHIFT },
{ TTYC_KF24, KEYC_F12|KEYC_SHIFT },
{ TTYC_KF13, KEYC_F1|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KF14, KEYC_F2|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KF15, KEYC_F3|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KF16, KEYC_F4|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KF17, KEYC_F5|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KF18, KEYC_F6|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KF19, KEYC_F7|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KF20, KEYC_F8|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KF21, KEYC_F9|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KF22, KEYC_F10|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KF23, KEYC_F11|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KF24, KEYC_F12|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KF25, KEYC_F1|KEYC_CTRL },
{ TTYC_KF26, KEYC_F2|KEYC_CTRL },
{ TTYC_KF27, KEYC_F3|KEYC_CTRL },
{ TTYC_KF28, KEYC_F4|KEYC_CTRL },
{ TTYC_KF29, KEYC_F5|KEYC_CTRL },
{ TTYC_KF30, KEYC_F6|KEYC_CTRL },
{ TTYC_KF31, KEYC_F7|KEYC_CTRL },
{ TTYC_KF32, KEYC_F8|KEYC_CTRL },
{ TTYC_KF33, KEYC_F9|KEYC_CTRL },
{ TTYC_KF34, KEYC_F10|KEYC_CTRL },
{ TTYC_KF35, KEYC_F11|KEYC_CTRL },
{ TTYC_KF36, KEYC_F12|KEYC_CTRL },
{ TTYC_KF25, KEYC_F1|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF26, KEYC_F2|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF27, KEYC_F3|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF28, KEYC_F4|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF29, KEYC_F5|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF30, KEYC_F6|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF31, KEYC_F7|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF32, KEYC_F8|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF33, KEYC_F9|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF34, KEYC_F10|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF35, KEYC_F11|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF36, KEYC_F12|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF37, KEYC_F1|KEYC_SHIFT|KEYC_CTRL },
{ TTYC_KF38, KEYC_F2|KEYC_SHIFT|KEYC_CTRL },
{ TTYC_KF39, KEYC_F3|KEYC_SHIFT|KEYC_CTRL },
{ TTYC_KF40, KEYC_F4|KEYC_SHIFT|KEYC_CTRL },
{ TTYC_KF41, KEYC_F5|KEYC_SHIFT|KEYC_CTRL },
{ TTYC_KF42, KEYC_F6|KEYC_SHIFT|KEYC_CTRL },
{ TTYC_KF43, KEYC_F7|KEYC_SHIFT|KEYC_CTRL },
{ TTYC_KF44, KEYC_F8|KEYC_SHIFT|KEYC_CTRL },
{ TTYC_KF45, KEYC_F9|KEYC_SHIFT|KEYC_CTRL },
{ TTYC_KF46, KEYC_F10|KEYC_SHIFT|KEYC_CTRL },
{ TTYC_KF47, KEYC_F11|KEYC_SHIFT|KEYC_CTRL },
{ TTYC_KF48, KEYC_F12|KEYC_SHIFT|KEYC_CTRL },
{ TTYC_KF37, KEYC_F1|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF38, KEYC_F2|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF39, KEYC_F3|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF40, KEYC_F4|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF41, KEYC_F5|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF42, KEYC_F6|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF43, KEYC_F7|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF44, KEYC_F8|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF45, KEYC_F9|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF46, KEYC_F10|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF47, KEYC_F11|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF48, KEYC_F12|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KF49, KEYC_F1|KEYC_ESCAPE },
{ TTYC_KF50, KEYC_F2|KEYC_ESCAPE },
{ TTYC_KF51, KEYC_F3|KEYC_ESCAPE },
{ TTYC_KF52, KEYC_F4|KEYC_ESCAPE },
{ TTYC_KF53, KEYC_F5|KEYC_ESCAPE },
{ TTYC_KF54, KEYC_F6|KEYC_ESCAPE },
{ TTYC_KF55, KEYC_F7|KEYC_ESCAPE },
{ TTYC_KF56, KEYC_F8|KEYC_ESCAPE },
{ TTYC_KF57, KEYC_F9|KEYC_ESCAPE },
{ TTYC_KF58, KEYC_F10|KEYC_ESCAPE },
{ TTYC_KF59, KEYC_F11|KEYC_ESCAPE },
{ TTYC_KF60, KEYC_F12|KEYC_ESCAPE },
{ TTYC_KF49, KEYC_F1|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KF50, KEYC_F2|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KF51, KEYC_F3|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KF52, KEYC_F4|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KF53, KEYC_F5|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KF54, KEYC_F6|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KF55, KEYC_F7|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KF56, KEYC_F8|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KF57, KEYC_F9|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KF58, KEYC_F10|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KF59, KEYC_F11|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KF60, KEYC_F12|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KF61, KEYC_F1|KEYC_ESCAPE|KEYC_SHIFT },
{ TTYC_KF62, KEYC_F2|KEYC_ESCAPE|KEYC_SHIFT },
{ TTYC_KF63, KEYC_F3|KEYC_ESCAPE|KEYC_SHIFT },
{ TTYC_KF61, KEYC_F1|KEYC_ESCAPE|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KF62, KEYC_F2|KEYC_ESCAPE|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KF63, KEYC_F3|KEYC_ESCAPE|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KICH1, KEYC_IC },
{ TTYC_KDCH1, KEYC_DC },
@@ -261,17 +266,14 @@ static const struct tty_default_key_code tty_default_code_keys[] = {
{ TTYC_KCUB1, KEYC_LEFT },
{ TTYC_KCUF1, KEYC_RIGHT },
/*
* Key and modifier capabilities. We set the xterm flag to mark that
* any leading escape means an escape key press and not the modifier.
*/
/* Key and modifier capabilities. */
{ TTYC_KDC2, KEYC_DC|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KDC3, KEYC_DC|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KDC4, KEYC_DC|KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KDC5, KEYC_DC|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KDC6, KEYC_DC|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KDC7, KEYC_DC|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KIND, KEYC_UP|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KIND, KEYC_DOWN|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KDN2, KEYC_DOWN|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KDN3, KEYC_DOWN|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KDN4, KEYC_DOWN|KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM },

View File

@@ -240,6 +240,7 @@ static const struct tty_term_code_entry tty_term_codes[] = {
[TTYC_MS] = { TTYCODE_STRING, "Ms" },
[TTYC_OP] = { TTYCODE_STRING, "op" },
[TTYC_REV] = { TTYCODE_STRING, "rev" },
[TTYC_RGB] = { TTYCODE_FLAG, "RGB" },
[TTYC_RI] = { TTYCODE_STRING, "ri" },
[TTYC_RMACS] = { TTYCODE_STRING, "rmacs" },
[TTYC_RMCUP] = { TTYCODE_STRING, "rmcup" },
@@ -493,8 +494,9 @@ tty_term_find(char *name, int fd, char **cause)
goto error;
}
/* Figure out if we have 256. */
if (tty_term_number(term, TTYC_COLORS) == 256)
/* Figure out if we have 256 colours (or more). */
if (tty_term_number(term, TTYC_COLORS) >= 256 ||
tty_term_has(term, TTYC_RGB))
term->flags |= TERM_256COLOURS;
/*
@@ -531,8 +533,11 @@ tty_term_find(char *name, int fd, char **cause)
code->type = TTYCODE_STRING;
}
/* On terminals with RGB colour (TC), fill in setrgbf and setrgbb. */
if (tty_term_flag(term, TTYC_TC) &&
/*
* On terminals with RGB colour (Tc or RGB), fill in setrgbf and
* setrgbb if they are missing.
*/
if ((tty_term_flag(term, TTYC_TC) || tty_term_flag(term, TTYC_RGB)) &&
!tty_term_has(term, TTYC_SETRGBF) &&
!tty_term_has(term, TTYC_SETRGBB)) {
code = &term->codes[TTYC_SETRGBF];

157
tty.c
View File

@@ -878,15 +878,42 @@ tty_draw_pane(struct tty *tty, const struct window_pane *wp, u_int py, u_int ox,
tty_draw_line(tty, wp, wp->screen, py, ox, oy);
}
static const struct grid_cell *
tty_check_codeset(struct tty *tty, const struct grid_cell *gc)
{
static struct grid_cell new;
u_int n;
/* Characters less than 0x7f are always fine, no matter what. */
if (gc->data.size == 1 && *gc->data.data < 0x7f)
return (gc);
/* UTF-8 terminal and a UTF-8 character - fine. */
if (tty->flags & TTY_UTF8)
return (gc);
/* Replace by the right number of underscores. */
n = gc->data.width;
if (n > UTF8_SIZE)
n = UTF8_SIZE;
memcpy(&new, gc, sizeof new);
new.data.size = n;
memset(new.data.data, '_', n);
return (&new);
}
void
tty_draw_line(struct tty *tty, const struct window_pane *wp,
struct screen *s, u_int py, u_int ox, u_int oy)
{
struct grid *gd = s->grid;
struct grid_cell gc, last;
const struct grid_cell *gcp;
u_int i, j, ux, sx, nx, width;
int flags, cleared = 0;
char buf[512];
size_t len, old_len;
u_int cellsize;
flags = (tty->flags & TTY_NOCURSOR);
tty->flags |= TTY_NOCURSOR;
@@ -900,15 +927,17 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
* there may be empty background cells after it (from BCE).
*/
sx = screen_size_x(s);
if (sx > s->grid->linedata[s->grid->hsize + py].cellsize)
sx = s->grid->linedata[s->grid->hsize + py].cellsize;
cellsize = grid_get_line(gd, gd->hsize + py)->cellsize;
if (sx > cellsize)
sx = cellsize;
if (sx > tty->sx)
sx = tty->sx;
ux = 0;
if (wp == NULL ||
py == 0 ||
(~s->grid->linedata[s->grid->hsize + py - 1].flags & GRID_LINE_WRAPPED) ||
(~grid_get_line(gd, gd->hsize + py - 1)->flags & GRID_LINE_WRAPPED) ||
ox != 0 ||
tty->cx < tty->sx ||
screen_size_x(s) < tty->sx) {
@@ -932,18 +961,16 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
width = 0;
for (i = 0; i < sx; i++) {
grid_view_get_cell(s->grid, i, py, &gc);
grid_view_get_cell(gd, i, py, &gc);
gcp = tty_check_codeset(tty, &gc);
if (len != 0 &&
(((~tty->flags & TTY_UTF8) &&
(gc.data.size != 1 ||
*gc.data.data >= 0x7f ||
gc.data.width != 1)) ||
(gc.attr & GRID_ATTR_CHARSET) ||
gc.flags != last.flags ||
gc.attr != last.attr ||
gc.fg != last.fg ||
gc.bg != last.bg ||
(sizeof buf) - len < gc.data.size)) {
((gcp->attr & GRID_ATTR_CHARSET) ||
gcp->flags != last.flags ||
gcp->attr != last.attr ||
gcp->fg != last.fg ||
gcp->bg != last.bg ||
ux + width + gcp->data.width >= screen_size_x(s) ||
(sizeof buf) - len < gcp->data.size)) {
tty_attributes(tty, &last, wp);
tty_putn(tty, buf, len, width);
ux += width;
@@ -952,28 +979,27 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
width = 0;
}
if (gc.flags & GRID_FLAG_SELECTED)
screen_select_cell(s, &last, &gc);
if (gcp->flags & GRID_FLAG_SELECTED)
screen_select_cell(s, &last, gcp);
else
memcpy(&last, &gc, sizeof last);
if (((~tty->flags & TTY_UTF8) &&
(gc.data.size != 1 ||
*gc.data.data >= 0x7f ||
gc.data.width != 1)) ||
(gc.attr & GRID_ATTR_CHARSET)) {
memcpy(&last, gcp, sizeof last);
if (ux + gcp->data.width > screen_size_x(s)) {
tty_attributes(tty, &last, wp);
if (~tty->flags & TTY_UTF8) {
for (j = 0; j < gc.data.width; j++)
tty_putc(tty, '_');
} else {
for (j = 0; j < gc.data.size; j++)
tty_putc(tty, gc.data.data[j]);
for (j = 0; j < gcp->data.width; j++) {
if (ux + j > screen_size_x(s))
break;
tty_putc(tty, ' ');
ux++;
}
} else if (gcp->attr & GRID_ATTR_CHARSET) {
tty_attributes(tty, &last, wp);
for (j = 0; j < gcp->data.size; j++)
tty_putc(tty, gcp->data.data[j]);
ux += gc.data.width;
} else {
memcpy(buf + len, gc.data.data, gc.data.size);
len += gc.data.size;
width += gc.data.width;
memcpy(buf + len, gcp->data.data, gcp->data.size);
len += gcp->data.size;
width += gcp->data.width;
}
}
if (len != 0) {
@@ -993,8 +1019,8 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
}
}
nx = screen_size_x(s) - ux;
if (!cleared && ux < tty->sx && nx != 0) {
if (!cleared && ux < screen_size_x(s)) {
nx = screen_size_x(s) - ux;
tty_default_attributes(tty, wp, 8);
tty_clear_line(tty, wp, oy + py, ox + ux, nx, 8);
}
@@ -1038,7 +1064,7 @@ tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *),
ctx->xoff = wp->xoff;
ctx->yoff = wp->yoff;
if (status_at_line(c) == 0)
ctx->yoff++;
ctx->yoff += status_line_size(c->session);
cmdfn(&c->tty, ctx);
}
@@ -1221,13 +1247,18 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
tty_margin_pane(tty, ctx);
/*
* If we want to wrap a pane, the cursor needs to be exactly on the
* right of the region. But if the pane isn't on the right, it may be
* off the edge - if so, move the cursor back to the right.
* If we want to wrap a pane while using margins, the cursor needs to
* be exactly on the right of the region. If the cursor is entirely off
* the edge - move it back to the right. Some terminals are funny about
* this and insert extra spaces, so only use the right if margins are
* enabled.
*/
if (ctx->xoff + ctx->ocx > tty->rright)
tty_cursor(tty, tty->rright, ctx->yoff + ctx->ocy);
else
if (ctx->xoff + ctx->ocx > tty->rright) {
if (!tty_use_margin(tty))
tty_cursor(tty, 0, ctx->yoff + ctx->ocy);
else
tty_cursor(tty, tty->rright, ctx->yoff + ctx->ocy);
} else
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
tty_putc(tty, '\n');
@@ -1252,11 +1283,16 @@ tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx)
tty_margin_pane(tty, ctx);
if (ctx->num == 1 || !tty_term_has(tty->term, TTYC_INDN)) {
tty_cursor(tty, tty->rright, tty->rlower);
if (!tty_use_margin(tty))
tty_cursor(tty, 0, tty->rlower);
else
tty_cursor(tty, tty->rright, tty->rlower);
for (i = 0; i < ctx->num; i++)
tty_putc(tty, '\n');
} else
} else {
tty_cursor(tty, 0, tty->cy);
tty_putcode1(tty, TTYC_INDN, ctx->num);
}
}
void
@@ -1400,7 +1436,7 @@ static void
tty_cell(struct tty *tty, const struct grid_cell *gc,
const struct window_pane *wp)
{
u_int i;
const struct grid_cell *gcp;
/* Skip last character if terminal is stupid. */
if ((tty->term->flags & TERM_EARLYWRAP) &&
@@ -1416,22 +1452,16 @@ tty_cell(struct tty *tty, const struct grid_cell *gc,
tty_attributes(tty, gc, wp);
/* Get the cell and if ASCII write with putc to do ACS translation. */
if (gc->data.size == 1) {
if (*gc->data.data < 0x20 || *gc->data.data == 0x7f)
gcp = tty_check_codeset(tty, gc);
if (gcp->data.size == 1) {
if (*gcp->data.data < 0x20 || *gcp->data.data == 0x7f)
return;
tty_putc(tty, *gc->data.data);
return;
}
/* If not UTF-8, write _. */
if (!(tty->flags & TTY_UTF8)) {
for (i = 0; i < gc->data.width; i++)
tty_putc(tty, '_');
tty_putc(tty, *gcp->data.data);
return;
}
/* Write the data. */
tty_putn(tty, gc->data.data, gc->data.size, gc->data.width);
tty_putn(tty, gcp->data.data, gcp->data.size, gcp->data.width);
}
void
@@ -1973,8 +2003,7 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc)
char s[32];
/* Is this a 24-bit or 256-colour colour? */
if (gc->fg & COLOUR_FLAG_RGB ||
gc->fg & COLOUR_FLAG_256) {
if (gc->fg & COLOUR_FLAG_RGB || gc->fg & COLOUR_FLAG_256) {
if (tty_try_colour(tty, gc->fg, "38") == 0)
goto save_fg;
/* Should not get here, already converted in tty_check_fg. */
@@ -2003,8 +2032,7 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc)
char s[32];
/* Is this a 24-bit or 256-colour colour? */
if (gc->bg & COLOUR_FLAG_RGB ||
gc->bg & COLOUR_FLAG_256) {
if (gc->bg & COLOUR_FLAG_RGB || gc->bg & COLOUR_FLAG_256) {
if (tty_try_colour(tty, gc->bg, "48") == 0)
goto save_bg;
/* Should not get here, already converted in tty_check_bg. */
@@ -2034,11 +2062,15 @@ tty_try_colour(struct tty *tty, int colour, const char *type)
if (colour & COLOUR_FLAG_256) {
/*
* If the user has specified -2 to the client, setaf and setab
* may not work (or they may not want to use them), so send the
* usual sequence.
* If the user has specified -2 to the client (meaning
* TERM_256COLOURS is set), setaf and setab may not work (or
* they may not want to use them), so send the usual sequence.
*
* Also if RGB is set, setaf and setab do not support the 256
* colour palette so use the sequences directly there too.
*/
if (tty->term_flags & TERM_256COLOURS)
if ((tty->term_flags & TERM_256COLOURS) ||
tty_term_has(tty->term, TTYC_RGB))
goto fallback_256;
/*
@@ -2079,6 +2111,7 @@ tty_try_colour(struct tty *tty, int colour, const char *type)
fallback_256:
xsnprintf(s, sizeof s, "\033[%s;5;%dm", type, colour & 0xff);
log_debug("%s: 256 colour fallback: %s", tty->client->name, s);
tty_puts(tty, s);
return (0);
}

View File

@@ -195,26 +195,20 @@ window_buffer_build(void *modedata, u_int sort_type, __unused uint64_t *tag,
}
static struct screen *
window_buffer_draw(__unused void *modedata, void *itemdata, u_int sx, u_int sy)
static void
window_buffer_draw(__unused void *modedata, void *itemdata,
struct screen_write_ctx *ctx, u_int sx, u_int sy)
{
struct window_buffer_itemdata *item = itemdata;
struct paste_buffer *pb;
static struct screen s;
struct screen_write_ctx ctx;
char line[1024];
const char *pdata, *end, *cp;
size_t psize, at;
u_int i;
u_int i, cx = ctx->s->cx, cy = ctx->s->cy;
pb = paste_get_name(item->name);
if (pb == NULL)
return (NULL);
screen_init(&s, sx, sy, 0);
screen_write_start(&ctx, NULL, &s);
screen_write_clearscreen(&ctx, 8);
return;
pdata = end = paste_buffer_data(pb, &psize);
for (i = 0; i < sy; i++) {
@@ -231,17 +225,14 @@ window_buffer_draw(__unused void *modedata, void *itemdata, u_int sx, u_int sy)
line[at] = '\0';
if (*line != '\0') {
screen_write_cursormove(&ctx, 0, i);
screen_write_puts(&ctx, &grid_default_cell, "%s", line);
screen_write_cursormove(ctx, cx, cy + i);
screen_write_puts(ctx, &grid_default_cell, "%s", line);
}
if (end == pdata + psize)
break;
end++;
}
screen_write_stop(&ctx);
return (&s);
}
static int
@@ -281,6 +272,7 @@ window_buffer_init(struct window_pane *wp, __unused struct cmd_find_state *fs,
data->data = mode_tree_start(wp, args, window_buffer_build,
window_buffer_draw, window_buffer_search, data,
window_buffer_sort_list, nitems(window_buffer_sort_list), &s);
mode_tree_zoom(data->data, args);
mode_tree_build(data->data);
mode_tree_draw(data->data);
@@ -318,7 +310,8 @@ window_buffer_resize(struct window_pane *wp, u_int sx, u_int sy)
}
static void
window_buffer_do_delete(void* modedata, void *itemdata, __unused key_code key)
window_buffer_do_delete(void* modedata, void *itemdata,
__unused struct client *c, __unused key_code key)
{
struct window_buffer_modedata *data = modedata;
struct window_buffer_itemdata *item = itemdata;
@@ -330,53 +323,53 @@ window_buffer_do_delete(void* modedata, void *itemdata, __unused key_code key)
paste_free(pb);
}
static void
window_buffer_do_paste(void* modedata, void *itemdata, struct client *c,
__unused key_code key)
{
struct window_buffer_modedata *data = modedata;
struct window_buffer_itemdata *item = itemdata;
struct paste_buffer *pb;
if ((pb = paste_get_name(item->name)) != NULL)
mode_tree_run_command(c, NULL, data->command, item->name);
}
static void
window_buffer_key(struct window_pane *wp, struct client *c,
__unused struct session *s, key_code key, struct mouse_event *m)
{
struct window_buffer_modedata *data = wp->modedata;
struct mode_tree_data *mtd = data->data;
struct window_buffer_itemdata *item;
char *command, *name;
int finished;
/*
* t = toggle tag
* T = tag none
* C-t = tag all
* q = exit
* O = change sort order
*
* d = delete buffer
* D = delete tagged buffers
* Enter = paste buffer
*/
finished = mode_tree_key(data->data, c, &key, m);
finished = mode_tree_key(mtd, c, &key, m, NULL, NULL);
switch (key) {
case 'd':
item = mode_tree_get_current(data->data);
window_buffer_do_delete(data, item, key);
mode_tree_build(data->data);
item = mode_tree_get_current(mtd);
window_buffer_do_delete(data, item, c, key);
mode_tree_build(mtd);
break;
case 'D':
mode_tree_each_tagged(data->data, window_buffer_do_delete, key,
0);
mode_tree_build(data->data);
mode_tree_each_tagged(mtd, window_buffer_do_delete, c, key, 0);
mode_tree_build(mtd);
break;
case 'P':
mode_tree_each_tagged(mtd, window_buffer_do_paste, c, key, 0);
finished = 1;
break;
case 'p':
case '\r':
item = mode_tree_get_current(data->data);
command = xstrdup(data->command);
name = xstrdup(item->name);
window_pane_reset_mode(wp);
mode_tree_run_command(c, NULL, command, name);
free(name);
free(command);
return;
item = mode_tree_get_current(mtd);
window_buffer_do_paste(data, item, c, key);
finished = 1;
break;
}
if (finished || paste_get_top(NULL) == NULL)
window_pane_reset_mode(wp);
else {
mode_tree_draw(data->data);
mode_tree_draw(mtd);
wp->flags |= PANE_REDRAW;
}
}

View File

@@ -210,37 +210,29 @@ window_client_build(void *modedata, u_int sort_type, __unused uint64_t *tag,
}
}
static struct screen *
window_client_draw(__unused void *modedata, void *itemdata, u_int sx, u_int sy)
static void
window_client_draw(__unused void *modedata, void *itemdata,
struct screen_write_ctx *ctx, u_int sx, u_int sy)
{
struct window_client_itemdata *item = itemdata;
struct client *c = item->c;
struct window_pane *wp;
static struct screen s;
struct screen_write_ctx ctx;
u_int cx = ctx->s->cx, cy = ctx->s->cy;
if (c->session == NULL || (c->flags & (CLIENT_DEAD|CLIENT_DETACHING)))
return (NULL);
return;
wp = c->session->curw->window->active;
screen_init(&s, sx, sy, 0);
screen_write_preview(ctx, &wp->base, sx, sy - 3);
screen_write_start(&ctx, NULL, &s);
screen_write_clearscreen(&ctx, 8);
screen_write_cursormove(ctx, cx, cy + sy - 2);
screen_write_hline(ctx, sx, 0, 0);
screen_write_preview(&ctx, &wp->base, sx, sy - 3);
screen_write_cursormove(&ctx, 0, sy - 2);
screen_write_hline(&ctx, sx, 0, 0);
screen_write_cursormove(&ctx, 0, sy - 1);
if (c->old_status != NULL)
screen_write_copy(&ctx, c->old_status, 0, 0, sx, 1, NULL, NULL);
screen_write_cursormove(ctx, cx, cy + sy - 1);
if (c->status.old_status != NULL)
screen_write_fast_copy(ctx, c->status.old_status, 0, 0, sx, 1);
else
screen_write_copy(&ctx, &c->status, 0, 0, sx, 1, NULL, NULL);
screen_write_stop(&ctx);
return (&s);
screen_write_fast_copy(ctx, &c->status.status, 0, 0, sx, 1);
}
static struct screen *
@@ -264,6 +256,7 @@ window_client_init(struct window_pane *wp, __unused struct cmd_find_state *fs,
data->data = mode_tree_start(wp, args, window_client_build,
window_client_draw, NULL, data, window_client_sort_list,
nitems(window_client_sort_list), &s);
mode_tree_zoom(data->data, args);
mode_tree_build(data->data);
mode_tree_draw(data->data);
@@ -301,7 +294,8 @@ window_client_resize(struct window_pane *wp, u_int sx, u_int sy)
}
static void
window_client_do_detach(void* modedata, void *itemdata, key_code key)
window_client_do_detach(void* modedata, void *itemdata,
__unused struct client *c, key_code key)
{
struct window_client_modedata *data = modedata;
struct window_client_itemdata *item = itemdata;
@@ -321,56 +315,35 @@ window_client_key(struct window_pane *wp, struct client *c,
__unused struct session *s, key_code key, struct mouse_event *m)
{
struct window_client_modedata *data = wp->modedata;
struct mode_tree_data *mtd = data->data;
struct window_client_itemdata *item;
char *command, *name;
int finished;
/*
* t = toggle tag
* T = tag none
* C-t = tag all
* q = exit
* O = change sort order
*
* d = detach client
* D = detach tagged clients
* x = detach and kill client
* X = detach and kill tagged clients
* z = suspend client
* Z = suspend tagged clients
* Enter = detach client
*/
finished = mode_tree_key(data->data, c, &key, m);
finished = mode_tree_key(mtd, c, &key, m, NULL, NULL);
switch (key) {
case 'd':
case 'x':
case 'z':
item = mode_tree_get_current(data->data);
window_client_do_detach(data, item, key);
mode_tree_build(data->data);
item = mode_tree_get_current(mtd);
window_client_do_detach(data, item, c, key);
mode_tree_build(mtd);
break;
case 'D':
case 'X':
case 'Z':
mode_tree_each_tagged(data->data, window_client_do_detach, key,
0);
mode_tree_build(data->data);
mode_tree_each_tagged(mtd, window_client_do_detach, c, key, 0);
mode_tree_build(mtd);
break;
case '\r':
item = mode_tree_get_current(data->data);
command = xstrdup(data->command);
name = xstrdup(item->c->ttyname);
window_pane_reset_mode(wp);
mode_tree_run_command(c, NULL, command, name);
free(name);
free(command);
return;
item = mode_tree_get_current(mtd);
mode_tree_run_command(c, NULL, data->command, item->c->ttyname);
finished = 1;
break;
}
if (finished || server_client_how_many() == 0)
window_pane_reset_mode(wp);
else {
mode_tree_draw(data->data);
mode_tree_draw(mtd);
wp->flags |= PANE_REDRAW;
}
}

View File

@@ -30,7 +30,7 @@ static void window_copy_command(struct window_pane *, struct client *,
static struct screen *window_copy_init(struct window_pane *,
struct cmd_find_state *, struct args *);
static void window_copy_free(struct window_pane *);
static int window_copy_pagedown(struct window_pane *, int);
static int window_copy_pagedown(struct window_pane *, int, int);
static void window_copy_next_paragraph(struct window_pane *);
static void window_copy_previous_paragraph(struct window_pane *);
static void window_copy_resize(struct window_pane *, u_int, u_int);
@@ -57,16 +57,17 @@ static void window_copy_move_right(struct screen *, u_int *, u_int *);
static int window_copy_is_lowercase(const char *);
static int window_copy_search_jump(struct window_pane *, struct grid *,
struct grid *, u_int, u_int, u_int, int, int, int);
static int window_copy_search(struct window_pane *, int, int);
static int window_copy_search_up(struct window_pane *, int);
static int window_copy_search_down(struct window_pane *, int);
static int window_copy_search(struct window_pane *, int);
static int window_copy_search_up(struct window_pane *);
static int window_copy_search_down(struct window_pane *);
static void window_copy_goto_line(struct window_pane *, const char *);
static void window_copy_update_cursor(struct window_pane *, u_int, u_int);
static void window_copy_start_selection(struct window_pane *);
static int window_copy_adjust_selection(struct window_pane *, u_int *,
u_int *);
static int window_copy_set_selection(struct window_pane *, int);
static int window_copy_update_selection(struct window_pane *, int);
static void window_copy_synchronize_cursor(struct window_pane *wp);
static void window_copy_synchronize_cursor(struct window_pane *);
static void *window_copy_get_selection(struct window_pane *, size_t *);
static void window_copy_copy_buffer(struct window_pane *, const char *,
void *, size_t);
@@ -91,8 +92,8 @@ static void window_copy_cursor_up(struct window_pane *, int);
static void window_copy_cursor_down(struct window_pane *, int);
static void window_copy_cursor_jump(struct window_pane *);
static void window_copy_cursor_jump_back(struct window_pane *);
static void window_copy_cursor_jump_to(struct window_pane *, int);
static void window_copy_cursor_jump_to_back(struct window_pane *, int);
static void window_copy_cursor_jump_to(struct window_pane *);
static void window_copy_cursor_jump_to_back(struct window_pane *);
static void window_copy_cursor_next_word(struct window_pane *,
const char *);
static void window_copy_cursor_next_word_end(struct window_pane *,
@@ -151,12 +152,12 @@ struct window_copy_mode_data {
struct screen *backing;
int backing_written; /* backing display started */
u_int oy; /* number of lines scrolled up */
u_int oy; /* number of lines scrolled up */
u_int selx; /* beginning of selection */
u_int selx; /* beginning of selection */
u_int sely;
u_int endselx; /* end of selection */
u_int endselx; /* end of selection */
u_int endsely;
enum {
@@ -165,14 +166,20 @@ struct window_copy_mode_data {
CURSORDRAG_SEL, /* start is synchronized with cursor */
} cursordrag;
int modekeys;
enum {
LINE_SEL_NONE,
LINE_SEL_LEFT_RIGHT,
LINE_SEL_RIGHT_LEFT,
} lineflag; /* line selection mode */
int rectflag; /* in rectangle copy mode? */
int scroll_exit; /* exit on scroll to end? */
u_int cx;
u_int cy;
u_int lastcx; /* position in last line w/ content */
u_int lastsx; /* size of last line w/ content */
u_int lastcx; /* position in last line w/ content */
u_int lastsx; /* size of last line w/ content */
int searchtype;
char *searchstr;
@@ -194,21 +201,10 @@ window_copy_init(struct window_pane *wp, __unused struct cmd_find_state *fs,
struct window_copy_mode_data *data;
struct screen *s;
wp->modedata = data = xmalloc(sizeof *data);
data->oy = 0;
data->cx = 0;
data->cy = 0;
wp->modedata = data = xcalloc(1, sizeof *data);
data->cursordrag = CURSORDRAG_NONE;
data->lastcx = 0;
data->lastsx = 0;
data->backing_written = 0;
data->rectflag = 0;
data->scroll_exit = 0;
data->lineflag = LINE_SEL_NONE;
if (wp->searchstr != NULL) {
data->searchtype = WINDOW_COPY_SEARCHUP;
@@ -228,7 +224,7 @@ window_copy_init(struct window_pane *wp, __unused struct cmd_find_state *fs,
s = &data->screen;
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
s->sel.modekeys = options_get_number(wp->window->options, "mode-keys");
data->modekeys = options_get_number(wp->window->options, "mode-keys");
data->backing = NULL;
@@ -357,7 +353,7 @@ window_copy_pageup(struct window_pane *wp, int half_page)
oy = screen_hsize(data->backing) + data->cy - data->oy;
ox = window_copy_find_length(wp, oy);
if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
window_copy_other_end(wp);
if (data->cx != ox) {
@@ -379,7 +375,7 @@ window_copy_pageup(struct window_pane *wp, int half_page)
else
data->oy += n;
if (!data->screen.sel.flag || !data->rectflag) {
if (data->screen.sel == NULL || !data->rectflag) {
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if ((data->cx >= data->lastsx && data->cx != px) ||
@@ -392,7 +388,7 @@ window_copy_pageup(struct window_pane *wp, int half_page)
}
static int
window_copy_pagedown(struct window_pane *wp, int half_page)
window_copy_pagedown(struct window_pane *wp, int half_page, int scroll_exit)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
@@ -401,7 +397,7 @@ window_copy_pagedown(struct window_pane *wp, int half_page)
oy = screen_hsize(data->backing) + data->cy - data->oy;
ox = window_copy_find_length(wp, oy);
if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT && oy == data->sely)
if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->sely)
window_copy_other_end(wp);
if (data->cx != ox) {
@@ -423,7 +419,7 @@ window_copy_pagedown(struct window_pane *wp, int half_page)
else
data->oy -= n;
if (!data->screen.sel.flag || !data->rectflag) {
if (data->screen.sel == NULL || !data->rectflag) {
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if ((data->cx >= data->lastsx && data->cx != px) ||
@@ -431,7 +427,7 @@ window_copy_pagedown(struct window_pane *wp, int half_page)
window_copy_cursor_end_of_line(wp);
}
if (data->scroll_exit && data->oy == 0)
if (scroll_exit && data->oy == 0)
return (1);
window_copy_update_selection(wp, 1);
window_copy_redraw_screen(wp);
@@ -524,7 +520,7 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
struct screen *sn = &data->screen;
const char *command, *argument, *ws;
u_int np = wp->modeprefix;
int cancel = 0, redraw = 0;
int cancel = 0, redraw = 0, scroll_exit;
char prefix;
if (args->argc == 0)
@@ -554,7 +550,7 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
if (m != NULL)
window_copy_start_drag(c, m);
else {
sn->sel.lineflag = LINE_SEL_NONE;
data->lineflag = LINE_SEL_NONE;
window_copy_start_selection(wp);
redraw = 1;
}
@@ -629,9 +625,14 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
}
if (strcmp(command, "end-of-line") == 0)
window_copy_cursor_end_of_line(wp);
if (strcmp(command, "halfpage-down") == 0) {
if (strcmp(command, "halfpage-down") == 0 ||
strcmp(command, "halfpage-down-and-cancel") == 0) {
if (strcmp(command, "halfpage-down-and-cancel") == 0)
scroll_exit = 1;
else
scroll_exit = data->scroll_exit;
for (; np != 0; np--) {
if (window_copy_pagedown(wp, 1)) {
if (window_copy_pagedown(wp, 1, scroll_exit)) {
cancel = 1;
break;
}
@@ -667,11 +668,11 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
break;
case WINDOW_COPY_JUMPTOFORWARD:
for (; np != 0; np--)
window_copy_cursor_jump_to(wp, 1);
window_copy_cursor_jump_to(wp);
break;
case WINDOW_COPY_JUMPTOBACKWARD:
for (; np != 0; np--)
window_copy_cursor_jump_to_back(wp, 1);
window_copy_cursor_jump_to_back(wp);
break;
}
}
@@ -687,11 +688,11 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
break;
case WINDOW_COPY_JUMPTOFORWARD:
for (; np != 0; np--)
window_copy_cursor_jump_to_back(wp, 1);
window_copy_cursor_jump_to_back(wp);
break;
case WINDOW_COPY_JUMPTOBACKWARD:
for (; np != 0; np--)
window_copy_cursor_jump_to(wp, 1);
window_copy_cursor_jump_to(wp);
break;
}
}
@@ -727,9 +728,14 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
if ((np % 2) != 0)
window_copy_other_end(wp);
}
if (strcmp(command, "page-down") == 0) {
if (strcmp(command, "page-down") == 0 ||
strcmp(command, "page-down-and-cancel") == 0) {
if (strcmp(command, "page-down-and-cancel") == 0)
scroll_exit = 1;
else
scroll_exit = data->scroll_exit;
for (; np != 0; np--) {
if (window_copy_pagedown(wp, 0)) {
if (window_copy_pagedown(wp, 0, scroll_exit)) {
cancel = 1;
break;
}
@@ -753,13 +759,18 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
window_copy_cursor_previous_word(wp, ws);
}
if (strcmp(command, "rectangle-toggle") == 0) {
sn->sel.lineflag = LINE_SEL_NONE;
data->lineflag = LINE_SEL_NONE;
window_copy_rectangle_toggle(wp);
}
if (strcmp(command, "scroll-down") == 0) {
if (strcmp(command, "scroll-down") == 0 ||
strcmp(command, "scroll-down-and-cancel") == 0) {
if (strcmp(command, "scroll-down-and-cancel") == 0)
scroll_exit = 1;
else
scroll_exit = data->scroll_exit;
for (; np != 0; np--)
window_copy_cursor_down(wp, 1);
if (data->scroll_exit && data->oy == 0)
if (scroll_exit && data->oy == 0)
cancel = 1;
}
if (strcmp(command, "scroll-up") == 0) {
@@ -769,23 +780,23 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
if (strcmp(command, "search-again") == 0) {
if (data->searchtype == WINDOW_COPY_SEARCHUP) {
for (; np != 0; np--)
window_copy_search_up(wp, 1);
window_copy_search_up(wp);
} else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
for (; np != 0; np--)
window_copy_search_down(wp, 1);
window_copy_search_down(wp);
}
}
if (strcmp(command, "search-reverse") == 0) {
if (data->searchtype == WINDOW_COPY_SEARCHUP) {
for (; np != 0; np--)
window_copy_search_down(wp, 1);
window_copy_search_down(wp);
} else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
for (; np != 0; np--)
window_copy_search_up(wp, 1);
window_copy_search_up(wp);
}
}
if (strcmp(command, "select-line") == 0) {
sn->sel.lineflag = LINE_SEL_LEFT_RIGHT;
data->lineflag = LINE_SEL_LEFT_RIGHT;
data->rectflag = 0;
window_copy_cursor_start_of_line(wp);
window_copy_start_selection(wp);
@@ -795,7 +806,7 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
redraw = 1;
}
if (strcmp(command, "select-word") == 0) {
sn->sel.lineflag = LINE_SEL_LEFT_RIGHT;
data->lineflag = LINE_SEL_LEFT_RIGHT;
data->rectflag = 0;
ws = options_get_string(s->options, "word-separators");
window_copy_cursor_previous_word(wp, ws);
@@ -841,27 +852,27 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
data->jumptype = WINDOW_COPY_JUMPTOBACKWARD;
data->jumpchar = *argument;
for (; np != 0; np--)
window_copy_cursor_jump_to_back(wp, 1);
window_copy_cursor_jump_to_back(wp);
}
if (strcmp(command, "jump-to-forward") == 0) {
data->jumptype = WINDOW_COPY_JUMPTOFORWARD;
data->jumpchar = *argument;
for (; np != 0; np--)
window_copy_cursor_jump_to(wp, 1);
window_copy_cursor_jump_to(wp);
}
if (strcmp(command, "search-backward") == 0) {
data->searchtype = WINDOW_COPY_SEARCHUP;
free(data->searchstr);
data->searchstr = xstrdup(argument);
for (; np != 0; np--)
window_copy_search_up(wp, 1);
window_copy_search_up(wp);
}
if (strcmp(command, "search-forward") == 0) {
data->searchtype = WINDOW_COPY_SEARCHDOWN;
free(data->searchstr);
data->searchstr = xstrdup(argument);
for (; np != 0; np--)
window_copy_search_down(wp, 1);
window_copy_search_down(wp);
}
if (strcmp(command, "search-backward-incremental") == 0) {
prefix = *argument++;
@@ -883,7 +894,7 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
data->searchtype = WINDOW_COPY_SEARCHUP;
free(data->searchstr);
data->searchstr = xstrdup(argument);
if (!window_copy_search_up(wp, 1)) {
if (!window_copy_search_up(wp)) {
window_copy_clear_marks(wp);
redraw = 1;
}
@@ -891,7 +902,7 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
data->searchtype = WINDOW_COPY_SEARCHDOWN;
free(data->searchstr);
data->searchstr = xstrdup(argument);
if (!window_copy_search_down(wp, 1)) {
if (!window_copy_search_down(wp)) {
window_copy_clear_marks(wp);
redraw = 1;
}
@@ -917,7 +928,7 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
data->searchtype = WINDOW_COPY_SEARCHDOWN;
free(data->searchstr);
data->searchstr = xstrdup(argument);
if (!window_copy_search_down(wp, 1)) {
if (!window_copy_search_down(wp)) {
window_copy_clear_marks(wp);
redraw = 1;
}
@@ -925,7 +936,7 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
data->searchtype = WINDOW_COPY_SEARCHUP;
free(data->searchstr);
data->searchstr = xstrdup(argument);
if (!window_copy_search_up(wp, 1)) {
if (!window_copy_search_up(wp)) {
window_copy_clear_marks(wp);
redraw = 1;
}
@@ -955,18 +966,22 @@ window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py)
data->cx = px;
gap = gd->sy / 4;
if (py < gd->sy) {
offset = 0;
data->cy = py;
} else if (py > gd->hsize + gd->sy - gap) {
offset = gd->hsize;
data->cy = py - gd->hsize;
} else {
offset = py + gap - gd->sy;
data->cy = py - offset;
if (py >= gd->hsize - data->oy && py < gd->hsize - data->oy + gd->sy)
data->cy = py - (gd->hsize - data->oy);
else {
gap = gd->sy / 4;
if (py < gd->sy) {
offset = 0;
data->cy = py;
} else if (py > gd->hsize + gd->sy - gap) {
offset = gd->hsize;
data->cy = py - gd->hsize;
} else {
offset = py + gap - gd->sy;
data->cy = py - offset;
}
data->oy = gd->hsize - offset;
}
data->oy = gd->hsize - offset;
window_copy_update_selection(wp, 1);
window_copy_redraw_screen(wp);
@@ -1128,11 +1143,10 @@ window_copy_search_jump(struct window_pane *wp, struct grid *gd,
/*
* Search in for text searchstr. If direction is 0 then search up, otherwise
* down. If moveflag is 0 then look for string at the current cursor position
* as well.
* down.
*/
static int
window_copy_search(struct window_pane *wp, int direction, int moveflag)
window_copy_search(struct window_pane *wp, int direction)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = data->backing, ss;
@@ -1152,12 +1166,10 @@ window_copy_search(struct window_pane *wp, int direction, int moveflag)
screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", data->searchstr);
screen_write_stop(&ctx);
if (moveflag) {
if (direction)
window_copy_move_right(s, &fx, &fy);
else
window_copy_move_left(s, &fx, &fy);
}
if (direction)
window_copy_move_right(s, &fx, &fy);
else
window_copy_move_left(s, &fx, &fy);
window_copy_clear_selection(wp);
wrapflag = options_get_number(wp->window->options, "wrap-search");
@@ -1243,15 +1255,15 @@ window_copy_clear_marks(struct window_pane *wp)
}
static int
window_copy_search_up(struct window_pane *wp, int moveflag)
window_copy_search_up(struct window_pane *wp)
{
return (window_copy_search(wp, 0, moveflag));
return (window_copy_search(wp, 0));
}
static int
window_copy_search_down(struct window_pane *wp, int moveflag)
window_copy_search_down(struct window_pane *wp)
{
return (window_copy_search(wp, 1, moveflag));
return (window_copy_search(wp, 1));
}
static void
@@ -1418,7 +1430,6 @@ static void
window_copy_start_selection(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
data->selx = data->cx;
data->sely = screen_hsize(data->backing) + data->cy - data->oy;
@@ -1428,8 +1439,7 @@ window_copy_start_selection(struct window_pane *wp)
data->cursordrag = CURSORDRAG_ENDSEL;
s->sel.flag = 1;
window_copy_update_selection(wp, 1);
window_copy_set_selection(wp, 1);
}
static int
@@ -1466,6 +1476,17 @@ window_copy_adjust_selection(struct window_pane *wp, u_int *selx, u_int *sely)
static int
window_copy_update_selection(struct window_pane *wp, int may_redraw)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
return (0);
return (window_copy_set_selection(wp, may_redraw));
}
static int
window_copy_set_selection(struct window_pane *wp, int may_redraw)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
@@ -1474,9 +1495,6 @@ window_copy_update_selection(struct window_pane *wp, int may_redraw)
u_int sx, sy, cy, endsx, endsy;
int startrelpos, endrelpos;
if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE)
return (0);
window_copy_synchronize_cursor(wp);
/* Adjust the selection. */
@@ -1499,7 +1517,8 @@ window_copy_update_selection(struct window_pane *wp, int may_redraw)
/* Set colours and selection. */
style_apply(&gc, oo, "mode-style");
gc.flags |= GRID_FLAG_NOPALETTE;
screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag, &gc);
screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag,
data->modekeys, &gc);
if (data->rectflag && may_redraw) {
/*
@@ -1532,10 +1551,10 @@ window_copy_get_selection(struct window_pane *wp, size_t *len)
char *buf;
size_t off;
u_int i, xx, yy, sx, sy, ex, ey, ey_last;
u_int firstsx, lastex, restex, restsx;
u_int firstsx, lastex, restex, restsx, selx;
int keys;
if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE)
if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE)
return (NULL);
buf = xmalloc(1);
@@ -1583,7 +1602,11 @@ window_copy_get_selection(struct window_pane *wp, size_t *len)
* Need to ignore the column with the cursor in it, which for
* rectangular copy means knowing which side the cursor is on.
*/
if (data->selx < data->cx) {
if (data->cursordrag == CURSORDRAG_ENDSEL)
selx = data->selx;
else
selx = data->endselx;
if (selx < data->cx) {
/* Selection start is on the left. */
if (keys == MODEKEY_EMACS) {
lastex = data->cx;
@@ -1593,12 +1616,12 @@ window_copy_get_selection(struct window_pane *wp, size_t *len)
lastex = data->cx + 1;
restex = data->cx + 1;
}
firstsx = data->selx;
restsx = data->selx;
firstsx = selx;
restsx = selx;
} else {
/* Cursor is on the left. */
lastex = data->selx + 1;
restex = data->selx + 1;
lastex = selx + 1;
restex = selx + 1;
firstsx = data->cx;
restsx = data->cx;
}
@@ -1661,7 +1684,7 @@ window_copy_copy_pipe(struct window_pane *wp, struct session *s,
return;
expanded = format_single(NULL, arg, NULL, s, NULL, wp);
job = job_run(expanded, s, NULL, NULL, NULL, NULL, NULL);
job = job_run(expanded, s, NULL, NULL, NULL, NULL, NULL, JOB_NOWAIT);
bufferevent_write(job->event, buf, len);
free(expanded);
@@ -1735,7 +1758,7 @@ window_copy_copy_line(struct window_pane *wp, char **buf, size_t *off, u_int sy,
* Work out if the line was wrapped at the screen edge and all of it is
* on screen.
*/
gl = &gd->linedata[sy];
gl = grid_get_line(gd, sy);
if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
wrapped = 1;
@@ -1823,7 +1846,7 @@ window_copy_find_length(struct window_pane *wp, u_int py)
* width of the grid, and screen_write_copy treats them as spaces, so
* ignore them here too.
*/
px = s->grid->linedata[py].cellsize;
px = grid_get_line(s->grid, py)->cellsize;
if (px > screen_size_x(s))
px = screen_size_x(s);
while (px > 0) {
@@ -1840,14 +1863,13 @@ window_copy_cursor_start_of_line(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *back_s = data->backing;
struct screen *s = &data->screen;
struct grid *gd = back_s->grid;
u_int py;
if (data->cx == 0 && s->sel.lineflag == LINE_SEL_NONE) {
if (data->cx == 0 && data->lineflag == LINE_SEL_NONE) {
py = screen_hsize(back_s) + data->cy - data->oy;
while (py > 0 &&
gd->linedata[py-1].flags & GRID_LINE_WRAPPED) {
grid_get_line(gd, py - 1)->flags & GRID_LINE_WRAPPED) {
window_copy_cursor_up(wp, 0);
py = screen_hsize(back_s) + data->cy - data->oy;
}
@@ -1885,22 +1907,24 @@ window_copy_cursor_end_of_line(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *back_s = data->backing;
struct screen *s = &data->screen;
struct grid *gd = back_s->grid;
struct grid_line *gl;
u_int px, py;
py = screen_hsize(back_s) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if (data->cx == px && s->sel.lineflag == LINE_SEL_NONE) {
if (data->screen.sel.flag && data->rectflag)
if (data->cx == px && data->lineflag == LINE_SEL_NONE) {
if (data->screen.sel != NULL && data->rectflag)
px = screen_size_x(back_s);
if (gd->linedata[py].flags & GRID_LINE_WRAPPED) {
while (py < gd->sy + gd->hsize &&
gd->linedata[py].flags & GRID_LINE_WRAPPED) {
gl = grid_get_line(gd, py);
if (gl->flags & GRID_LINE_WRAPPED) {
while (py < gd->sy + gd->hsize) {
gl = grid_get_line(gd, py);
if (~gl->flags & GRID_LINE_WRAPPED)
break;
window_copy_cursor_down(wp, 0);
py = screen_hsize(back_s)
+ data->cy - data->oy;
py = screen_hsize(back_s) + data->cy - data->oy;
}
px = window_copy_find_length(wp, py);
}
@@ -1918,13 +1942,13 @@ window_copy_other_end(struct window_pane *wp)
struct screen *s = &data->screen;
u_int selx, sely, cy, yy, hsize;
if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE)
if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
return;
if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT)
s->sel.lineflag = LINE_SEL_RIGHT_LEFT;
else if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT)
s->sel.lineflag = LINE_SEL_LEFT_RIGHT;
if (data->lineflag == LINE_SEL_LEFT_RIGHT)
data->lineflag = LINE_SEL_RIGHT_LEFT;
else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
data->lineflag = LINE_SEL_LEFT_RIGHT;
switch (data->cursordrag) {
case CURSORDRAG_NONE:
@@ -1996,7 +2020,7 @@ window_copy_cursor_right(struct window_pane *wp)
py = screen_hsize(data->backing) + data->cy - data->oy;
yy = screen_hsize(data->backing) + screen_size_y(data->backing) - 1;
if (data->screen.sel.flag && data->rectflag)
if (data->screen.sel != NULL && data->rectflag)
px = screen_size_x(&data->screen);
else
px = window_copy_find_length(wp, py);
@@ -2033,7 +2057,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
data->lastsx = ox;
}
if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
window_copy_other_end(wp);
data->cx = data->lastcx;
@@ -2055,7 +2079,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
}
}
if (!data->screen.sel.flag || !data->rectflag) {
if (data->screen.sel != NULL || !data->rectflag) {
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if ((data->cx >= data->lastsx && data->cx != px) ||
@@ -2063,9 +2087,9 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
window_copy_cursor_end_of_line(wp);
}
if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT)
if (data->lineflag == LINE_SEL_LEFT_RIGHT)
window_copy_cursor_end_of_line(wp);
else if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT)
else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
window_copy_cursor_start_of_line(wp);
}
@@ -2083,7 +2107,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
data->lastsx = ox;
}
if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
window_copy_other_end(wp);
data->cx = data->lastcx;
@@ -2097,7 +2121,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
window_copy_redraw_lines(wp, data->cy - 1, 2);
}
if (!data->screen.sel.flag || !data->rectflag) {
if (data->screen.sel == NULL || !data->rectflag) {
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if ((data->cx >= data->lastsx && data->cx != px) ||
@@ -2105,9 +2129,9 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
window_copy_cursor_end_of_line(wp);
}
if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT)
if (data->lineflag == LINE_SEL_LEFT_RIGHT)
window_copy_cursor_end_of_line(wp);
else if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT)
else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
window_copy_cursor_start_of_line(wp);
}
@@ -2166,14 +2190,14 @@ window_copy_cursor_jump_back(struct window_pane *wp)
}
static void
window_copy_cursor_jump_to(struct window_pane *wp, int jump_again)
window_copy_cursor_jump_to(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *back_s = data->backing;
struct grid_cell gc;
u_int px, py, xx;
px = data->cx + 1 + jump_again;
px = data->cx + 2;
py = screen_hsize(back_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
@@ -2191,7 +2215,7 @@ window_copy_cursor_jump_to(struct window_pane *wp, int jump_again)
}
static void
window_copy_cursor_jump_to_back(struct window_pane *wp, int jump_again)
window_copy_cursor_jump_to_back(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *back_s = data->backing;
@@ -2204,7 +2228,7 @@ window_copy_cursor_jump_to_back(struct window_pane *wp, int jump_again)
if (px > 0)
px--;
if (jump_again && px > 0)
if (px > 0)
px--;
for (;;) {
@@ -2378,7 +2402,7 @@ window_copy_scroll_up(struct window_pane *wp, u_int ny)
window_copy_write_line(wp, &ctx, 1);
if (screen_size_y(s) > 3)
window_copy_write_line(wp, &ctx, screen_size_y(s) - 2);
if (s->sel.flag && screen_size_y(s) > ny)
if (s->sel != NULL && screen_size_y(s) > ny)
window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1);
screen_write_cursormove(&ctx, data->cx, data->cy);
screen_write_stop(&ctx);
@@ -2406,7 +2430,7 @@ window_copy_scroll_down(struct window_pane *wp, u_int ny)
screen_write_cursormove(&ctx, 0, 0);
screen_write_insertline(&ctx, ny, 8);
window_copy_write_lines(wp, &ctx, 0, ny);
if (s->sel.flag && screen_size_y(s) > ny)
if (s->sel != NULL && screen_size_y(s) > ny)
window_copy_write_line(wp, &ctx, ny);
else if (ny == 1) /* nuke position */
window_copy_write_line(wp, &ctx, 1);
@@ -2418,13 +2442,13 @@ void
window_copy_add_formats(struct window_pane *wp, struct format_tree *ft)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
if (wp->mode != &window_copy_mode)
return;
format_add(ft, "selection_present", "%d", s->sel.flag);
format_add(ft, "selection_present", "%d", data->screen.sel != NULL);
format_add(ft, "scroll_position", "%d", data->oy);
format_add(ft, "rectangle_toggle", "%d", data->rectflag);
}
static void

View File

@@ -18,6 +18,7 @@
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
@@ -43,8 +44,10 @@ static void window_tree_key(struct window_pane *,
"#{?#{==:#{window_panes},1}, \"#{pane_title}\",}" \
"," \
"#{session_windows} windows" \
"#{?session_grouped, (group ,}" \
"#{session_group}#{?session_grouped,),}" \
"#{?session_grouped, " \
"(group #{session_group}: " \
"#{session_group_list})," \
"}" \
"#{?session_attached, (attached),}" \
"}" \
"}"
@@ -91,17 +94,23 @@ struct window_tree_modedata {
struct mode_tree_data *data;
char *format;
char *command;
int squash_groups;
struct window_tree_itemdata **item_list;
u_int item_size;
struct client *client;
const char *entered;
struct cmd_find_state fs;
enum window_tree_type type;
int offset;
int left;
int right;
u_int start;
u_int end;
u_int each;
};
static void
@@ -288,7 +297,8 @@ window_tree_build_window(struct session *s, struct winlink *wl, void* modedata,
free(text);
free(name);
wp = TAILQ_FIRST(&wl->window->panes);
if ((wp = TAILQ_FIRST(&wl->window->panes)) == NULL)
goto empty;
if (TAILQ_NEXT(wp, entry) == NULL) {
if (!window_tree_filter_pane(s, wl, wp, filter))
goto empty;
@@ -395,8 +405,11 @@ window_tree_build(void *modedata, u_int sort_type, uint64_t *tag,
{
struct window_tree_modedata *data = modedata;
struct session *s, **l;
struct session_group *sg, *current;
u_int n, i;
current = session_group_contains(data->fs.s);
for (i = 0; i < data->item_size; i++)
window_tree_free_item(data->item_list[i]);
free(data->item_list);
@@ -406,6 +419,12 @@ window_tree_build(void *modedata, u_int sort_type, uint64_t *tag,
l = NULL;
n = 0;
RB_FOREACH(s, sessions, &sessions) {
if (data->squash_groups &&
(sg = session_group_contains(s)) != NULL) {
if ((sg == current && s != data->fs.s) ||
(sg != current && s != TAILQ_FIRST(&sg->sessions)))
continue;
}
l = xreallocarray(l, n + 1, sizeof *l);
l[n++] = s;
}
@@ -434,11 +453,36 @@ window_tree_build(void *modedata, u_int sort_type, uint64_t *tag,
*tag = (uint64_t)data->fs.wl;
break;
case WINDOW_TREE_PANE:
*tag = (uint64_t)data->fs.wp;
if (window_count_panes(data->fs.wl->window) == 1)
*tag = (uint64_t)data->fs.wl;
else
*tag = (uint64_t)data->fs.wp;
break;
}
}
static void
window_tree_draw_label(struct screen_write_ctx *ctx, u_int px, u_int py,
u_int sx, u_int sy, const struct grid_cell *gc, const char *label)
{
size_t len;
u_int ox, oy;
len = strlen(label);
if (sx == 0 || sy == 1 || len > sx)
return;
ox = (sx - len + 1) / 2;
oy = (sy + 1) / 2;
if (ox > 1 && ox + len < sx - 1 && sy >= 3) {
screen_write_cursormove(ctx, px + ox - 1, py + oy - 1);
screen_write_box(ctx, len + 2, 3);
}
screen_write_cursormove(ctx, px + ox, py + oy);
screen_write_puts(ctx, gc, "%s", label);
}
static void
window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
struct screen_write_ctx *ctx, u_int sx, u_int sy)
@@ -446,12 +490,12 @@ window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
struct options *oo = s->options;
struct winlink *wl;
struct window *w;
u_int cx = ctx->s->cx, cy = ctx->s->cy;
u_int loop, total, visible, each, width, offset;
u_int current, start, end, remaining, i;
struct grid_cell gc;
int colour, active_colour, left, right;
char *label;
size_t len;
total = winlink_count(&s->windows);
@@ -509,17 +553,25 @@ window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
return;
if (left) {
screen_write_cursormove(ctx, 2, 0);
data->left = cx + 2;
screen_write_cursormove(ctx, cx + 2, cy);
screen_write_vline(ctx, sy, 0, 0);
screen_write_cursormove(ctx, 0, sy / 2);
screen_write_cursormove(ctx, cx, cy + sy / 2);
screen_write_puts(ctx, &grid_default_cell, "<");
}
} else
data->left = -1;
if (right) {
screen_write_cursormove(ctx, sx - 3, 0);
data->right = cx + sx - 3;
screen_write_cursormove(ctx, cx + sx - 3, cy);
screen_write_vline(ctx, sy, 0, 0);
screen_write_cursormove(ctx, sx - 1, sy / 2);
screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2);
screen_write_puts(ctx, &grid_default_cell, ">");
}
} else
data->right = -1;
data->start = start;
data->end = end;
data->each = each;
i = loop = 0;
RB_FOREACH(wl, winlinks, &s->windows) {
@@ -545,20 +597,18 @@ window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
else
width = each - 1;
screen_write_cursormove(ctx, offset, 0);
screen_write_cursormove(ctx, cx + offset, cy);
screen_write_preview(ctx, &w->active->base, width, sy);
xasprintf(&label, " %u:%s ", wl->idx, w->name);
if (strlen(label) > width)
xasprintf(&label, " %u ", wl->idx);
len = strlen(label) / 2;
screen_write_cursormove(ctx, offset + (each / 2) - len, sy / 2);
if (len < width)
screen_write_puts(ctx, &gc, "%s", label);
window_tree_draw_label(ctx, cx + offset, cy, width, sy, &gc,
label);
free(label);
if (loop != end - 1) {
screen_write_cursormove(ctx, offset + width, 0);
screen_write_cursormove(ctx, cx + offset + width, cy);
screen_write_vline(ctx, sy, 0, 0);
}
loop++;
@@ -573,12 +623,12 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
{
struct options *oo = s->options;
struct window_pane *wp;
u_int cx = ctx->s->cx, cy = ctx->s->cy;
u_int loop, total, visible, each, width, offset;
u_int current, start, end, remaining, i;
struct grid_cell gc;
int colour, active_colour, left, right;
int colour, active_colour, left, right, pane_idx;
char *label;
size_t len;
total = window_count_panes(w);
@@ -636,17 +686,25 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
return;
if (left) {
screen_write_cursormove(ctx, 2, 0);
data->left = cx + 2;
screen_write_cursormove(ctx, cx + 2, cy);
screen_write_vline(ctx, sy, 0, 0);
screen_write_cursormove(ctx, 0, sy / 2);
screen_write_cursormove(ctx, cx, cy + sy / 2);
screen_write_puts(ctx, &grid_default_cell, "<");
}
} else
data->left = -1;
if (right) {
screen_write_cursormove(ctx, sx - 3, 0);
data->right = cx + sx - 3;
screen_write_cursormove(ctx, cx + sx - 3, cy);
screen_write_vline(ctx, sy, 0, 0);
screen_write_cursormove(ctx, sx - 1, sy / 2);
screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2);
screen_write_puts(ctx, &grid_default_cell, ">");
}
} else
data->right = -1;
data->start = start;
data->end = end;
data->each = each;
i = loop = 0;
TAILQ_FOREACH(wp, &w->panes, entry) {
@@ -671,18 +729,18 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
else
width = each - 1;
screen_write_cursormove(ctx, offset, 0);
screen_write_cursormove(ctx, cx + offset, cy);
screen_write_preview(ctx, &wp->base, width, sy);
xasprintf(&label, " %u ", loop);
len = strlen(label) / 2;
screen_write_cursormove(ctx, offset + (each / 2) - len, sy / 2);
if (len < width)
screen_write_puts(ctx, &gc, "%s", label);
if (window_pane_index(wp, &pane_idx) != 0)
pane_idx = loop;
xasprintf(&label, " %u ", pane_idx);
window_tree_draw_label(ctx, cx + offset, cy, each, sy, &gc,
label);
free(label);
if (loop != end - 1) {
screen_write_cursormove(ctx, offset + width, 0);
screen_write_cursormove(ctx, cx + offset + width, cy);
screen_write_vline(ctx, sy, 0, 0);
}
loop++;
@@ -691,39 +749,32 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
}
}
static struct screen *
window_tree_draw(void *modedata, void *itemdata, u_int sx, u_int sy)
static void
window_tree_draw(void *modedata, void *itemdata, struct screen_write_ctx *ctx,
u_int sx, u_int sy)
{
struct window_tree_itemdata *item = itemdata;
struct session *sp;
struct winlink *wlp;
struct window_pane *wp;
static struct screen s;
struct screen_write_ctx ctx;
window_tree_pull_item(item, &sp, &wlp, &wp);
if (wp == NULL)
return (NULL);
screen_init(&s, sx, sy, 0);
screen_write_start(&ctx, NULL, &s);
return;
switch (item->type) {
case WINDOW_TREE_NONE:
return (0);
break;
case WINDOW_TREE_SESSION:
window_tree_draw_session(modedata, sp, &ctx, sx, sy);
window_tree_draw_session(modedata, sp, ctx, sx, sy);
break;
case WINDOW_TREE_WINDOW:
window_tree_draw_window(modedata, sp, wlp->window, &ctx, sx, sy);
window_tree_draw_window(modedata, sp, wlp->window, ctx, sx, sy);
break;
case WINDOW_TREE_PANE:
screen_write_preview(&ctx, &wp->base, sx, sy);
screen_write_preview(ctx, &wp->base, sx, sy);
break;
}
screen_write_stop(&ctx);
return (&s);
}
static int
@@ -787,10 +838,12 @@ window_tree_init(struct window_pane *wp, struct cmd_find_state *fs,
data->command = xstrdup(WINDOW_TREE_DEFAULT_COMMAND);
else
data->command = xstrdup(args->argv[0]);
data->squash_groups = !args_has(args, 'G');
data->data = mode_tree_start(wp, args, window_tree_build,
window_tree_draw, window_tree_search, data, window_tree_sort_list,
nitems(window_tree_sort_list), &s);
mode_tree_zoom(data->data, args);
mode_tree_build(data->data);
mode_tree_draw(data->data);
@@ -808,8 +861,6 @@ window_tree_destroy(struct window_tree_modedata *data)
if (--data->references != 0)
return;
mode_tree_free(data->data);
for (i = 0; i < data->item_size; i++)
window_tree_free_item(data->item_list[i]);
free(data->item_list);
@@ -829,6 +880,7 @@ window_tree_free(struct window_pane *wp)
return;
data->dead = 1;
mode_tree_free(data->data);
window_tree_destroy(data);
}
@@ -879,7 +931,8 @@ window_tree_get_target(struct window_tree_itemdata *item,
}
static void
window_tree_command_each(void* modedata, void* itemdata, __unused key_code key)
window_tree_command_each(void* modedata, void* itemdata, struct client *c,
__unused key_code key)
{
struct window_tree_modedata *data = modedata;
struct window_tree_itemdata *item = itemdata;
@@ -888,7 +941,7 @@ window_tree_command_each(void* modedata, void* itemdata, __unused key_code key)
name = window_tree_get_target(item, &fs);
if (name != NULL)
mode_tree_run_command(data->client, &fs, data->entered, name);
mode_tree_run_command(c, &fs, data->entered, name);
free(name);
}
@@ -912,16 +965,12 @@ window_tree_command_callback(struct client *c, void *modedata, const char *s,
{
struct window_tree_modedata *data = modedata;
if (data->dead)
if (s == NULL || *s == '\0' || data->dead)
return (0);
data->client = c;
data->entered = s;
mode_tree_each_tagged(data->data, window_tree_command_each, KEYC_NONE,
1);
data->client = NULL;
mode_tree_each_tagged(data->data, window_tree_command_each, c,
KEYC_NONE, 1);
data->entered = NULL;
data->references++;
@@ -938,21 +987,160 @@ window_tree_command_free(void *modedata)
window_tree_destroy(data);
}
static void
window_tree_kill_each(__unused void* modedata, void* itemdata,
__unused struct client *c, __unused key_code key)
{
struct window_tree_itemdata *item = itemdata;
struct session *s;
struct winlink *wl;
struct window_pane *wp;
window_tree_pull_item(item, &s, &wl, &wp);
switch (item->type) {
case WINDOW_TREE_NONE:
break;
case WINDOW_TREE_SESSION:
if (s != NULL) {
server_destroy_session(s);
session_destroy(s, __func__);
}
break;
case WINDOW_TREE_WINDOW:
if (wl != NULL)
server_kill_window(wl->window);
break;
case WINDOW_TREE_PANE:
if (wp != NULL)
server_kill_pane(wp);
break;
}
}
static int
window_tree_kill_current_callback(struct client *c, void *modedata,
const char *s, __unused int done)
{
struct window_tree_modedata *data = modedata;
struct mode_tree_data *mtd = data->data;
if (s == NULL || *s == '\0' || data->dead)
return (0);
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
return (0);
window_tree_kill_each(data, mode_tree_get_current(mtd), c, KEYC_NONE);
data->references++;
cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
return (0);
}
static int
window_tree_kill_tagged_callback(struct client *c, void *modedata,
const char *s, __unused int done)
{
struct window_tree_modedata *data = modedata;
struct mode_tree_data *mtd = data->data;
if (s == NULL || *s == '\0' || data->dead)
return (0);
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
return (0);
mode_tree_each_tagged(mtd, window_tree_kill_each, c, KEYC_NONE, 1);
data->references++;
cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
return (0);
}
static key_code
window_tree_mouse(struct window_tree_modedata *data, key_code key, u_int x,
struct window_tree_itemdata *item)
{
struct session *s;
struct winlink *wl;
struct window_pane *wp;
u_int loop;
if (key != KEYC_MOUSEDOWN1_PANE)
return (KEYC_NONE);
if (data->left != -1 && x <= (u_int)data->left)
return ('<');
if (data->right != -1 && x >= (u_int)data->right)
return ('>');
if (data->left != -1)
x -= data->left;
else if (x != 0)
x--;
if (x == 0 || data->end == 0)
x = 0;
else {
x = x / data->each;
if (data->start + x >= data->end)
x = data->end - 1;
}
window_tree_pull_item(item, &s, &wl, &wp);
if (item->type == WINDOW_TREE_SESSION) {
if (s == NULL)
return (KEYC_NONE);
mode_tree_expand_current(data->data);
loop = 0;
RB_FOREACH(wl, winlinks, &s->windows) {
if (loop == data->start + x)
break;
loop++;
}
if (wl != NULL)
mode_tree_set_current(data->data, (uint64_t)wl);
return ('\r');
}
if (item->type == WINDOW_TREE_WINDOW) {
if (wl == NULL)
return (KEYC_NONE);
mode_tree_expand_current(data->data);
loop = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
if (loop == data->start + x)
break;
loop++;
}
if (wp != NULL)
mode_tree_set_current(data->data, (uint64_t)wp);
return ('\r');
}
return (KEYC_NONE);
}
static void
window_tree_key(struct window_pane *wp, struct client *c,
__unused struct session *s, key_code key, struct mouse_event *m)
{
struct window_tree_modedata *data = wp->modedata;
struct window_tree_itemdata *item;
char *command, *name, *prompt;
struct window_tree_itemdata *item, *new_item;
char *name, *prompt = NULL;
struct cmd_find_state fs;
int finished;
u_int tagged;
u_int tagged, x, y, idx;
struct session *ns;
struct winlink *nwl;
struct window_pane *nwp;
item = mode_tree_get_current(data->data);
finished = mode_tree_key(data->data, c, &key, m);
if (item != mode_tree_get_current(data->data))
finished = mode_tree_key(data->data, c, &key, m, &x, &y);
if (item != (new_item = mode_tree_get_current(data->data))) {
item = new_item;
data->offset = 0;
}
if (KEYC_IS_MOUSE(key))
key = window_tree_mouse(data, key, x, item);
switch (key) {
case '<':
data->offset--;
@@ -960,6 +1148,46 @@ window_tree_key(struct window_pane *wp, struct client *c,
case '>':
data->offset++;
break;
case 'x':
window_tree_pull_item(item, &ns, &nwl, &nwp);
switch (item->type) {
case WINDOW_TREE_NONE:
break;
case WINDOW_TREE_SESSION:
if (ns == NULL)
break;
xasprintf(&prompt, "Kill session %s? ", ns->name);
break;
case WINDOW_TREE_WINDOW:
if (nwl == NULL)
break;
xasprintf(&prompt, "Kill window %u? ", nwl->idx);
break;
case WINDOW_TREE_PANE:
if (nwp == NULL || window_pane_index(nwp, &idx) != 0)
break;
xasprintf(&prompt, "Kill pane %u? ", idx);
break;
}
if (prompt == NULL)
break;
data->references++;
status_prompt_set(c, prompt, "",
window_tree_kill_current_callback, window_tree_command_free,
data, PROMPT_SINGLE|PROMPT_NOFORMAT);
free(prompt);
break;
case 'X':
tagged = mode_tree_count_tagged(data->data);
if (tagged == 0)
break;
xasprintf(&prompt, "Kill %u tagged? ", tagged);
data->references++;
status_prompt_set(c, prompt, "",
window_tree_kill_tagged_callback, window_tree_command_free,
data, PROMPT_SINGLE|PROMPT_NOFORMAT);
free(prompt);
break;
case ':':
tagged = mode_tree_count_tagged(data->data);
if (tagged != 0)
@@ -973,14 +1201,12 @@ window_tree_key(struct window_pane *wp, struct client *c,
break;
case '\r':
item = mode_tree_get_current(data->data);
command = xstrdup(data->command);
name = window_tree_get_target(item, &fs);
window_pane_reset_mode(wp);
if (name != NULL)
mode_tree_run_command(c, NULL, command, name);
mode_tree_run_command(c, NULL, data->command, name);
finished = 1;
free(name);
free(command);
return;
break;
}
if (finished)
window_pane_reset_mode(wp);

View File

@@ -339,7 +339,7 @@ window_create_spawn(const char *name, int argc, char **argv, const char *path,
struct window_pane *wp;
w = window_create(sx, sy);
wp = window_add_pane(w, NULL, 0, hlimit);
wp = window_add_pane(w, NULL, 0, 0, hlimit);
layout_init(w, wp);
if (window_pane_spawn(wp, argc, argv, path, shell, cwd,
@@ -608,7 +608,7 @@ window_unzoom(struct window *w)
struct window_pane *
window_add_pane(struct window *w, struct window_pane *other, int before,
u_int hlimit)
int full_size, u_int hlimit)
{
struct window_pane *wp;
@@ -621,10 +621,16 @@ window_add_pane(struct window *w, struct window_pane *other, int before,
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
} else if (before) {
log_debug("%s: @%u before %%%u", __func__, w->id, wp->id);
TAILQ_INSERT_BEFORE(other, wp, entry);
if (full_size)
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
else
TAILQ_INSERT_BEFORE(other, wp, entry);
} else {
log_debug("%s: @%u after %%%u", __func__, w->id, wp->id);
TAILQ_INSERT_AFTER(&w->panes, other, wp, entry);
if (full_size)
TAILQ_INSERT_TAIL(&w->panes, wp, entry);
else
TAILQ_INSERT_AFTER(&w->panes, other, wp, entry);
}
return (wp);
}
@@ -912,12 +918,14 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
free((void *)wp->cwd);
wp->cwd = xstrdup(cwd);
}
wp->flags &= ~(PANE_STATUSREADY|PANE_STATUSDRAWN);
cmd = cmd_stringify_argv(wp->argc, wp->argv);
log_debug("spawn: %s -- %s", wp->shell, cmd);
for (i = 0; i < wp->argc; i++)
log_debug("spawn: argv[%d] = %s", i, wp->argv[i]);
environ_log(env, "spawn: ");
log_debug("%s: shell=%s", __func__, wp->shell);
log_debug("%s: cmd=%s", __func__, cmd);
log_debug("%s: cwd=%s", __func__, cwd);
cmd_log_argv(wp->argc, wp->argv, __func__);
environ_log(env, "%s: environment ", __func__);
memset(&ws, 0, sizeof ws);
ws.ws_col = screen_size_x(&wp->base);
@@ -938,10 +946,13 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
proc_clear_signals(server_proc, 1);
sigprocmask(SIG_SETMASK, &oldset, NULL);
if (chdir(wp->cwd) != 0) {
if ((home = find_home()) == NULL || chdir(home) != 0)
chdir("/");
}
cwd = NULL;
if (chdir(wp->cwd) == 0)
cwd = wp->cwd;
else if ((home = find_home()) != NULL && chdir(home) == 0)
cwd = home;
else
chdir("/");
if (tcgetattr(STDIN_FILENO, &tio2) != 0)
fatal("tcgetattr failed");
@@ -959,6 +970,8 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
if (path != NULL)
environ_set(env, "PATH", "%s", path);
if (cwd != NULL)
environ_set(env, "PWD", "%s", cwd);
environ_set(env, "TMUX_PANE", "%%%u", wp->id);
environ_push(env);
@@ -993,6 +1006,8 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
execl(wp->shell, argv0, (char *)NULL);
fatal("execl failed");
}
log_debug("%s: master=%s", __func__, ttyname(wp->fd));
log_debug("%s: slave=%s", __func__, wp->tty);
#ifdef HAVE_UTEMPTER
xsnprintf(s, sizeof s, "tmux(%lu).%%%u", (long) getpid(), wp->id);