mirror of
https://github.com/tmux/tmux.git
synced 2026-09-16 18:21:58 +00:00
Compare commits
1434 Commits
3.6
...
command_pa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c624de9f3c | ||
|
|
9b0ad73a4b | ||
|
|
bd8218e85d | ||
|
|
8f3101d820 | ||
|
|
77309c07b0 | ||
|
|
c8e889694d | ||
|
|
b402687fcd | ||
|
|
0530a7d89a | ||
|
|
6bdb9ba54c | ||
|
|
f2bfd611e2 | ||
|
|
9c1d5a080b | ||
|
|
b28244e2fe | ||
|
|
8b3834c34f | ||
|
|
af3e4d2e5b | ||
|
|
c552d1bf16 | ||
|
|
6a1ecdcce3 | ||
|
|
39357c829c | ||
|
|
40381bdcd9 | ||
|
|
7bad4f7722 | ||
|
|
65e811570b | ||
|
|
dd31900f80 | ||
|
|
013ada58c8 | ||
|
|
78dad45f3b | ||
|
|
52b452948f | ||
|
|
267746603a | ||
|
|
b26b240613 | ||
|
|
8e48c889dd | ||
|
|
f4445a310a | ||
|
|
4157b64754 | ||
|
|
0d2aafe7b7 | ||
|
|
6f4c9b32af | ||
|
|
eb77a75ab7 | ||
|
|
0851650c6b | ||
|
|
1459c90a7f | ||
|
|
af29c080ba | ||
|
|
50ea32162f | ||
|
|
2d5328a860 | ||
|
|
e5db7598b2 | ||
|
|
dc78d8f9ea | ||
|
|
022b8451e3 | ||
|
|
5b54c7d41a | ||
|
|
f94036b2b0 | ||
|
|
7d358208b9 | ||
|
|
c8ff8ea96f | ||
|
|
402d366bba | ||
|
|
41e701ad84 | ||
|
|
f763f94556 | ||
|
|
c9f5ecb4b5 | ||
|
|
7792a74c76 | ||
|
|
4cabc2ae85 | ||
|
|
995b395795 | ||
|
|
3d44f75d09 | ||
|
|
c1f947a3c5 | ||
|
|
696a16cca2 | ||
|
|
936bb6e7cd | ||
|
|
8dfa903346 | ||
|
|
95a7170709 | ||
|
|
554c4bbde4 | ||
|
|
ac23f21a2c | ||
|
|
6696151008 | ||
|
|
50d0348b64 | ||
|
|
cf3ab3cad9 | ||
|
|
bf7bbba7ea | ||
|
|
b28b1b7b9a | ||
|
|
8499d8007e | ||
|
|
e5a2058c7c | ||
|
|
e94fcd96f9 | ||
|
|
c5017e6da8 | ||
|
|
0169f9e18c | ||
|
|
b170c19274 | ||
|
|
22b3679752 | ||
|
|
4714f478fe | ||
|
|
72c5037f06 | ||
|
|
6238793ad7 | ||
|
|
da641e4e8d | ||
|
|
19a085a672 | ||
|
|
f672a0f677 | ||
|
|
db194ced5b | ||
|
|
11ed661e2c | ||
|
|
b2de803871 | ||
|
|
30abbe36a8 | ||
|
|
62044f02df | ||
|
|
a18d4e0067 | ||
|
|
0f241b7447 | ||
|
|
efaa1fe31c | ||
|
|
1729bb8e8a | ||
|
|
9fdd04ae61 | ||
|
|
87a8bda023 | ||
|
|
d384557b63 | ||
|
|
534a4f81fc | ||
|
|
a0d3585c6c | ||
|
|
ec34ff52cc | ||
|
|
0ac8138ce3 | ||
|
|
c41cad4c5f | ||
|
|
f466d6289e | ||
|
|
c6f62289b0 | ||
|
|
851c5a933d | ||
|
|
10048f6579 | ||
|
|
a598b2a910 | ||
|
|
2ec1038ffd | ||
|
|
cbb1da66c3 | ||
|
|
35ab660042 | ||
|
|
40a485db9c | ||
|
|
641e75e6e2 | ||
|
|
2e394bef11 | ||
|
|
4a9dbac435 | ||
|
|
d60dbcf91c | ||
|
|
bd483a63cf | ||
|
|
d5dc0ba855 | ||
|
|
e56a042153 | ||
|
|
1995b5559d | ||
|
|
fe384e06bc | ||
|
|
0198ee9e51 | ||
|
|
72e705cbd6 | ||
|
|
d5afb67a81 | ||
|
|
3894397b07 | ||
|
|
36381f0884 | ||
|
|
5cd1976a4a | ||
|
|
c9ae3f6a02 | ||
|
|
d2322d0114 | ||
|
|
7a431ec7b9 | ||
|
|
114aa68082 | ||
|
|
f07a76d959 | ||
|
|
ca0d77855f | ||
|
|
cd3f577c85 | ||
|
|
9228f97d7d | ||
|
|
6db5175e4e | ||
|
|
fba5ece05c | ||
|
|
01a775a46c | ||
|
|
4918360ea1 | ||
|
|
433a5cf580 | ||
|
|
fc9270c943 | ||
|
|
fa8c5789a6 | ||
|
|
cce56fa19b | ||
|
|
31dccb6bc9 | ||
|
|
8dfb7d0294 | ||
|
|
265fb7b4ea | ||
|
|
fa38b36f1f | ||
|
|
44b8a40b8c | ||
|
|
5cd5df1d33 | ||
|
|
415d265728 | ||
|
|
b114b7e089 | ||
|
|
f85b015dc1 | ||
|
|
d6c37ce314 | ||
|
|
c6d02d54d1 | ||
|
|
6f41dac898 | ||
|
|
899b4b5471 | ||
|
|
5534f1ac32 | ||
|
|
9f2c535909 | ||
|
|
7cc0c11cde | ||
|
|
31fe1ded5d | ||
|
|
6a13d61b48 | ||
|
|
9c402fa7b7 | ||
|
|
a115ca68a5 | ||
|
|
a5ad1914b8 | ||
|
|
3c1b2969a8 | ||
|
|
e2a5ea2e78 | ||
|
|
27ab96b284 | ||
|
|
00b5323d5c | ||
|
|
f751d3f2c1 | ||
|
|
9b97dadc01 | ||
|
|
8ca512b502 | ||
|
|
5269e14113 | ||
|
|
ff214cf9a1 | ||
|
|
d57d75deee | ||
|
|
008a3f3f8b | ||
|
|
4cc45aa719 | ||
|
|
0255981a54 | ||
|
|
0a92ff6e76 | ||
|
|
3068ae06a8 | ||
|
|
55169f1275 | ||
|
|
afb95f3134 | ||
|
|
10726b1b27 | ||
|
|
0768795ce3 | ||
|
|
29bf7fe2f7 | ||
|
|
47f210a9d2 | ||
|
|
e361982acf | ||
|
|
cc7eea1e34 | ||
|
|
0ec289545a | ||
|
|
190b5bde16 | ||
|
|
8862390c34 | ||
|
|
c59230316b | ||
|
|
a2f3bdb601 | ||
|
|
689e6f8fac | ||
|
|
6049298140 | ||
|
|
a10ed3233c | ||
|
|
7568c19276 | ||
|
|
fb88172346 | ||
|
|
26bdd2b511 | ||
|
|
38feebb5d2 | ||
|
|
7428b0431a | ||
|
|
7277712ca8 | ||
|
|
2a5389416a | ||
|
|
597d04ed78 | ||
|
|
9625fe3b5f | ||
|
|
09a2ea190d | ||
|
|
18fc547b82 | ||
|
|
242239b561 | ||
|
|
bd4ac02994 | ||
|
|
0868435e81 | ||
|
|
7abb9af062 | ||
|
|
a57b0f1282 | ||
|
|
c59db2d007 | ||
|
|
8bf2a4e807 | ||
|
|
2848a12562 | ||
|
|
92f090c0c0 | ||
|
|
9d583cad5a | ||
|
|
abd2f3a9a5 | ||
|
|
3e61e63851 | ||
|
|
4d1cf62fb4 | ||
|
|
0e2576a842 | ||
|
|
418ddada23 | ||
|
|
16064a410e | ||
|
|
8aaae25e56 | ||
|
|
5ed5e3606e | ||
|
|
d13b69ece4 | ||
|
|
88a91b9f83 | ||
|
|
efcfc55535 | ||
|
|
afb3e954bf | ||
|
|
aea209b142 | ||
|
|
8dd0e2129e | ||
|
|
8024fab1f2 | ||
|
|
c750c014b2 | ||
|
|
1b179582e6 | ||
|
|
c766669b3b | ||
|
|
c45bf2e84d | ||
|
|
6ef280fb0f | ||
|
|
2a2bce3dd4 | ||
|
|
cad1c81c71 | ||
|
|
496bfdce38 | ||
|
|
bacc7952ad | ||
|
|
377a810168 | ||
|
|
481d48b53b | ||
|
|
6dacc024f0 | ||
|
|
1ce000062a | ||
|
|
5bd10a8c2a | ||
|
|
2711780dff | ||
|
|
a177d0f590 | ||
|
|
a8ad3c7d43 | ||
|
|
d5b1f3ad89 | ||
|
|
b46684427f | ||
|
|
5cd43626ef | ||
|
|
43092f8d54 | ||
|
|
fcc7366e86 | ||
|
|
e50545f451 | ||
|
|
1d0d22df22 | ||
|
|
f07ea87e20 | ||
|
|
824a07290f | ||
|
|
fba51526af | ||
|
|
15746a1bc7 | ||
|
|
edefce8eb5 | ||
|
|
d98635e1bd | ||
|
|
9459c7ca64 | ||
|
|
75c874c55b | ||
|
|
10b2bb76f6 | ||
|
|
cbb97b961c | ||
|
|
5350da0be3 | ||
|
|
5d2b6542b6 | ||
|
|
1c7ed8d9ad | ||
|
|
8f2d25024a | ||
|
|
66e6b2e1c3 | ||
|
|
4e586ed0b8 | ||
|
|
ad6832e697 | ||
|
|
11496010c0 | ||
|
|
e54785ddd6 | ||
|
|
6546fa0982 | ||
|
|
1a02c9957c | ||
|
|
145f8ef173 | ||
|
|
34a11db6ca | ||
|
|
d705471aa5 | ||
|
|
67f71fe4ac | ||
|
|
a10252dad2 | ||
|
|
c9d6d4b601 | ||
|
|
f88189cd59 | ||
|
|
c39d69f961 | ||
|
|
cf110d9d1d | ||
|
|
ed4245a74d | ||
|
|
09d5977263 | ||
|
|
42b3ea0d74 | ||
|
|
2a75cc2236 | ||
|
|
df6ed20271 | ||
|
|
de7fdbe85d | ||
|
|
37da97fbe6 | ||
|
|
f0f59bc2fd | ||
|
|
9c65d349e8 | ||
|
|
2818069d5f | ||
|
|
2f0308ea4d | ||
|
|
b1c347ee0c | ||
|
|
fba5083b58 | ||
|
|
9c9477ae76 | ||
|
|
e4dbd11d44 | ||
|
|
c3e38b317d | ||
|
|
f75ef5ca1c | ||
|
|
8fbbde7035 | ||
|
|
2dc05ae328 | ||
|
|
511fe53846 | ||
|
|
658e087f7a | ||
|
|
dba85ee32e | ||
|
|
b91086a5c8 | ||
|
|
4cd39ee33e | ||
|
|
e3ef97b6b4 | ||
|
|
e00a1a3e26 | ||
|
|
006cce5e4d | ||
|
|
4a06a1f296 | ||
|
|
fe1b877410 | ||
|
|
2b091d91d3 | ||
|
|
6d227a8479 | ||
|
|
447d804a3a | ||
|
|
687c6b9cc0 | ||
|
|
b2e2fe824d | ||
|
|
baf71480d0 | ||
|
|
1f6385e7bb | ||
|
|
309119f659 | ||
|
|
884ae3f8da | ||
|
|
d9b953d5c6 | ||
|
|
e0014bbc7c | ||
|
|
d03de4986a | ||
|
|
6126988781 | ||
|
|
25e2e1d671 | ||
|
|
e6eb26518b | ||
|
|
8b2bc1a384 | ||
|
|
0ce72059e6 | ||
|
|
f80d3f6123 | ||
|
|
0925c9846b | ||
|
|
3612a9a605 | ||
|
|
cc8e0f2f67 | ||
|
|
a662981f10 | ||
|
|
d77c9dc6aa | ||
|
|
8ac3fcedca | ||
|
|
ea236c12a6 | ||
|
|
a53a0aa0b5 | ||
|
|
5e3db12c07 | ||
|
|
4f981a2506 | ||
|
|
b602dc57b1 | ||
|
|
330bedfb47 | ||
|
|
3ff24a8eb4 | ||
|
|
28a1231100 | ||
|
|
6fd9987632 | ||
|
|
8f27092756 | ||
|
|
e7fef1fd64 | ||
|
|
7f2b0ae16e | ||
|
|
0cc84b8cae | ||
|
|
1329473a4b | ||
|
|
84cc6541f3 | ||
|
|
512255b9a7 | ||
|
|
f3c6b4f1a3 | ||
|
|
ad662d3926 | ||
|
|
d29aa12117 | ||
|
|
ca6dd6ca92 | ||
|
|
1508bec957 | ||
|
|
bcc73e0db4 | ||
|
|
ec31f4566d | ||
|
|
dfb2a9404f | ||
|
|
7ac0d6bead | ||
|
|
041b6a6bc7 | ||
|
|
3a6c717bb8 | ||
|
|
ec74c46d1e | ||
|
|
161dbaf1ce | ||
|
|
e242da168b | ||
|
|
dea309cf8d | ||
|
|
ee3944c8fd | ||
|
|
1fefb80445 | ||
|
|
f92cb43ce4 | ||
|
|
cd2ca9ec34 | ||
|
|
e37a2e54ab | ||
|
|
53f3b05001 | ||
|
|
8e76565c9c | ||
|
|
c830710e11 | ||
|
|
0f354ac4e0 | ||
|
|
e601bfb362 | ||
|
|
dac6514147 | ||
|
|
ac723bf2df | ||
|
|
c8f6b54da7 | ||
|
|
27c26e88e5 | ||
|
|
e77d9ad043 | ||
|
|
25060c3fa5 | ||
|
|
28c2005a2a | ||
|
|
db115c6b97 | ||
|
|
7b02cb6d03 | ||
|
|
8beb17df0d | ||
|
|
76b693aa81 | ||
|
|
d53f1b7458 | ||
|
|
7188391a22 | ||
|
|
869170abd6 | ||
|
|
1ea574e4ca | ||
|
|
af35bcb64f | ||
|
|
55ce48c152 | ||
|
|
ff09914327 | ||
|
|
3946e24eff | ||
|
|
b07424224b | ||
|
|
d33d5b7de8 | ||
|
|
9180356b13 | ||
|
|
20ef19b42f | ||
|
|
1117caaf09 | ||
|
|
e6505947ec | ||
|
|
79b83600af | ||
|
|
85e3ca5ae2 | ||
|
|
e11af53819 | ||
|
|
0593cbeb84 | ||
|
|
d565fd3b54 | ||
|
|
699b18414d | ||
|
|
eb82e8527a | ||
|
|
069201dd1a | ||
|
|
37e4b3cdb6 | ||
|
|
501e8da925 | ||
|
|
6a6822b906 | ||
|
|
e7c1361a10 | ||
|
|
913e503296 | ||
|
|
2c0f06782d | ||
|
|
fcce73af42 | ||
|
|
2b2963859b | ||
|
|
327c05307a | ||
|
|
3f065cf789 | ||
|
|
dc1693d5a1 | ||
|
|
29b2b7a875 | ||
|
|
34af038fcc | ||
|
|
d422621eaa | ||
|
|
f556e4b6fc | ||
|
|
2fdcb64a79 | ||
|
|
468c2942a3 | ||
|
|
df56ba95fc | ||
|
|
bd39ce0d49 | ||
|
|
5068e4149a | ||
|
|
de024e04d7 | ||
|
|
7ff972773a | ||
|
|
9634538106 | ||
|
|
5356c62ead | ||
|
|
9af9226ff9 | ||
|
|
92028ed6e2 | ||
|
|
7a8f8f5a74 | ||
|
|
415885ecb9 | ||
|
|
7b833d07d9 | ||
|
|
2f58804717 | ||
|
|
b05f0abeeb | ||
|
|
2d75f79217 | ||
|
|
898a91903a | ||
|
|
6e9574c715 | ||
|
|
2efd2d4970 | ||
|
|
219dc7f99e | ||
|
|
1b4015226f | ||
|
|
0f77d9b30a | ||
|
|
a19b961427 | ||
|
|
646637f53a | ||
|
|
21e91cfa00 | ||
|
|
f32b65ac4a | ||
|
|
a02e25ba01 | ||
|
|
c5a7309966 | ||
|
|
1d7021130d | ||
|
|
8e03310afe | ||
|
|
31b0b0c99e | ||
|
|
90492aa26d | ||
|
|
d512a65d4c | ||
|
|
4378a17fbe | ||
|
|
8e8fa3d10b | ||
|
|
b5a6d9bcab | ||
|
|
929e6b5c9b | ||
|
|
44304bf9e4 | ||
|
|
e03a937c71 | ||
|
|
820067826a | ||
|
|
4a6ac5e209 | ||
|
|
29f0939a5b | ||
|
|
310d0e93d6 | ||
|
|
6967f54774 | ||
|
|
8d67f8af24 | ||
|
|
0148ad5820 | ||
|
|
e1fc6b31ee | ||
|
|
47b90a4e03 | ||
|
|
cceca5a158 | ||
|
|
88932f2d09 | ||
|
|
89a59d4df5 | ||
|
|
fa2c9f4551 | ||
|
|
f645f0abe8 | ||
|
|
f0ec51e78d | ||
|
|
2b8c3c1362 | ||
|
|
dbb70b394e | ||
|
|
abcf8dca3a | ||
|
|
351bef58a3 | ||
|
|
8d877421cf | ||
|
|
f592be00fa | ||
|
|
352b1173c8 | ||
|
|
bf0eee35f9 | ||
|
|
228c9c9277 | ||
|
|
fa2a3b679a | ||
|
|
5838b45315 | ||
|
|
d718b0eac7 | ||
|
|
93039db58c | ||
|
|
6ebef7450a | ||
|
|
a82e09d1a3 | ||
|
|
63a8af0e15 | ||
|
|
6b9b6c0b0b | ||
|
|
390805d8b9 | ||
|
|
70f37ef815 | ||
|
|
b6fca55447 | ||
|
|
e22c56f02f | ||
|
|
01c86e64b7 | ||
|
|
ca81c36383 | ||
|
|
a9a04c7bc0 | ||
|
|
0a81f4d742 | ||
|
|
0ad5035457 | ||
|
|
d626cef6de | ||
|
|
7713cbebd2 | ||
|
|
baf16f0419 | ||
|
|
9dcc2da348 | ||
|
|
f50a38de23 | ||
|
|
3ef51a469c | ||
|
|
d5688bf165 | ||
|
|
8dc9e24c74 | ||
|
|
735bbf9da7 | ||
|
|
6ad86ebdf1 | ||
|
|
3d58e04c93 | ||
|
|
9fb67a2cdd | ||
|
|
d9d12c5c43 | ||
|
|
728ad24d4a | ||
|
|
5b37471db7 | ||
|
|
c41e98be3c | ||
|
|
35f429cb6d | ||
|
|
85fc0ea57c | ||
|
|
6f588402c3 | ||
|
|
fada35478b | ||
|
|
bd5d7a8a7a | ||
|
|
8108356978 | ||
|
|
5e32eddb8c | ||
|
|
1818b6ac16 | ||
|
|
e802909de0 | ||
|
|
824ef37f5f | ||
|
|
cfa755a961 | ||
|
|
565db46a19 | ||
|
|
82683707bc | ||
|
|
87aa44f4bc | ||
|
|
e9396e59d9 | ||
|
|
3ee24bde1a | ||
|
|
4f7bef5083 | ||
|
|
80b1f20e7d | ||
|
|
111a11ac6a | ||
|
|
002ac977f8 | ||
|
|
724f85d275 | ||
|
|
1853c220a4 | ||
|
|
115002748b | ||
|
|
b3fa1c0b9c | ||
|
|
e69950a9ca | ||
|
|
db8f9b4c52 | ||
|
|
4951eac7fa | ||
|
|
185ae656e0 | ||
|
|
ab3da84e34 | ||
|
|
41b4743eba | ||
|
|
1e9a16a748 | ||
|
|
74a5069c0a | ||
|
|
bce30eefd3 | ||
|
|
1302bbde07 | ||
|
|
e935342702 | ||
|
|
6d56dd9e7b | ||
|
|
8d470017bc | ||
|
|
8ca7434d65 | ||
|
|
a9cff084c0 | ||
|
|
928c7a9771 | ||
|
|
eda7e563d0 | ||
|
|
186f51b7ee | ||
|
|
298b35c8a9 | ||
|
|
7a1cc1d443 | ||
|
|
fefb926291 | ||
|
|
36273fde4f | ||
|
|
8ac29f6587 | ||
|
|
db9b54f232 | ||
|
|
54f5c82500 | ||
|
|
b3bb8bbd9f | ||
|
|
c92720e3b0 | ||
|
|
08500f844d | ||
|
|
a97912a4f8 | ||
|
|
91ea9e4beb | ||
|
|
b30f5f82e0 | ||
|
|
d4eca8d586 | ||
|
|
8908f50524 | ||
|
|
eb2e26f4cd | ||
|
|
9569c57fc3 | ||
|
|
90fc51542f | ||
|
|
b48e2ea8e9 | ||
|
|
f8674cc993 | ||
|
|
f7cd6ab547 | ||
|
|
843adbf454 | ||
|
|
abefc3f705 | ||
|
|
401793eba6 | ||
|
|
fcfa0b6db4 | ||
|
|
5f7a4b0f52 | ||
|
|
bcc2b7ad1e | ||
|
|
9e8cf6f0e2 | ||
|
|
b8a62979ac | ||
|
|
45f4000017 | ||
|
|
572b32766c | ||
|
|
e6ad44c8a3 | ||
|
|
96cd98560b | ||
|
|
ac23a47a5f | ||
|
|
22b6ad6fce | ||
|
|
dddd7b44c8 | ||
|
|
25c874c489 | ||
|
|
0e418b62d2 | ||
|
|
a97f643bd3 | ||
|
|
78a2145a47 | ||
|
|
dbe50934b1 | ||
|
|
efe2453eac | ||
|
|
543d104f85 | ||
|
|
e06207c914 | ||
|
|
166267c87a | ||
|
|
91e0737b8a | ||
|
|
65a032b205 | ||
|
|
80c7dcdbd7 | ||
|
|
bcd54d12d8 | ||
|
|
726e19a886 | ||
|
|
95719e342d | ||
|
|
132a63d1da | ||
|
|
822f700b15 | ||
|
|
5df51a06f5 | ||
|
|
ad74c5ed7f | ||
|
|
d5284be91d | ||
|
|
c29b41e527 | ||
|
|
4e612612dc | ||
|
|
705fbf92ee | ||
|
|
2dc704abb6 | ||
|
|
6c2ef75681 | ||
|
|
96899dc527 | ||
|
|
b0db912bde | ||
|
|
7cd33ce0dd | ||
|
|
e0dd40f812 | ||
|
|
79f0f97495 | ||
|
|
5e0b0a2aa3 | ||
|
|
e24969b422 | ||
|
|
dd02989e88 | ||
|
|
7383c04205 | ||
|
|
84291b021f | ||
|
|
91e30f4f22 | ||
|
|
5be44a6c03 | ||
|
|
8cc20a5618 | ||
|
|
81f88f8517 | ||
|
|
4eafb27b89 | ||
|
|
4fc4644652 | ||
|
|
c0f213b056 | ||
|
|
a2915cfdef | ||
|
|
4b921f3821 | ||
|
|
575f84ce0f | ||
|
|
1048796003 | ||
|
|
973c4ab569 | ||
|
|
445677dc00 | ||
|
|
da27529d91 | ||
|
|
f59921ce18 | ||
|
|
ec3c65122f | ||
|
|
9fa5e81836 | ||
|
|
4869a5165a | ||
|
|
30e84ff687 | ||
|
|
73fd01c986 | ||
|
|
3729af7438 | ||
|
|
1e5aef279a | ||
|
|
19db019e0c | ||
|
|
666464d7a9 | ||
|
|
391f880d07 | ||
|
|
d0bf3bf06d | ||
|
|
edb027e910 | ||
|
|
dd2fef6673 | ||
|
|
8e79c4a03d | ||
|
|
19d70a85fc | ||
|
|
f5e9bcc1fc | ||
|
|
3631f81236 | ||
|
|
1e6f64d5c9 | ||
|
|
569e9d932f | ||
|
|
6a7f4a1894 | ||
|
|
8c55a388cd | ||
|
|
d176f1f89c | ||
|
|
2d0845860a | ||
|
|
5ae701aab5 | ||
|
|
0d016195ac | ||
|
|
fc2de240d2 | ||
|
|
7c1ef6a387 | ||
|
|
0b538b6f2a | ||
|
|
3d26aa0dfb | ||
|
|
51d037e881 | ||
|
|
e5fb88fb85 | ||
|
|
787234eff4 | ||
|
|
6b1219b370 | ||
|
|
ed48555bdd | ||
|
|
ba9faae8b6 | ||
|
|
6935dee976 | ||
|
|
12473bb6d3 | ||
|
|
280a962328 | ||
|
|
37633ff957 | ||
|
|
1c2fc8c3c4 | ||
|
|
d3adecd819 | ||
|
|
0a71af41be | ||
|
|
8fb484da37 | ||
|
|
6e6a434a2d | ||
|
|
f23ea9e977 | ||
|
|
55cfdbaa3f | ||
|
|
1b5a07a740 | ||
|
|
00b0af7021 | ||
|
|
89027bd22c | ||
|
|
ff8de1a106 | ||
|
|
0c5e6770df | ||
|
|
c2ad33a04c | ||
|
|
c0a5e10313 | ||
|
|
1c394b8606 | ||
|
|
505d557fbb | ||
|
|
a63e429d22 | ||
|
|
de086f9848 | ||
|
|
6643acb375 | ||
|
|
c25cb107bb | ||
|
|
9dba08ac8b | ||
|
|
3ec115115d | ||
|
|
09c91b8931 | ||
|
|
de1940065a | ||
|
|
748ef8b2ae | ||
|
|
2ecf0a9053 | ||
|
|
b82048eb18 | ||
|
|
9d58ff97fe | ||
|
|
51b787e449 | ||
|
|
7654b518f1 | ||
|
|
e7f414416f | ||
|
|
52877c9af1 | ||
|
|
265f22be49 | ||
|
|
2a26c738bd | ||
|
|
02b37b3c69 | ||
|
|
d8370864f3 | ||
|
|
ffe48f00e3 | ||
|
|
49dff83a00 | ||
|
|
95afd7549c | ||
|
|
06ee890db3 | ||
|
|
e680420c89 | ||
|
|
357ee692bd | ||
|
|
347baa6f3e | ||
|
|
cc922de758 | ||
|
|
dbca906ef5 | ||
|
|
1fc4dcb76f | ||
|
|
dcd7d1c8e6 | ||
|
|
72e768ef14 | ||
|
|
047f61aad6 | ||
|
|
d04b1ffca5 | ||
|
|
c93e2f2332 | ||
|
|
e7c29d0ceb | ||
|
|
6c46358be8 | ||
|
|
b0ff8af9ac | ||
|
|
624db256c6 | ||
|
|
cfb15d158e | ||
|
|
34c7881ddd | ||
|
|
f06d930445 | ||
|
|
b29f5688bd | ||
|
|
333e2f266a | ||
|
|
af94399473 | ||
|
|
3d35f26031 | ||
|
|
b1c72ec48c | ||
|
|
8dee34459b | ||
|
|
e7f649e40a | ||
|
|
5843fbc6ee | ||
|
|
c8eca3a69d | ||
|
|
12fdcea8b8 | ||
|
|
035447b08f | ||
|
|
55b2e748e7 | ||
|
|
3246331876 | ||
|
|
6d9fbb0e97 | ||
|
|
14fc4a06a6 | ||
|
|
cba4ba9cdc | ||
|
|
937d99150c | ||
|
|
0a6c846091 | ||
|
|
c6b8ad6e7e | ||
|
|
d92a479d2f | ||
|
|
f242182840 | ||
|
|
f5871369cc | ||
|
|
b1b184cdb8 | ||
|
|
1a6de01210 | ||
|
|
1dd2589a42 | ||
|
|
3485e1c089 | ||
|
|
6f7965e4f1 | ||
|
|
1ba8fa6f04 | ||
|
|
6eb67fcc5f | ||
|
|
3b8e25fef4 | ||
|
|
64e83caf04 | ||
|
|
a8abea8247 | ||
|
|
d4defd943a | ||
|
|
eafd2bed5d | ||
|
|
6549765930 | ||
|
|
6cb2233cd2 | ||
|
|
9ad75e1dc3 | ||
|
|
762e503978 | ||
|
|
bec0f7d975 | ||
|
|
4b772fd783 | ||
|
|
c809aea278 | ||
|
|
1596f9c9f5 | ||
|
|
2f28d9a168 | ||
|
|
baac29debc | ||
|
|
2c4df765c5 | ||
|
|
1d026b921c | ||
|
|
fcbb6a7384 | ||
|
|
bdc01f44de | ||
|
|
d2c23773ff | ||
|
|
38dc3ec0da | ||
|
|
c03acc9572 | ||
|
|
30e133d36a | ||
|
|
0890df5891 | ||
|
|
d223a49d18 | ||
|
|
26285e183e | ||
|
|
408e9f1481 | ||
|
|
7c8344930b | ||
|
|
482e254a49 | ||
|
|
eb65331403 | ||
|
|
9031f59f7b | ||
|
|
2d9afa6348 | ||
|
|
bae5c14941 | ||
|
|
9cf8de099c | ||
|
|
b86bd1fcd0 | ||
|
|
c156e597dc | ||
|
|
bb750b07bc | ||
|
|
0e6fe5a097 | ||
|
|
13de7cafb2 | ||
|
|
057b688fc7 | ||
|
|
45bb3e7ffc | ||
|
|
8ced9c332c | ||
|
|
9fcd5ce03d | ||
|
|
a41e6e2ed2 | ||
|
|
e54855ef88 | ||
|
|
7a18fa281d | ||
|
|
f98aaf544d | ||
|
|
78afc24736 | ||
|
|
83e4534387 | ||
|
|
aed9018807 | ||
|
|
97b5f22a70 | ||
|
|
748dab2f38 | ||
|
|
3c11129b04 | ||
|
|
6e0e343f23 | ||
|
|
cc27470cb6 | ||
|
|
fb527fa7db | ||
|
|
87976aa48e | ||
|
|
863923472a | ||
|
|
778a15b64a | ||
|
|
5eaf5570c4 | ||
|
|
cbe0f1f1e9 | ||
|
|
97472e374f | ||
|
|
7a28aa0dd7 | ||
|
|
b1054ac227 | ||
|
|
1618b98533 | ||
|
|
5b6ed54817 | ||
|
|
d23a2b7e97 | ||
|
|
ab92b27226 | ||
|
|
eb6efdf17a | ||
|
|
b182791052 | ||
|
|
97a7f174ce | ||
|
|
654758e622 | ||
|
|
c8887a5846 | ||
|
|
56779f9542 | ||
|
|
f474838e22 | ||
|
|
19393e13db | ||
|
|
301b10de8d | ||
|
|
aa2fd3a151 | ||
|
|
2dd604949f | ||
|
|
ec481ac82a | ||
|
|
7afee45635 | ||
|
|
385d18590a | ||
|
|
bc9252f6e3 | ||
|
|
6c76f2a7c7 | ||
|
|
bf187170b1 | ||
|
|
14837e8e0f | ||
|
|
b44cdf1006 | ||
|
|
5d73f90133 | ||
|
|
34a6a9d3a1 | ||
|
|
f92a4e611b | ||
|
|
b3deb9ec86 | ||
|
|
dabaae1534 | ||
|
|
a92653f2b2 | ||
|
|
29cdab650b | ||
|
|
574a4eccb5 | ||
|
|
42c0641daf | ||
|
|
11b6e7844a | ||
|
|
f1b67152af | ||
|
|
b6be437bab | ||
|
|
3d7f421809 | ||
|
|
fa6d33f742 | ||
|
|
dc22196394 | ||
|
|
3ea458b9dc | ||
|
|
86128a7f06 | ||
|
|
de60750506 | ||
|
|
f07ac3068b | ||
|
|
7ec94fda08 | ||
|
|
9231c80cd8 | ||
|
|
4702e58ee5 | ||
|
|
2719549cf2 | ||
|
|
cd26f29fb8 | ||
|
|
9c350af582 | ||
|
|
c019b3dad9 | ||
|
|
8cb4aabb8b | ||
|
|
7ad8b3366d | ||
|
|
c6c8f77bc0 | ||
|
|
f415a70c0b | ||
|
|
da31d94c2a | ||
|
|
5c0db5a293 | ||
|
|
d533d7c97c | ||
|
|
490802099d | ||
|
|
34dd42dc7f | ||
|
|
b374868750 | ||
|
|
538688486e | ||
|
|
27111bd76d | ||
|
|
4a3f380fd2 | ||
|
|
cc87db74c7 | ||
|
|
4ec7e66e90 | ||
|
|
a42e425d44 | ||
|
|
2179c3e420 | ||
|
|
d5c9196348 | ||
|
|
aa1f0653e9 | ||
|
|
97156f3382 | ||
|
|
8771b6051f | ||
|
|
27c58c764d | ||
|
|
1564584ba9 | ||
|
|
fd10db5a62 | ||
|
|
6f683da2e9 | ||
|
|
a6a06c5aa6 | ||
|
|
4d1ab1ba2a | ||
|
|
d7a6a8e35b | ||
|
|
bf2e078ecf | ||
|
|
a25ce36925 | ||
|
|
a0f4038df2 | ||
|
|
7d8c1ae295 | ||
|
|
df7c2e605b | ||
|
|
ea51cdb3f2 | ||
|
|
fe986a52d6 | ||
|
|
34fd261a4f | ||
|
|
bbd4768bb6 | ||
|
|
cb237b5193 | ||
|
|
85d72b9952 | ||
|
|
a04c33c42d | ||
|
|
529afada82 | ||
|
|
a532f4868f | ||
|
|
e1d37c37b5 | ||
|
|
ae5e0e8c05 | ||
|
|
bbea0ef439 | ||
|
|
a134c43f4d | ||
|
|
e0ebae4481 | ||
|
|
1fbc51b69f | ||
|
|
42f3e7f7ce | ||
|
|
e163cbacec | ||
|
|
0ec6870902 | ||
|
|
55421ede70 | ||
|
|
3acd247f5d | ||
|
|
59151704b4 | ||
|
|
343ee5ece1 | ||
|
|
0256ee77c2 | ||
|
|
72f5415fc8 | ||
|
|
ef8e9df02f | ||
|
|
306ee0eddb | ||
|
|
3d9e6bf454 | ||
|
|
0fc6cb4099 | ||
|
|
5744021ac9 | ||
|
|
54be05e5e4 | ||
|
|
c9e22ab67b | ||
|
|
4063f968c6 | ||
|
|
8388c53a47 | ||
|
|
3a72f3beb8 | ||
|
|
35709a30ee | ||
|
|
f9a683cf39 | ||
|
|
d7a2b52da8 | ||
|
|
f43adc364a | ||
|
|
6beebbe074 | ||
|
|
019f8eb278 | ||
|
|
580f9ced08 | ||
|
|
642cc15b99 | ||
|
|
cfeade6055 | ||
|
|
390207cdf1 | ||
|
|
c97b2b95e6 | ||
|
|
a3bf632276 | ||
|
|
5368ee32dd | ||
|
|
e89f02bd8f | ||
|
|
ae6a749d3a | ||
|
|
0759030ee8 | ||
|
|
35f4c8b333 | ||
|
|
97ac32f536 | ||
|
|
2f3ef88dbf | ||
|
|
9725a0b9bf | ||
|
|
b368e89bea | ||
|
|
3269833caa | ||
|
|
922f7d1645 | ||
|
|
a1873fef61 | ||
|
|
0eff3b6b97 | ||
|
|
f6557d1ea2 | ||
|
|
718eb2b4cc | ||
|
|
cd6c01e42b | ||
|
|
0b773dd792 | ||
|
|
b68ab3a4b4 | ||
|
|
d8c9f88fe7 | ||
|
|
f6398ba51c | ||
|
|
67dbf01eeb | ||
|
|
7c71064b64 | ||
|
|
4d91ff8d8d | ||
|
|
e778f7f805 | ||
|
|
3bff7a9e62 | ||
|
|
705c2ac55a | ||
|
|
3f3d65e452 | ||
|
|
a9721ea268 | ||
|
|
d876bb8cf3 | ||
|
|
b17dcc6773 | ||
|
|
e3ee2b327b | ||
|
|
74b91d6dec | ||
|
|
7a3b7ae812 | ||
|
|
35df67c893 | ||
|
|
290303e64f | ||
|
|
f8ab7a5158 | ||
|
|
decaaf4b55 | ||
|
|
b9d228c72f | ||
|
|
11e48c3fa9 | ||
|
|
c40302a7ff | ||
|
|
964e22cfef | ||
|
|
55db69e3b2 | ||
|
|
99b08ecde5 | ||
|
|
4ecf93487e | ||
|
|
f066933418 | ||
|
|
481d8299ca | ||
|
|
3b19536df9 | ||
|
|
2212157b61 | ||
|
|
7ebeed1ae7 | ||
|
|
7769097915 | ||
|
|
595b0cb471 | ||
|
|
c50c3629e6 | ||
|
|
887b6f4da7 | ||
|
|
9c6cfcd2e9 | ||
|
|
658c7d1dbf | ||
|
|
ecfe6e4e7a | ||
|
|
f53c4e7525 | ||
|
|
3690c64e88 | ||
|
|
c489f786b6 | ||
|
|
5c40cc43b2 | ||
|
|
54ae850322 | ||
|
|
a9b9d2f6d3 | ||
|
|
f00f92e7e3 | ||
|
|
bbe26df83d | ||
|
|
daf9988b3a | ||
|
|
ee67452772 | ||
|
|
781364f7f9 | ||
|
|
84d016ddcf | ||
|
|
0241fdac1a | ||
|
|
d62bae442b | ||
|
|
9cc8947a43 | ||
|
|
bff68fa079 | ||
|
|
00c59041ea | ||
|
|
a77b81f0e5 | ||
|
|
f839588c69 | ||
|
|
27d719cd4d | ||
|
|
7a15dc6772 | ||
|
|
bfd7f468ce | ||
|
|
cca1e77f95 | ||
|
|
cc81287665 | ||
|
|
ca95153b45 | ||
|
|
eb330a6df6 | ||
|
|
b498979d4d | ||
|
|
f047b3f8e7 | ||
|
|
c67787536b | ||
|
|
3cfc96d4de | ||
|
|
91a8c66537 | ||
|
|
5c3a4746b7 | ||
|
|
b8e0004ff2 | ||
|
|
4e0aabd8a7 | ||
|
|
143a177055 | ||
|
|
d45a9cad8c | ||
|
|
285a3b7522 | ||
|
|
d4255818c4 | ||
|
|
f714f3ee78 | ||
|
|
36bc351557 | ||
|
|
d5ee330d20 | ||
|
|
634e9d6213 | ||
|
|
9aa9a92f72 | ||
|
|
8c51c0fdbd | ||
|
|
24e4a545a2 | ||
|
|
c5fb5e8bb0 | ||
|
|
b8434182c9 | ||
|
|
e1f942f26a | ||
|
|
91b85efabb | ||
|
|
0057905ca0 | ||
|
|
572e26deb8 | ||
|
|
caff9a135f | ||
|
|
ce24b92758 | ||
|
|
f5a086ac98 | ||
|
|
cb1025e0e8 | ||
|
|
a46cdb8bbc | ||
|
|
34e2035bad | ||
|
|
a9ba7b8ecb | ||
|
|
962d647993 | ||
|
|
a8520ba59e | ||
|
|
f12d7b4e67 | ||
|
|
bbea6e6375 | ||
|
|
b24b8424b1 | ||
|
|
35bd1a4c02 | ||
|
|
818352c3cd | ||
|
|
742efe989f | ||
|
|
4cea1c7189 | ||
|
|
18ddda48d2 | ||
|
|
5651519f5d | ||
|
|
281e8ff766 | ||
|
|
dbc0710bc9 | ||
|
|
8f28f31b78 | ||
|
|
3f651d9fa9 | ||
|
|
18fced7e7f | ||
|
|
f1f0158741 | ||
|
|
3d6c542e34 | ||
|
|
c3036116de | ||
|
|
9e3653a612 | ||
|
|
27a00d1bfd | ||
|
|
800837ff3f | ||
|
|
bfbfb6dbf3 | ||
|
|
8fb1b1d412 | ||
|
|
af98467d0d | ||
|
|
f9d50d580c | ||
|
|
496805476e | ||
|
|
962e565591 | ||
|
|
862625a4bf | ||
|
|
2d8aade74b | ||
|
|
2aad2cfc53 | ||
|
|
ad94405dac | ||
|
|
518fcf7e03 | ||
|
|
1fbd00e1e8 | ||
|
|
cae229cadc | ||
|
|
9d3dcdbc38 | ||
|
|
d52fabce72 | ||
|
|
637d4c3083 | ||
|
|
1e96d9a87f | ||
|
|
49172b256c | ||
|
|
9a94f48663 | ||
|
|
2e9c6c2586 | ||
|
|
92522473b0 | ||
|
|
56200ca044 | ||
|
|
524f283cc6 | ||
|
|
a2acf0f7cf | ||
|
|
d85f1b942d | ||
|
|
8da41bdc2b | ||
|
|
4a926e489b | ||
|
|
746dd91e86 | ||
|
|
763dec881a | ||
|
|
2a5715fad5 | ||
|
|
ec58272b95 | ||
|
|
f90d3af403 | ||
|
|
c2659401b0 | ||
|
|
9840d4a4a3 | ||
|
|
fc6d94a9f8 | ||
|
|
61a7be0eab | ||
|
|
e4a439aa0c | ||
|
|
b844cafb9c | ||
|
|
1d9522a7a6 | ||
|
|
ffe80579df | ||
|
|
bcd17cf99a | ||
|
|
bc15723f7f | ||
|
|
7a0cc03532 | ||
|
|
d36f6783c7 | ||
|
|
d339ab51eb | ||
|
|
fee70031f6 | ||
|
|
303edb71bd | ||
|
|
314f0ae964 | ||
|
|
0835980ef1 | ||
|
|
baf55e4616 | ||
|
|
dd62c2f946 | ||
|
|
638cecf43c | ||
|
|
a97cfe513d | ||
|
|
9de3c0495f | ||
|
|
67e6f8245b | ||
|
|
31c93c483a | ||
|
|
86d4d5689c | ||
|
|
663e82bc19 | ||
|
|
51109e3f72 | ||
|
|
a11363e9e7 | ||
|
|
cc57913d7a | ||
|
|
057d169492 | ||
|
|
e5a2a25faf | ||
|
|
147521b757 | ||
|
|
31d77e29b6 | ||
|
|
4b0ff07bcb | ||
|
|
0ee18d4421 | ||
|
|
21da45e5c3 | ||
|
|
d5ed967f58 | ||
|
|
42dafcc62a | ||
|
|
cad282ebb7 | ||
|
|
7f2ac9c871 | ||
|
|
87aaff5fae | ||
|
|
b411010237 | ||
|
|
d2d86ac360 | ||
|
|
a827725a8d | ||
|
|
3badbc50e0 | ||
|
|
cd60de443e | ||
|
|
95e40115a2 | ||
|
|
66c324d7ef | ||
|
|
6b056eb53f | ||
|
|
8cfdcf9a6f | ||
|
|
0917cd7010 | ||
|
|
bdd78ce38e | ||
|
|
7497db6e37 | ||
|
|
43e2942fa0 | ||
|
|
51bc2f3b76 | ||
|
|
483683c197 | ||
|
|
c95d341220 | ||
|
|
be2c6f3b5e | ||
|
|
2d5736f297 | ||
|
|
1a51193899 | ||
|
|
8b51abef08 | ||
|
|
cbb49e8c84 | ||
|
|
dc12da4573 | ||
|
|
7af58f74b0 | ||
|
|
1081876810 | ||
|
|
2ff0dd3fef | ||
|
|
a30fc69f86 | ||
|
|
022b5cf193 | ||
|
|
7620c03b72 | ||
|
|
6324dae114 | ||
|
|
e0237c6b8c | ||
|
|
1cf3e02bfb | ||
|
|
6ca5405db9 | ||
|
|
fa31f2a3eb | ||
|
|
d03f9454b9 | ||
|
|
616fb1cbcf | ||
|
|
b7d1e6257c | ||
|
|
b101ffaed6 | ||
|
|
f7dad4f38f | ||
|
|
b88c08f860 | ||
|
|
cc47f4d1c2 | ||
|
|
3909d7e92f | ||
|
|
d70edfa0a0 | ||
|
|
d22ab85b84 | ||
|
|
5c30b145df | ||
|
|
e446cba6a9 | ||
|
|
8a0b4e0d8c | ||
|
|
02a9cdff57 | ||
|
|
f516f8a1d4 | ||
|
|
bef4865d91 | ||
|
|
fd62f419ac | ||
|
|
7fa6f320ed | ||
|
|
19f3fb131b | ||
|
|
551e8fcd24 | ||
|
|
04b4952f0e | ||
|
|
0d77555c97 | ||
|
|
67141fb4bb | ||
|
|
2efa762c2b | ||
|
|
6c2dd193cf | ||
|
|
881bec958e | ||
|
|
8899c751e5 | ||
|
|
d0caf0a322 | ||
|
|
91b5108eae | ||
|
|
2c7f73f9c4 | ||
|
|
5310592967 | ||
|
|
41bddae907 | ||
|
|
d9d2b2f1ee | ||
|
|
1e208abd93 | ||
|
|
d32088b58a | ||
|
|
6d37cc94a7 | ||
|
|
55722a7ed7 | ||
|
|
d2fa20a390 | ||
|
|
bcbad050d4 | ||
|
|
27698c468b | ||
|
|
49bb43047d | ||
|
|
77ce0a837d | ||
|
|
bbbfa8f360 | ||
|
|
d781d2eaa1 | ||
|
|
f33b14bda6 | ||
|
|
e603549563 | ||
|
|
e80e0c761a | ||
|
|
9e804202b6 | ||
|
|
0c678b1e1a | ||
|
|
4cb29deb93 | ||
|
|
5413953d30 | ||
|
|
50e51b4513 | ||
|
|
ee0647aba6 | ||
|
|
35be70f1f0 | ||
|
|
dbb23d2182 | ||
|
|
478eaea982 | ||
|
|
0800e51d41 | ||
|
|
5ff385f8a9 | ||
|
|
5b3c642195 | ||
|
|
bd6e201926 | ||
|
|
08779aa2a3 | ||
|
|
09bd686327 | ||
|
|
9316476a73 | ||
|
|
00946007d8 | ||
|
|
bc47bc7c22 | ||
|
|
dc693601f4 | ||
|
|
f1f9c63cdb | ||
|
|
0cc4f0fd76 | ||
|
|
0dc1b5adfb | ||
|
|
a76e6eca6b | ||
|
|
8c7278b53a | ||
|
|
50a3b4c777 | ||
|
|
3094ca1da5 | ||
|
|
23ad10c849 | ||
|
|
c9fb989a31 | ||
|
|
8356578a54 | ||
|
|
0310404155 | ||
|
|
03f8690f9c | ||
|
|
4cc3de4f84 | ||
|
|
fedd4440f0 | ||
|
|
55cedc24fa | ||
|
|
c9162837a0 | ||
|
|
f218463976 | ||
|
|
1f0c54f7ea | ||
|
|
d3522c328c | ||
|
|
7e50eb0e83 | ||
|
|
5b455abecc | ||
|
|
7d41761e84 | ||
|
|
25f6d8b1e9 | ||
|
|
5a33616e65 | ||
|
|
1cf17b06ae | ||
|
|
aa03706ed0 | ||
|
|
d8794e2b30 | ||
|
|
b7939eb266 | ||
|
|
19b9a34c48 | ||
|
|
f016e08153 | ||
|
|
7b1c503086 | ||
|
|
5865001e4a | ||
|
|
62944da74b | ||
|
|
588013bb44 | ||
|
|
615c27c117 | ||
|
|
3c3d9ce3a9 | ||
|
|
66011fe48b | ||
|
|
d7f59eccaf | ||
|
|
e652213855 | ||
|
|
f70150a663 | ||
|
|
fe52f76913 | ||
|
|
0d9c3c895c | ||
|
|
6525bb7cef | ||
|
|
0790e74f84 | ||
|
|
195a9cfd88 | ||
|
|
ecbf8d76d0 | ||
|
|
818745a605 | ||
|
|
26aacd0e32 | ||
|
|
8e06739e26 | ||
|
|
ab1f2ef71c | ||
|
|
d2e09cb259 | ||
|
|
bf8ea85bd7 | ||
|
|
9c0aeaff40 | ||
|
|
95b4bb51c6 | ||
|
|
1e5f93b7b6 | ||
|
|
b89d46bb00 | ||
|
|
97d61131df | ||
|
|
5721767921 | ||
|
|
a443531280 | ||
|
|
ad083677c5 | ||
|
|
426467856d | ||
|
|
844042744e | ||
|
|
65b3a95be8 | ||
|
|
ca95950148 | ||
|
|
6234d79852 | ||
|
|
a5d8b92012 | ||
|
|
890cfc6dc3 | ||
|
|
0e6fc2e88b | ||
|
|
c8ccd420be | ||
|
|
ff4f6b9066 | ||
|
|
7cffa2de78 | ||
|
|
e2afaaea75 | ||
|
|
75d3974c12 | ||
|
|
583f12ea71 | ||
|
|
3de7a8ad8d | ||
|
|
f6c9052082 | ||
|
|
f226804149 | ||
|
|
cf94486e32 | ||
|
|
035a2f35d4 | ||
|
|
9b7732eac4 | ||
|
|
5f9dac8abc | ||
|
|
ccd4dd7ff2 | ||
|
|
77417b7cbe | ||
|
|
6a7cd79a63 | ||
|
|
baa3b51b3e | ||
|
|
abeba4910c | ||
|
|
356d0aedbd | ||
|
|
45f23f3a59 | ||
|
|
6ef7375ade | ||
|
|
00030aabf7 | ||
|
|
f72832cc08 | ||
|
|
b5c33ca2b7 | ||
|
|
d607399850 | ||
|
|
d005803934 | ||
|
|
a22ec275b4 | ||
|
|
188f963fe0 | ||
|
|
9c5df33325 | ||
|
|
74f60951cc | ||
|
|
54202fcaad | ||
|
|
fe645c5bcc | ||
|
|
86c15d7ae9 | ||
|
|
3c36d5e433 | ||
|
|
1c7e164c22 | ||
|
|
ce7eb22e3a | ||
|
|
739a97140f | ||
|
|
99ed397e9c | ||
|
|
d2c7668bc2 | ||
|
|
7abf3e8bdf | ||
|
|
506b4db762 | ||
|
|
21c27fdcae | ||
|
|
672e89a640 | ||
|
|
4b810ae493 | ||
|
|
52e2a7d990 | ||
|
|
2e5e9c0298 | ||
|
|
afa05ae15e | ||
|
|
f58b8d0d6a | ||
|
|
5c73d3878d | ||
|
|
ef0a7e328c | ||
|
|
cc117b5048 | ||
|
|
faebe7a70a | ||
|
|
01962e25dc | ||
|
|
ff207eb583 | ||
|
|
8e922ab690 | ||
|
|
1a3db6b65e | ||
|
|
987e05ff31 | ||
|
|
2fc123cf4a | ||
|
|
3b57077d01 | ||
|
|
33c1ba1549 | ||
|
|
bd16b22dac | ||
|
|
0929d8ddfa | ||
|
|
9d6c69ebde | ||
|
|
1bcd360dfe | ||
|
|
1f2210a3ce | ||
|
|
2fe1378d3a | ||
|
|
796539c60b | ||
|
|
700936b2ad | ||
|
|
a28dbe3a59 | ||
|
|
820df0f551 | ||
|
|
ee9cf1bbaa | ||
|
|
52917abe21 | ||
|
|
a40f98df0a | ||
|
|
2c78a5aceb | ||
|
|
02a8e3fd34 | ||
|
|
322adfbdde | ||
|
|
194d0a0e25 | ||
|
|
b2d6ebaa10 | ||
|
|
bfecbb0685 | ||
|
|
e4c552f5a5 | ||
|
|
04f32073c0 | ||
|
|
e9afd2bb5e | ||
|
|
55d660a548 | ||
|
|
dfaf47d97c | ||
|
|
640e1a7643 | ||
|
|
2a0b078e15 | ||
|
|
0af04295f3 | ||
|
|
3542bfa5b8 | ||
|
|
e3a54ed0f4 | ||
|
|
ec4b5b52af | ||
|
|
a0dfef3b04 | ||
|
|
6db6a30ab5 | ||
|
|
bfa2f73335 | ||
|
|
1decccace7 | ||
|
|
ee53d49059 | ||
|
|
f949f9a23a | ||
|
|
f0dec832b8 |
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
@@ -63,7 +63,7 @@ tmux -vv -Ltest -f/dev/null new
|
||||
|
||||
Or if you need your configuration:
|
||||
|
||||
~~~base
|
||||
~~~bash
|
||||
tmux kill-server
|
||||
tmux -vv new
|
||||
~~~
|
||||
|
||||
2
.github/README.md
vendored
2
.github/README.md
vendored
@@ -79,7 +79,7 @@ A small example configuration is in `example_tmux.conf`.
|
||||
|
||||
And a bash(1) completion file at:
|
||||
|
||||
https://github.com/scop/bash-completion/blob/main/completions/tmux
|
||||
https://github.com/scop/bash-completion/blob/main/completions-core/tmux.bash
|
||||
|
||||
For debugging, run tmux with `-v` or `-vv` to generate server and client log
|
||||
files in the current directory.
|
||||
|
||||
11
.github/copilot-instructions.md
vendored
Normal file
11
.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
For pull request code reviews in this repository, do not leave any review comments under any circumstances.
|
||||
|
||||
If asked to review a pull request, produce no comments.
|
||||
|
||||
Do not comment on pull requests in this repository.
|
||||
|
||||
For pull request code reviews in this repository, do not leave a pull request overview.
|
||||
|
||||
Do not leave inline review comments.
|
||||
|
||||
If asked to review a pull request, provide no summary, no overview, and no code comments.
|
||||
4
.github/workflows/lock.yml
vendored
4
.github/workflows/lock.yml
vendored
@@ -16,8 +16,10 @@ concurrency:
|
||||
jobs:
|
||||
action:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'tmux/tmux'
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v5
|
||||
- uses: dessant/lock-threads@89ae32b08ed1a541efecbab17912962a5e38981c # v6
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
issue-inactive-days: '30'
|
||||
|
||||
90
.github/workflows/regress.yml
vendored
Normal file
90
.github/workflows/regress.yml
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
name: 'Run Tests'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '33 3 * * *'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: tmux-tests
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
regress:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
if: github.repository == 'tmux/tmux'
|
||||
timeout-minutes: 300
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: ubuntu-24.04-x64
|
||||
runner: ubuntu-24.04
|
||||
make: make
|
||||
configure: --enable-utf8proc --enable-asan
|
||||
#- name: ubuntu-24.04-arm64
|
||||
# runner: ubuntu-24.04-arm
|
||||
# make: make
|
||||
# configure: --enable-utf8proc --enable-asan
|
||||
- name: macos-26-arm64
|
||||
runner: macos-26
|
||||
make: gmake
|
||||
configure: --enable-utf8proc --enable-asan
|
||||
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: dependencies
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
autoconf \
|
||||
automake \
|
||||
bison \
|
||||
build-essential \
|
||||
libevent-dev \
|
||||
libncurses-dev \
|
||||
libutf8proc-dev \
|
||||
pkg-config
|
||||
|
||||
- name: dependencies
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew install \
|
||||
autoconf \
|
||||
automake \
|
||||
bison \
|
||||
libevent \
|
||||
jemalloc \
|
||||
make \
|
||||
ncurses \
|
||||
utf8proc \
|
||||
pkg-config
|
||||
|
||||
- name: build
|
||||
run: |
|
||||
sh autogen.sh
|
||||
./configure ${{ matrix.configure }}
|
||||
${{ matrix.make }} -j"$(getconf _NPROCESSORS_ONLN)"
|
||||
|
||||
- name: test
|
||||
run: |
|
||||
cd regress
|
||||
${{ matrix.make }}
|
||||
|
||||
- name: logs
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: regress-logs-${{ matrix.name }}
|
||||
path: regress/logs/*.log
|
||||
if-no-files-found: ignore
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,6 +7,8 @@
|
||||
*~
|
||||
.deps/
|
||||
.dirstamp
|
||||
.serena/
|
||||
AGENTS.md
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
@@ -19,6 +21,7 @@ configure
|
||||
core
|
||||
etc/
|
||||
fuzz/*-fuzzer
|
||||
regress/logs/
|
||||
tags
|
||||
tmux
|
||||
tmux.1.*
|
||||
|
||||
1
.mailmap
1
.mailmap
@@ -29,6 +29,7 @@ Ted Unangst <tedu@openbsd.org> tedu <tedu>
|
||||
Theo de Raadt <deraadt@openbsd.org> Theo Deraadt <deraadt@openbsd.org>
|
||||
Theo de Raadt <deraadt@openbsd.org> deraadt <deraadt>
|
||||
Thomas Adam <thomas@xteddy.org> Thomas <thomas@xteddy.org>
|
||||
Thomas Adam <thomas@xteddy.org> Thomas Adam <thomas.adam22@gmail.com>
|
||||
Thomas Adam <thomas@xteddy.org> Thomas Adam <thomas.adam@smoothwall.net>
|
||||
Thomas Adam <thomas@xteddy.org> n6tadam <n6tadam@xteddy.org>
|
||||
Tim van der Molen <tim@openbsd.org> tim <tim>
|
||||
|
||||
553
CHANGES
553
CHANGES
@@ -1,3 +1,556 @@
|
||||
CHANGES FROM 3.7c TO 3.8
|
||||
|
||||
* Many improvements to floating panes:
|
||||
|
||||
- new-pane and split-window can now set the title with -T and border lines
|
||||
with -B, and new-pane -W waits for the pane command to exit;
|
||||
|
||||
- dragging with Ctrl now creates a new floating pane;
|
||||
|
||||
- modal panes may be created with new-pane -O; a window can have one modal
|
||||
pane and it prevents interaction with the other panes while it is active.
|
||||
A modal pane is now used for the editor in buffer mode;
|
||||
|
||||
- move-pane and resize-pane can now move and resize floating panes, including
|
||||
mouse dragging;
|
||||
|
||||
- split-window in a floating pane creates a new floating pane that does not
|
||||
overlap the active pane, if possible;
|
||||
|
||||
- break-pane can float a tiled pane, join-pane can tile a floating pane, and
|
||||
swap-pane works with floating panes;
|
||||
|
||||
- choose-tree -h and choose-client -h hide the pane containing the mode, and
|
||||
-k for choose commands kills the pane when the mode exits, which is useful
|
||||
for modes in floating panes;
|
||||
|
||||
- pane-border-status has top-floating and bottom-floating, and there are new
|
||||
default bindings under C-b g for common move and resize operations;
|
||||
|
||||
- floating panes are unzoomed before creation to avoid a crash.
|
||||
|
||||
* Add support for themes and improve default colours:
|
||||
|
||||
- tmux now has builtin light and dark colour themes for terminals with 256 or
|
||||
more colours; a new theme option controls whether tmux detects the terminal
|
||||
theme, uses terminal colours, or forces light or dark (set to terminal for
|
||||
the old colours);
|
||||
|
||||
- styles can use new theme colour names such as themeblack, themewhite and
|
||||
themegreen, and colours in styles are expanded as formats;
|
||||
|
||||
- the terminal's own theme is reported to panes instead of being guessed from
|
||||
the background, and inferred more accurately when theme reporting is not
|
||||
supported (Ayman Bagabas, issue 5343);
|
||||
|
||||
- tree-mode-selection-style has been added, tree mode selection styling now
|
||||
covers the whole line, and built-in modes use improved theme colours.
|
||||
|
||||
* Improvements to customize mode:
|
||||
|
||||
- hooks and environment variables are now shown;
|
||||
|
||||
- e opens the selected value in an editor;
|
||||
|
||||
- C toggles showing only changed items;
|
||||
|
||||
- array item keys can now be changed.
|
||||
|
||||
* Hooks (and control mode notifications) are now handled internally by using
|
||||
events, each of which may carry keys and values as a payload. The control
|
||||
mode subscriptions mechanism has been extended to allow general-purpose
|
||||
"monitors" which check a format every second and trigger a hook when it
|
||||
changes or becomes true:
|
||||
|
||||
- set-hook -B adds a monitor hook using the same subscription syntax as
|
||||
refresh-client -B, and show-hooks -B lists them. -T runs the hook only when
|
||||
the format is true;
|
||||
|
||||
- wait-for -E waits for hooks, notifications or user events, and set-hook -E
|
||||
fires an event immediately;
|
||||
|
||||
- hooks have additional keys available. wait-for -v can be used to see the
|
||||
keys sent with a hook event;
|
||||
|
||||
- new hooks to cover areas including client create and destroy, pane
|
||||
activity, pane mode and prompt changes, pane movement and resizing, session
|
||||
group changes and window creation, close and zoom;
|
||||
|
||||
- OSC 133 escape sequences now trigger events: pane-command-started,
|
||||
pane-command-finished and pane-shell-prompt.
|
||||
|
||||
* Add switch-mode, a fast switcher bound by default to Tab for windows and BTab
|
||||
(S-Tab) for sessions.
|
||||
|
||||
* Pane scrollbars now support auto-hide. This replaces the previous modal
|
||||
behaviour where the pane was resized. With auto-hide, the scrollbar appears
|
||||
while scrolling or while hovered and disappears after pane-scrollbars-timeout
|
||||
(Michael Grant).
|
||||
|
||||
* Extend the fill-character option so both inside and outside the window can be
|
||||
changed.
|
||||
|
||||
* Change set-option and set-hooks to use formats and add a -F flag to each.
|
||||
|
||||
* Add a #{A/count:frames} modifier to show a series of frames as an animation
|
||||
in the status line (issue 5412 from Fernando Daciuk).
|
||||
|
||||
* Change command templates so %% is escaped for single quotes while %1 remains
|
||||
unquoted, preventing single quotes in session or target names from
|
||||
terminating quoted command sections (reported by Aliz Hammond).
|
||||
|
||||
* display-panes is now a mode rather than an overlay, and can be run inside
|
||||
another pane. The -b flag has been removed.
|
||||
|
||||
* Add new-window -E, respawn-pane -E and respawn-window -E as more convenient
|
||||
methods to create an empty pane (rather than using '' for the command).
|
||||
|
||||
* Menus now belong to the window, so appear on all clients.
|
||||
|
||||
* Dragging over an existing copy mode selection now adjusts it (Michael Grant).
|
||||
|
||||
* Rectangle selection in copy mode may extend past the end of the current line
|
||||
to match vi's virtualedit=block behaviour (Mark Kelly, issue 5227).
|
||||
|
||||
* With mode-keys set to vi, scrolling in copy mode now keeps the cursor in the
|
||||
same position relative to the text (Arseniy Simonov, issue 5216).
|
||||
|
||||
* Copy mode no longer exits at the bottom while a selection is in progress
|
||||
(issue 5349).
|
||||
|
||||
* Add style attributes for dimming colours (dim=) and for hyperlinks (link= and
|
||||
nolink) (issues 4842 and 4280 from Moritz Angermann).
|
||||
|
||||
* New format modifiers: O: loops over options, V: loops over environments,
|
||||
the I modifier reports client terminal information, t/d gives a time
|
||||
difference in seconds, c/f and c/b emit colours, and the m operator supports
|
||||
multiple terms and fuzzy matching.
|
||||
|
||||
* Add or improve format variables including client_colours,
|
||||
pane_start_command_list, window_manual_width, window_manual_height,
|
||||
pane_last_output_time, pane_modal_flag and window_modal_pane.
|
||||
|
||||
* Add additional pane sort orders, and a z sort order for choose-tree so
|
||||
floating panes can be sorted by z-index.
|
||||
|
||||
* Add -f filters to kill-pane -a, kill-window -a and kill-session -a (issue
|
||||
4782).
|
||||
|
||||
* Allow server ACLs to use groups as well as users (issue 4917).
|
||||
|
||||
* The mouse option now defaults to on.
|
||||
|
||||
* Fix send-keys -K so keys are inserted in the correct place in the input
|
||||
queue, like keys from key bindings (issue 3476).
|
||||
|
||||
* Fix control mode clients hanging on exit if pty data was still queued (Ben
|
||||
Maurer, issue 5356), and avoid sending notifications to clients which are
|
||||
already exiting (Ben Maurer, issue 5357).
|
||||
|
||||
* Fix grouped sessions sometimes being left as unusable command targets while
|
||||
they are being killed (Bryce Miller, issue 5180).
|
||||
|
||||
* Fix choose mode filtering when more than one pane exists (issue 5326), and
|
||||
fix an infinite loop in customize mode when a filter does not match.
|
||||
|
||||
* Fix regsub when the pattern is anchored at the start (issue 5341).
|
||||
|
||||
* Fix redraw issues around synchronized updates, copy mode, tabs, padding,
|
||||
status lines, menus, popups, wide characters and floating panes. This
|
||||
includes fixes for flicker with alternate screen applications and scrollbars
|
||||
(Michael Grant, issue 5351; Noam Stolero, issue 5350; Aung Myo Kyaw, issue
|
||||
5098).
|
||||
|
||||
* Do not crash looking for the next or previous session (issue 5344), or when
|
||||
no client is available.
|
||||
|
||||
CHANGES FROM 3.7b TO 3.7c
|
||||
|
||||
* Build with jemalloc on macOS to avoid what appears to be a bug in calloc
|
||||
(issue 5385).
|
||||
|
||||
* Fix scrollbar initial state so they appear on new windows (issue 5339).
|
||||
|
||||
* Check time periodically in loops rather than every one (issue 5367).
|
||||
|
||||
* Use message-style again as default for message-format.
|
||||
|
||||
* Unzoom before creating floating panes to avoid a crash.
|
||||
|
||||
CHANGES FROM 3.7a TO 3.7b
|
||||
|
||||
* Fix so that the end of a synchronized update again triggers a redraw.
|
||||
|
||||
CHANGES FROM 3.7 TO 3.7a
|
||||
|
||||
* Fix crash in break-pane when no name is provided.
|
||||
|
||||
* Scrollbar options are now cached rather than being looked up for every redraw
|
||||
(issue 5298).
|
||||
|
||||
* Only forbid #( in names, allow #[, empty names, : and .
|
||||
|
||||
CHANGES FROM 3.6b TO 3.7
|
||||
|
||||
* Add floating panes. These are panes which sit above the layout ("tiled
|
||||
panes") like popups but unlike popups are not modal and behave like panes (so
|
||||
the same escape sequence support). Floating panes are created with the
|
||||
new-pane command, bound to * by default.
|
||||
|
||||
This is an early release of this feature and they are relatively limited.
|
||||
Currently floating panes can only be moved and resized using the mouse. The
|
||||
default second status line (if status-format is set to 2) has changed to show
|
||||
a list of panes. Many obvious features are not yet available for floating
|
||||
panes (notably the ability to swap floating panes, resize them using
|
||||
resize-pane, change them between floating and tiles, and restore custom
|
||||
layouts with floating panes).
|
||||
|
||||
Mostly written by Michael Grant with help from Dane Jensen; testing and fixes
|
||||
from others.
|
||||
|
||||
* Allow run-shell arguments after a shell command to be expanded as #{1}, #{2}
|
||||
and so on (from Rasmus Thystrup Karstensen in issue 5121).
|
||||
|
||||
* Add -g to kill-session to kill all sessions in a session group (issue 5157
|
||||
from github at jiku dot jp).
|
||||
|
||||
* Tighten up read-only checks on attach-session, detach-client and
|
||||
switch-client so that a user should be able to only detach their own client
|
||||
(reported by John Walker).
|
||||
|
||||
* Increase escape delay if the buffer contains a partial paste end, fixes
|
||||
issues with at least Windows Terminal (from jing dot empty at gmail.com issue
|
||||
5088).
|
||||
|
||||
* When mode-keys is set to vi, do not allow the cursor to go into the invisible
|
||||
extra cell to the right of the visible text; this is closer to what vi(1)
|
||||
does (from Max Vim in issue 5070).
|
||||
|
||||
* Add a five second limit on pasting for terminals which mysteriously lose the
|
||||
end sequence if the paste is too big (that is, Terminal.app) (reported by
|
||||
Garri Djavadyan in issue 4527).
|
||||
|
||||
* Show file open errors more sensibly (reported by Meriel Luna Mittelbach in
|
||||
issue 5081).
|
||||
|
||||
* Update supported features list for Foot terminal (from Meriel Luna Mittelbach
|
||||
in issue 5079).
|
||||
|
||||
* Turn off the "is this a paste" guessing if the terminal supports bracket
|
||||
pasting instead (issue 5031).
|
||||
|
||||
* Check FIONREAD for all panes not just piped panes.
|
||||
|
||||
* Add emacs-style recentre-top-bottom command to copy mode (issue 5053 from
|
||||
sinyax75 at gmail dot com).
|
||||
|
||||
* Allow the indicator in tree mode to be customized by two new options:
|
||||
tree-mode-preview-format and tree-mode-preview-style.
|
||||
|
||||
* Fix control client hang on exit after toggling no-output (issue 5049 from
|
||||
Aaron Campbell). Also various other control mode fixes.
|
||||
|
||||
* Add support for line numbers in copy mode. There is a new
|
||||
copy-mode-line-numbers option which may be set to off, default (tmux's normal
|
||||
line numbering where 0 is the top visible line), absolute (first line in
|
||||
history is 1), relative (relative to the cursor) and hybrid (current line is
|
||||
absolute, others relative). Also adds copy-mode-line-number-style and
|
||||
copy-mode-current-line-number-style to set the style of the line numbers.
|
||||
When copy mode is entered with the mouse, line numbers stay off. From Leo
|
||||
Henon in issue 5025.
|
||||
|
||||
* Make C-[ have the same bindings as Escape for terminals with extended
|
||||
keys where they are different (issue 5035 from Eric Nicolas).
|
||||
|
||||
* Sanitize paste buffer names in paste_set and paste_rename (issue 5032 from
|
||||
Barrett Ruth).
|
||||
|
||||
* Do not hang in run-shell when job_run fails (from Barrett Ruth in issue
|
||||
5037).
|
||||
|
||||
* Add ability to forward progress bar to outside terminal (issue 4972
|
||||
from Eric Dorland).
|
||||
|
||||
* Translate keypad keys to text in prompt input (from Barrett Ruth in issue
|
||||
4996).
|
||||
|
||||
* Sanitize pane titles and window and session names more consistently and
|
||||
strictly, prevents C0 characters and other invisible characters causing
|
||||
problems (reported by Chris Monardo in issue 4999).
|
||||
|
||||
* Make clock visible on terminals without colours (from Manuel Einfalt in issue
|
||||
5001).
|
||||
|
||||
* Add detach to default session menu (suggested by Przemyslaw Sztoch).
|
||||
|
||||
* Include window format variables for pane notifications (issue 5007 from Saul
|
||||
Nogueras).
|
||||
|
||||
* Limit precision to 100 for formats to stop silly formats from running out of
|
||||
memory, reported by z1281552865 at gmail dot com. Also various other similar
|
||||
changes, mostly found by OSS-Fuzz.
|
||||
|
||||
* Add WAYLAND_DISPLAY to default update-environment (issue 4965). Also some
|
||||
additional XDG_* variables (issue 5169).
|
||||
|
||||
* Add -C flag to command-prompt to match display-message -C (do not freeze
|
||||
panes) (from Barrett Ruth in issue 4978).
|
||||
|
||||
* Cache user from getpwuid because it can be very expensive on some
|
||||
platforms (from Ben Maurer in issue 4973).
|
||||
|
||||
* Add remain-on-exit key to keep pane around until a key is pressed (from
|
||||
Michael Grant).
|
||||
|
||||
* Add some new mouse ranges called "control0" to "control9" and use to add some
|
||||
mouse controls to the pane state line (from Dane Jensen with some bits from
|
||||
Michael Grant).
|
||||
|
||||
* Handle OSC 9;4 progress bar sequence and store in format variables (from Eric
|
||||
Dorland in issue 4954).
|
||||
|
||||
* Correctly size buffer used for parsing clipboard sequences (from Michal
|
||||
Majchrowicz).
|
||||
|
||||
* Limit MSG_COMMAND argument to between 0 and 1000 to prevent a misbehaving
|
||||
client from crashing the server (from Michal Majchrowicz).
|
||||
|
||||
* Reorganize host keys are represented internally so they can be built more
|
||||
easily (from Dane Jensen in issue 4953).
|
||||
|
||||
* Add new fuzzers for command parsing, formats and styles (from David
|
||||
Korczynski in issue 4957). Also fix various issues shown from these.
|
||||
|
||||
* Add bracket_paste_flag format flag (from George Nachman in issue 4951).
|
||||
|
||||
* Use \- for hyphens in tmux.1 to cause newer groff versions to render them
|
||||
correctly (from Keith Thompson in issue 4948).
|
||||
|
||||
* Various minor code improvements and fixes from Pavel Lavrukhin (issue 4936
|
||||
and others).
|
||||
|
||||
* Use window options for cursor-style to avoid crash when no pane (from Arden
|
||||
Packeer in issue 4942).
|
||||
|
||||
* Fix issue where popup window gets overwritten by background updates (from
|
||||
Conor Taylor in issue 4920).
|
||||
|
||||
* Protect against overflow when scrollbar is off screen (from san65384 at gmail
|
||||
dot com in issue 4933).
|
||||
|
||||
* Copy hyperlinks when redrawing popup so they do not vanish (from Antoine
|
||||
Gaudreau Simard in issue 4925).
|
||||
|
||||
* Work around systemd killing panes early during system shutdown by creating
|
||||
dependencies from the panes to the service which started tmux (issue 4926
|
||||
from Dmitry Torokhov).
|
||||
|
||||
* Allow codepoint-widths to accept ranges (from san65384 at gmail dot com in
|
||||
issue 4930).
|
||||
|
||||
* Add a short builtin help text for each mode accessible with C-h (based on
|
||||
code from Patrick Motard in issue 4751).
|
||||
|
||||
* Draw message as one format, allowing prompts and messages to occupy only a
|
||||
portion of the status bar, overlaying the normal status content rather than
|
||||
replacing the entire line. A new message-format option now controls the
|
||||
entire message (like status-format). The message-style option now need to
|
||||
include "fill" in order to cover the whole width (the default has
|
||||
"fill=yellow"). From Conor Taylor in issue 4861.
|
||||
|
||||
* Add next/previous variables for windows in W: loop (from Conor Taylor in
|
||||
issue 4856).
|
||||
|
||||
* Various bug and memory leak fixes from Renaud Allard (issue 4916).
|
||||
|
||||
* Add pane_pipe_pid with pipe file descriptor.
|
||||
|
||||
* Make -c work with new-session -A (from Jody Frankowski in issue 4906).
|
||||
|
||||
* Allow copy mode to work for readonly clients, except for copy commands (from
|
||||
Dane Jensen).
|
||||
|
||||
* Pass paste buffer through vis(3) when pasting to prevent buffers containing
|
||||
for example the bracket end sequence causing issues, a new -S flag disables
|
||||
(reported by Mason Davis).
|
||||
|
||||
* Add sorting (-O flag) and a custom format (-F) to list-keys (from Dane Jensen
|
||||
in issue 4845).
|
||||
|
||||
* Add scroll-exit-on, scroll-exit-off, scroll-exit-toggle commands to copy mode
|
||||
(from xcdnlgd at hotmail dot com in issue 4884).
|
||||
|
||||
* Respond to DECRQM 2026 (from David Turnbull in issue 4887) and various others
|
||||
(from Ayman Bagabas in issue 5118).
|
||||
|
||||
* Fix various memory leaks reported by Huihui Huang (issue 4872).
|
||||
|
||||
* Pass which clipboard is set through to the terminal (from Axel Lindskog in
|
||||
issue 4858).
|
||||
|
||||
* Reuse extended entry when clearing RGB cell, to prevent memory growth when
|
||||
cells are repeatedly cleared (from Michael K Darling in issue 4862).
|
||||
|
||||
* Do not write before buffer when parsing empty clipboard or palette replies,
|
||||
or try to allocate zero bytes with an empty clipboard sequence (reported by
|
||||
DongHan Kim).
|
||||
|
||||
* Various bug fixes and code improvements from Conor Taylor (issue 4848).
|
||||
|
||||
* Clear search counts when clearing marks in case of repeated search (reported
|
||||
by Daniel Pereira in issue 4817).
|
||||
|
||||
* Make OSC 52 work in popups (from gogongxt at 163 dot com in issue 4797).
|
||||
|
||||
* Refresh copy mode when style changes (from Josh Cooper in issue 4830).
|
||||
|
||||
* Make sorting code common and add -O for sorting to the list commands (from
|
||||
Dane Jensen in issue 4813).
|
||||
|
||||
* Do not treat cells as empty unless the background colour stays the same,
|
||||
fixes invisible clock in clock mode (reported by Theo Buehler).
|
||||
|
||||
* When history-limit is changed, apply to existing panes, not just new
|
||||
ones (issue 4705).
|
||||
|
||||
* Reevaluate menu and popup styles on each draw to allow them to change when
|
||||
options change (from Josh Cooper in issues 4828 and 4829).
|
||||
|
||||
* Handle theme keys earlier so they are processed even if a popup is open (from
|
||||
Josh Cooper in issue 4827).
|
||||
|
||||
* Fix window-size=latest not resizing on switch-client in session groups (from
|
||||
Ilya Grigoriev in issue 4818).
|
||||
|
||||
* Add -e flag to command-prompt to close if empty (from Dane Jensen in issue
|
||||
4812).
|
||||
|
||||
* Correctly draw indicators when pane-border-indicators is set to both
|
||||
(reported by Ilya Grigoriev in issue 4780).
|
||||
|
||||
* Remember last pane or type of location for double and triple clicks and
|
||||
correctly handle it changes between first and second or second and third
|
||||
(issue 4795 from Shaobo Song).
|
||||
|
||||
* Add paste to the default pane menu (issue 4763).
|
||||
|
||||
* Reduce request timeout to 500 milliseconds to match the extended escape-time,
|
||||
and discard palette requests if receiving a reply for a different index.
|
||||
|
||||
* Extend escape timeout if there are active forwarded requests not just
|
||||
tmux's own requests (issue 4793).
|
||||
|
||||
* Correct redrawing of wide characters when overwritten (reported by Jake
|
||||
Stewart in issue 4737).
|
||||
|
||||
* If cannot find a terminator for palette responses, treat as a partial key not
|
||||
complete (issue 4749).
|
||||
|
||||
* Do not send theme unless it has changed, and do not send immediately when
|
||||
updates are enabled (issue 5787).
|
||||
|
||||
* Do not use ;;s in list-keys output as it is confusing and cannot be
|
||||
parsed on input (from Patrick Motard in issue 4750).
|
||||
|
||||
* Redraw pane borders when entering or leaving alternate screen (from Mike
|
||||
Jonkmans in issue 4788).
|
||||
|
||||
* Add focus-follows-mouse option (from Barry Wasdell in issue 4771).
|
||||
|
||||
* Add selection_mode format variable for copy mode (from Mike Jonkmans in issue
|
||||
4773).
|
||||
|
||||
* Add prompt-command-cursor-style (from Joshua Cooper in issue 4765).
|
||||
|
||||
* With status-keys vi, move the cursor left by one when pressing Escape to
|
||||
enter command mode, like vi (issue 4767 from Joshua Cooper).
|
||||
|
||||
* Add {current}/{active} for -t for current window or active pane (from Manuel
|
||||
Einfalt, issue 4766).
|
||||
|
||||
* Add support for applications to use synchronized output mode (DECSET 2026) to
|
||||
prevent screen tearing during rapid updates (from Chris Lloyd in issue 4744).
|
||||
|
||||
* Do not set a default prompt cursor colour because some terminals (urxvt, st)
|
||||
do not support the reset sequence (issue 4759).
|
||||
|
||||
* Add a scroll-to-mouse command for copy mode to scroll to the mouse position
|
||||
and bind to the scrollbar, brings the scrollbar keys into line with the other
|
||||
mouse keys (from Michael Grant in issue 4731).
|
||||
|
||||
* Bump the maximum number of SIXEL images to 20.
|
||||
|
||||
* Fix key code for M-BSpace (issue 4717).
|
||||
|
||||
* Fix calculation of scaled SIXEL size (from nincsnevem662 at gmail dot com in
|
||||
issue 4739). Also various other fixes and improvements for SIXEL.
|
||||
|
||||
* Fix a race between fork and pane_current_path, most noticeable on systems
|
||||
where starting processes is slow (issue 4719).
|
||||
|
||||
* Fix mouse position calculation on scrollbar with pane status line at the top
|
||||
(issue 4738 from Michael Grant).
|
||||
|
||||
* Do not read outside buffer if format is a single #, and do not loop forever
|
||||
if UTF-8 is unfinished in a format (reported by Giorgi Kobakhia in issue
|
||||
4735).
|
||||
|
||||
* Add a missing skin tone character (from Jake Stewart in issue 4736).
|
||||
|
||||
* Allow UTF-8 characters to be combined in either order (reported by Jake
|
||||
Stewart in issue 4726).
|
||||
|
||||
* Do not show scrollbar when entering copy mode from a pane in the alternate
|
||||
screen (issue 4728 from Michael Grant).
|
||||
|
||||
* Fix the size calculation for left-right windows used to spread out cells
|
||||
horizontally evenly (from Michael Grant in issue 4724).
|
||||
|
||||
* Add a get-clipboard option which when enabled (the default is off) and a
|
||||
clipboard is requested from a pane, requests it from the terminal and
|
||||
forwards to the requesting pane; also remove the now-redundant
|
||||
forward-to-pane ability from "refresh-client -l" (issue 4275).
|
||||
|
||||
* Fix the noattr attribute in styles, used by the default mode-style (issue
|
||||
4713).
|
||||
|
||||
* Do not remove TERM for commands run from config file (regression reported by
|
||||
Dennis Eriksen).
|
||||
|
||||
* Add seconds options for clock mode (from augustus7613 dot mail at pm dot me,
|
||||
issue 4697; later improved by Joao Pedro in issue 4760).
|
||||
|
||||
CHANGES FROM 3.6a TO 3.6b
|
||||
|
||||
* Remove images from the correct list when they are removed while in the
|
||||
alternate screen (reported by xlabai at tencent dot com).
|
||||
|
||||
CHANGES FROM 3.6 TO 3.6a
|
||||
|
||||
* Fix a buffer overread and an infinite loop in format processing (reported by
|
||||
Giorgi Kobakhia, issue 4735).
|
||||
|
||||
* Allow drag in alternate screen again (issue 4743 reported by Brad King).
|
||||
|
||||
* Fix y offset of mouse if status at top (issue 4738 from Michael Grant).
|
||||
|
||||
* Add a missing skin tone (from Jake Stewart, issue 4736).
|
||||
|
||||
* Allow characters to be combined in either order (issue 4726, reported by Jake
|
||||
Stewart).
|
||||
|
||||
* Fix horizontal mouse resizing when pane status lines are on (from Michael
|
||||
Grant, issue 4720).
|
||||
|
||||
* Fix noattr so it does not delete attributes set in the style itself (issue
|
||||
4713).
|
||||
|
||||
* Newer libevents do not allow event_del on a zero'd event (issue 4706).
|
||||
|
||||
* Place cursor on correct line if message-line is not 0 (issue 4707).
|
||||
|
||||
* Fix compile error on FreeBSD (from Yasuhiro Kimura, issue 4701).
|
||||
|
||||
CHANGES FROM 3.5a TO 3.6
|
||||
|
||||
* Add seconds options for clock mode (issue 4697).
|
||||
|
||||
7
COPYING
7
COPYING
@@ -1,9 +1,4 @@
|
||||
THIS IS FOR INFORMATION ONLY, CODE IS UNDER THE LICENCE AT THE TOP OF ITS FILE.
|
||||
|
||||
The README, CHANGES, FAQ and TODO files are licensed under the ISC license. All
|
||||
other files have a license and copyright notice at their start, typically:
|
||||
|
||||
Copyright (c) <author>
|
||||
Copyright (c) Various Authors
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
|
||||
66
Makefile.am
66
Makefile.am
@@ -4,7 +4,7 @@ CLEANFILES = tmux.1.mdoc tmux.1.man cmd-parse.c
|
||||
|
||||
# Distribution tarball options.
|
||||
EXTRA_DIST = \
|
||||
CHANGES README README.ja COPYING example_tmux.conf \
|
||||
CHANGES README COPYING example_tmux.conf \
|
||||
osdep-*.c mdoc2man.awk tmux.1
|
||||
dist_EXTRA_tmux_SOURCES = compat/*.[ch]
|
||||
|
||||
@@ -13,28 +13,40 @@ AM_CPPFLAGS += @XOPEN_DEFINES@ \
|
||||
-DTMUX_VERSION='"@VERSION@"' \
|
||||
-DTMUX_CONF='"$(sysconfdir)/tmux.conf:~/.tmux.conf:$$XDG_CONFIG_HOME/tmux/tmux.conf:~/.config/tmux/tmux.conf"' \
|
||||
-DTMUX_LOCK_CMD='"@DEFAULT_LOCK_CMD@"' \
|
||||
-DTMUX_TERM='"@DEFAULT_TERM@"'
|
||||
-DTMUX_TERM='"@DEFAULT_TERM@"' \
|
||||
-DTMUX_MOUSE=1
|
||||
|
||||
# Additional object files.
|
||||
LDADD = $(LIBOBJS)
|
||||
|
||||
# Set flags for gcc.
|
||||
if IS_GCC
|
||||
AM_CFLAGS += -std=gnu99 -O2
|
||||
AM_CFLAGS += -std=gnu99
|
||||
if IS_OPTIMIZED
|
||||
AM_CFLAGS += -O2
|
||||
else
|
||||
AM_CFLAGS += -O0
|
||||
endif
|
||||
if IS_DEBUG
|
||||
AM_CFLAGS += -g
|
||||
AM_CFLAGS += -Wno-long-long -Wall -W -Wformat=2
|
||||
AM_CFLAGS += -g3 -ggdb
|
||||
AM_CFLAGS += -Wno-long-long -Wall -W -Wformat=2 -Wno-use-after-free
|
||||
AM_CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
|
||||
AM_CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
|
||||
AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
|
||||
AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wno-cast-align
|
||||
AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
|
||||
AM_CFLAGS += -Wno-unused-result -Wno-format-y2k
|
||||
AM_CFLAGS += -Wno-unused-result -Wno-format-y2k -Wno-unknown-warning-option
|
||||
AM_CFLAGS += -Wno-maybe-uninitialized
|
||||
if IS_DARWIN
|
||||
AM_CFLAGS += -Wno-deprecated-declarations -Wno-cast-align -Wno-macro-redefined
|
||||
AM_CFLAGS += -Wno-deprecated-declarations -Wno-macro-redefined
|
||||
endif
|
||||
AM_CPPFLAGS += -DDEBUG
|
||||
endif
|
||||
AM_CPPFLAGS += -iquote.
|
||||
if IS_ASAN
|
||||
AM_CPPFLAGS += -DASAN
|
||||
AM_CFLAGS += -fsanitize=address -fno-omit-frame-pointer
|
||||
AM_LDFLAGS += -fsanitize=address
|
||||
endif
|
||||
endif
|
||||
|
||||
# Set flags for Solaris.
|
||||
@@ -89,10 +101,10 @@ dist_tmux_SOURCES = \
|
||||
cmd-detach-client.c \
|
||||
cmd-display-menu.c \
|
||||
cmd-display-message.c \
|
||||
cmd-display-panes.c \
|
||||
cmd-find-window.c \
|
||||
cmd-find.c \
|
||||
cmd-if-shell.c \
|
||||
cmd-invoke.c \
|
||||
cmd-join-pane.c \
|
||||
cmd-kill-pane.c \
|
||||
cmd-kill-server.c \
|
||||
@@ -100,6 +112,7 @@ dist_tmux_SOURCES = \
|
||||
cmd-kill-window.c \
|
||||
cmd-list-buffers.c \
|
||||
cmd-list-clients.c \
|
||||
cmd-list-commands.c \
|
||||
cmd-list-keys.c \
|
||||
cmd-list-panes.c \
|
||||
cmd-list-sessions.c \
|
||||
@@ -148,12 +161,16 @@ dist_tmux_SOURCES = \
|
||||
control-notify.c \
|
||||
control.c \
|
||||
environ.c \
|
||||
events-payload.c \
|
||||
events.c \
|
||||
file.c \
|
||||
format.c \
|
||||
format-draw.c \
|
||||
format.c \
|
||||
fuzzy.c \
|
||||
grid-reader.c \
|
||||
grid-view.c \
|
||||
grid.c \
|
||||
hooks.c \
|
||||
hyperlinks.c \
|
||||
input-keys.c \
|
||||
input.c \
|
||||
@@ -166,13 +183,15 @@ dist_tmux_SOURCES = \
|
||||
log.c \
|
||||
menu.c \
|
||||
mode-tree.c \
|
||||
monitor.c \
|
||||
names.c \
|
||||
notify.c \
|
||||
options-table.c \
|
||||
options.c \
|
||||
paste.c \
|
||||
popup.c \
|
||||
proc.c \
|
||||
prompt-history.c \
|
||||
prompt.c \
|
||||
regsub.c \
|
||||
resize.c \
|
||||
screen-redraw.c \
|
||||
@@ -183,25 +202,31 @@ dist_tmux_SOURCES = \
|
||||
server-fn.c \
|
||||
server.c \
|
||||
session.c \
|
||||
sort.c \
|
||||
spawn.c \
|
||||
status.c \
|
||||
style.c \
|
||||
tmux-protocol.h \
|
||||
tmux.c \
|
||||
tmux.h \
|
||||
tmux-protocol.h \
|
||||
tty-acs.c \
|
||||
tty-draw.c \
|
||||
tty-features.c \
|
||||
tty-keys.c \
|
||||
tty-term.c \
|
||||
tty.c \
|
||||
utf8-combined.c \
|
||||
utf8.c \
|
||||
window-border.c \
|
||||
window-buffer.c \
|
||||
window-client.c \
|
||||
window-clock.c \
|
||||
window-copy.c \
|
||||
window-customize.c \
|
||||
window-panes.c \
|
||||
window-switch.c \
|
||||
window-tree.c \
|
||||
window-visible.c \
|
||||
window.c \
|
||||
xmalloc.c \
|
||||
xmalloc.h
|
||||
@@ -227,10 +252,21 @@ if ENABLE_SIXEL
|
||||
dist_tmux_SOURCES += image.c image-sixel.c
|
||||
endif
|
||||
|
||||
# Add bits for fuzzing if enabled.
|
||||
if NEED_FUZZING
|
||||
check_PROGRAMS = fuzz/input-fuzzer
|
||||
check_PROGRAMS = \
|
||||
fuzz/input-fuzzer \
|
||||
fuzz/cmd-parse-fuzzer \
|
||||
fuzz/format-fuzzer \
|
||||
fuzz/style-fuzzer
|
||||
fuzz_input_fuzzer_LDFLAGS = $(FUZZING_LIBS)
|
||||
fuzz_input_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
|
||||
fuzz_cmd_parse_fuzzer_LDFLAGS = $(FUZZING_LIBS)
|
||||
fuzz_cmd_parse_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
|
||||
fuzz_format_fuzzer_LDFLAGS = $(FUZZING_LIBS)
|
||||
fuzz_format_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
|
||||
fuzz_style_fuzzer_LDFLAGS = $(FUZZING_LIBS)
|
||||
fuzz_style_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
|
||||
endif
|
||||
|
||||
# Install tmux.1 in the right format.
|
||||
@@ -245,3 +281,7 @@ install-exec-hook:
|
||||
$(mkdir_p) $(DESTDIR)$(mandir)/man1
|
||||
$(INSTALL_DATA) $(srcdir)/tmux.1.@MANFORMAT@ \
|
||||
$(DESTDIR)$(mandir)/man1/tmux.1
|
||||
|
||||
# And uninstall it.
|
||||
uninstall-hook:
|
||||
rm -f $(DESTDIR)$(mandir)/man1/tmux.1
|
||||
|
||||
62
README.ja
62
README.ja
@@ -1,62 +0,0 @@
|
||||
tmuxへようこそ!
|
||||
|
||||
tmuxはターミナルマルチプレクサーです。複数のターミナルを一つのスクリーン内に作成し、操作することができます。
|
||||
バックグラウンドで処理を実行中に一度スクリーンから離れて後から復帰することも可能です。
|
||||
|
||||
OpenBSD、FreeBSD、NetBSD、Linux、macOS、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/scop/bash-completion/blob/main/completions/tmux
|
||||
|
||||
「-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>
|
||||
1
SECURITY.md
Normal file
1
SECURITY.md
Normal file
@@ -0,0 +1 @@
|
||||
Please report security issues to nicholas.marriott@gmail.com.
|
||||
173
SYNCING
173
SYNCING
@@ -1,173 +0,0 @@
|
||||
Preamble
|
||||
========
|
||||
|
||||
Tmux portable relies on repositories "tmux" and "tmux-obsd".
|
||||
Here's a description of them:
|
||||
|
||||
* "tmux" is the portable version, the one which contains code for other
|
||||
operating systems, and autotools, etc., which isn't found or needed in the
|
||||
OpenBSD base system.
|
||||
|
||||
* "tmux-obsd" is the version of tmux in OpenBSD base system which provides
|
||||
the basis of the portable tmux version.
|
||||
|
||||
Note: The "tmux-obsd" repository is actually handled by "git cvsimport"
|
||||
running at 15 minute intervals, so a commit made to OpenBSD's tmux CVS
|
||||
repository will take at least that long to appear in this git repository.
|
||||
(It might take longer, depending on the CVS mirror used to import the
|
||||
OpenBSD code).
|
||||
|
||||
If you've never used git before, git tracks meta-data about the committer
|
||||
and the author, as part of a commit, hence:
|
||||
|
||||
% git config [--global] user.name "Your name"
|
||||
% git config [--global] user.email "you@yourdomain.com"
|
||||
|
||||
Note that, if you already have this in the global ~/.gitconfig option, then
|
||||
this will be used. Setting this per-repository would involve not using the
|
||||
"--global" flag above. If you wish to use the same credentials always,
|
||||
pass the "--global" option, as shown.
|
||||
|
||||
This is a one-off operation once the repository has been cloned, assuming
|
||||
this information has ever been set before.
|
||||
|
||||
Cloning repositories
|
||||
====================
|
||||
|
||||
This involves having both tmux and tmux-obsd cloned, as in:
|
||||
|
||||
% cd /some/where/useful
|
||||
% git clone https://github.com/tmux/tmux.git
|
||||
% git clone https://github.com/ThomasAdam/tmux-obsd.git
|
||||
|
||||
Note that you do not need additional checkouts to manage the sync -- an
|
||||
existing clone of either repositories will suffice. So if you already have
|
||||
these checkouts existing, skip that.
|
||||
|
||||
Adding in git-remotes
|
||||
=====================
|
||||
|
||||
Because the portable "tmux" git repository and the "tmux-obsd"
|
||||
repository do not inherently share any history between each other, the
|
||||
history has been faked between them. This "faking of history" is something
|
||||
which has to be told to git for the purposes of comparing the "tmux" and
|
||||
"tmux-obsd" repositories for syncing. To do this, we must reference the
|
||||
clone of the "tmux-obsd" repository from the "tmux" repository, as
|
||||
shown by the following command:
|
||||
|
||||
% cd /path/to/tmux
|
||||
% git remote add obsd-tmux file:///path/to/tmux-obsd
|
||||
|
||||
So that now, the remote "obsd-tmux" can be used to reference branches and
|
||||
commits from the "tmux-obsd" repository, but from the context of the
|
||||
portable "tmux" repository, which makes sense because it's the "tmux"
|
||||
repository which will have the updates applied to them.
|
||||
|
||||
Fetching updates
|
||||
================
|
||||
|
||||
To ensure the latest commits from "tmux-obsd" can be found from within
|
||||
"tmux", we have to ensure the "master" branch from "tmux-obsd" is
|
||||
up-to-date first, and then reference that update in "tmux", as in:
|
||||
|
||||
% cd /path/to/tmux-obsd
|
||||
% git checkout master
|
||||
% git pull
|
||||
|
||||
Then back in "tmux":
|
||||
|
||||
% cd /path/to/tmux
|
||||
% git fetch obsd-tmux
|
||||
|
||||
Creating the necessary branches
|
||||
===============================
|
||||
|
||||
Now that "tmux" can see commits and branches from "tmux-obsd" by way
|
||||
of the remote name "obsd-tmux", we can now create the master branch from
|
||||
"tmux-obsd" in the "tmux" repository:
|
||||
|
||||
% git checkout -b obsd-master obsd-tmux/master
|
||||
|
||||
Adding in the fake history points
|
||||
=================================
|
||||
|
||||
To tie both the "master" branch from "tmux" and the "obsd-master"
|
||||
branch from "tmux-obsd" together, the fake history points added to the
|
||||
"tmux" repository need to be added. To do this, we must add an
|
||||
additional refspec line, as in:
|
||||
|
||||
% cd /path/to/tmux
|
||||
% git config --add remote.origin.fetch '+refs/replace/*:refs/replace/*'
|
||||
% git fetch origin
|
||||
|
||||
Performing the Sync
|
||||
===================
|
||||
|
||||
Make sure the "master" branch is checked out:
|
||||
|
||||
% git checkout master
|
||||
|
||||
The following will show commits on OpenBSD not yet synched with "tmux":
|
||||
|
||||
% git log master..obsd-master
|
||||
|
||||
From there, merge the result in, fixing up any conflicts which might arise.
|
||||
|
||||
% git merge obsd-master
|
||||
|
||||
Then ensure things look correct by BUILDING the result of that sync:
|
||||
|
||||
% make clean && ./autogen.sh && ./configure && make
|
||||
|
||||
Compare the git merge result with what's on origin/master -- that is, check
|
||||
which commits you're about to push:
|
||||
|
||||
% git log origin/master..master
|
||||
|
||||
And if happy:
|
||||
|
||||
% git push origin master
|
||||
|
||||
Keeping an eye on libutil in OpenBSD
|
||||
====================================
|
||||
|
||||
A lot of the compat/ code in tmux comes from libutil, especially imsg.
|
||||
Sometimes the API can change, etc., which might cause interesting problems
|
||||
trying to run the portable version of tmux. It's worth checking
|
||||
periodically for any changes to libutil in OpenBSD and syncing those files
|
||||
to compat/ as and when appropriate.
|
||||
|
||||
Release tmux for next version
|
||||
=============================
|
||||
|
||||
1. Update and commit README and CHANGES. The former should be checked for
|
||||
anything outdated and updated with a list of things that might break
|
||||
upgrades and the latter should mention all the major changes since
|
||||
the last version.
|
||||
|
||||
2. Make sure configure.ac has the new version number.
|
||||
|
||||
3. Tag with:
|
||||
|
||||
% git tag -a 2.X
|
||||
|
||||
Where "2.X" is the next version.
|
||||
|
||||
Push the tag out with:
|
||||
|
||||
% git push --tags
|
||||
|
||||
4. Build the tarball with 'make dist'.
|
||||
|
||||
5. Check the tarball. If it's good, go here to select the tag just pushed:
|
||||
|
||||
https://github.com/tmux/tmux/tags
|
||||
|
||||
Click the "Add release notes", upload the tarball and add a link in the
|
||||
description field to the CHANGES file.
|
||||
|
||||
6. Clone the tmux.github.io repository, and change the RELEASE version in the
|
||||
Makefile. Commit it, and run 'make' to replace %%RELEASE%%. Push the
|
||||
result out.
|
||||
|
||||
7. Change version back to master in configure.ac.
|
||||
234
SYNCING.md
Normal file
234
SYNCING.md
Normal file
@@ -0,0 +1,234 @@
|
||||
# Preamble
|
||||
|
||||
tmux portable is maintained from two repositories:
|
||||
|
||||
* `tmux` is the portable repository. It contains the portability layer,
|
||||
autotools build files, regression tests, documentation, and code needed for
|
||||
platforms outside OpenBSD.
|
||||
* `tmux-openbsd-cutover` is the OpenBSD tmux import repository. Its `master`
|
||||
branch is the OpenBSD tmux history after the OpenBSD Git cutover. Portable
|
||||
merges this branch when importing OpenBSD changes.
|
||||
|
||||
To create the commits in the tmux-openbsd-cutover repo, the source repo is the
|
||||
Github mirror of OpenBSD's src repo:
|
||||
|
||||
```text
|
||||
https://github.com/openbsd/src.git
|
||||
```
|
||||
|
||||
The update automation filters the OpenBSD source tree to `usr.bin/tmux/`,
|
||||
publishes that filtered history as `openbsd-git` in the cutover repository,
|
||||
cherry-picks new filtered commits onto cutover `master`, then merges cutover
|
||||
`master` into portable `master`.
|
||||
|
||||
If you've never used git before, configure your identity before committing:
|
||||
|
||||
```sh
|
||||
git config [--global] user.name "Your name"
|
||||
git config [--global] user.email "you@yourdomain.com"
|
||||
```
|
||||
|
||||
# Repository layout
|
||||
|
||||
The usual local layout is:
|
||||
|
||||
```sh
|
||||
cd /some/where/useful
|
||||
git clone https://github.com/tmux/tmux.git tmux-portable
|
||||
git clone https://github.com/ThomasAdam/tmux-obsd.git tmux-openbsd-cutover
|
||||
```
|
||||
|
||||
The exact directory names do not matter, but the examples below use:
|
||||
|
||||
```text
|
||||
/path/to/tmux-portable
|
||||
/path/to/tmux-openbsd-cutover
|
||||
```
|
||||
|
||||
The cutover repository has three important branches:
|
||||
|
||||
* `master` is the branch portable consumes. It should contain tmux source
|
||||
only, not automation files.
|
||||
* `openbsd-git` is the raw filtered OpenBSD tmux branch generated from
|
||||
OpenBSD src `master`.
|
||||
* `automation` is an orphan branch containing the GitHub Actions workflow. It
|
||||
is separate so that workflow files are not merged into portable.
|
||||
|
||||
# Adding the OpenBSD remote to portable
|
||||
|
||||
In the portable repository, add the cutover repository as a remote:
|
||||
|
||||
```sh
|
||||
cd /path/to/tmux-portable
|
||||
git remote add tmux-openbsd /path/to/tmux-openbsd-cutover
|
||||
git config remote.tmux-openbsd.tagOpt --no-tags
|
||||
```
|
||||
|
||||
If the remote already exists, update it instead:
|
||||
|
||||
```sh
|
||||
git remote set-url tmux-openbsd /path/to/tmux-openbsd-cutover
|
||||
git config remote.tmux-openbsd.tagOpt --no-tags
|
||||
```
|
||||
|
||||
Fetch the cutover master branch explicitly:
|
||||
|
||||
```sh
|
||||
git fetch --no-tags tmux-openbsd master:refs/remotes/tmux-openbsd/master
|
||||
```
|
||||
|
||||
# Automated syncing
|
||||
|
||||
The normal sync is performed by the GitHub Actions workflow in the
|
||||
`automation` branch of the cutover repository. That workflow:
|
||||
|
||||
1. Fetches or clones OpenBSD src using a blobless clone.
|
||||
2. Filters `usr.bin/tmux/` into a local `tmux-openbsd` branch.
|
||||
3. Updates `tmux-openbsd-cutover/openbsd-git`.
|
||||
4. Cherry-picks new `openbsd-git` commits onto cutover `master`.
|
||||
5. Merges cutover `master` into portable `master`.
|
||||
6. Pushes the changed repositories.
|
||||
|
||||
The workflow deliberately runs from the orphan `automation` branch but checks
|
||||
out cutover `master` as the branch to update. This keeps `.github/` out of
|
||||
cutover `master`, so portable does not import workflow files when it merges
|
||||
OpenBSD changes.
|
||||
|
||||
# Manual portable merge
|
||||
|
||||
If the workflow fails while merging into portable, do the merge locally and
|
||||
push the result.
|
||||
|
||||
Start from an up-to-date portable master:
|
||||
|
||||
```sh
|
||||
cd /path/to/tmux-portable
|
||||
git fetch origin
|
||||
git checkout master
|
||||
git pull --ff-only origin master
|
||||
```
|
||||
|
||||
Fetch the cutover branch:
|
||||
|
||||
```sh
|
||||
git remote add tmux-openbsd /path/to/tmux-openbsd-cutover 2>/dev/null || true
|
||||
git config remote.tmux-openbsd.tagOpt --no-tags
|
||||
git fetch --no-tags tmux-openbsd master:refs/remotes/tmux-openbsd/master
|
||||
```
|
||||
|
||||
Merge it:
|
||||
|
||||
```sh
|
||||
git merge --no-ff --log refs/remotes/tmux-openbsd/master
|
||||
```
|
||||
|
||||
Resolve conflicts by deciding whether portable or OpenBSD owns the file.
|
||||
|
||||
Useful commands:
|
||||
|
||||
```sh
|
||||
git checkout --ours path/to/file
|
||||
git add path/to/file
|
||||
```
|
||||
|
||||
This keeps the portable version of a conflicted file.
|
||||
|
||||
```sh
|
||||
git checkout --theirs path/to/file
|
||||
git add path/to/file
|
||||
```
|
||||
|
||||
This takes the OpenBSD/cutover version of a conflicted file.
|
||||
|
||||
Before committing, inspect the result:
|
||||
|
||||
```sh
|
||||
git status
|
||||
git diff --check
|
||||
git diff --cached --stat
|
||||
```
|
||||
|
||||
Then finish and publish:
|
||||
|
||||
```sh
|
||||
git commit
|
||||
git push origin master
|
||||
```
|
||||
|
||||
If the merge attempt is wrong, abort it:
|
||||
|
||||
```sh
|
||||
git merge --abort
|
||||
```
|
||||
|
||||
After pushing a manually resolved merge, rerun the workflow. It should either
|
||||
no-op or continue from the now-merged portable state.
|
||||
|
||||
# Manual cutover update
|
||||
|
||||
Normally this is handled by the workflow. If it must be done manually, update
|
||||
`openbsd-git` in the cutover repository from a filtered OpenBSD src checkout,
|
||||
then cherry-pick the new filtered commits onto cutover `master`.
|
||||
|
||||
The important range is:
|
||||
|
||||
```text
|
||||
origin/openbsd-git..openbsd-git
|
||||
```
|
||||
|
||||
where `origin/openbsd-git` is the previously published filtered OpenBSD tmux
|
||||
branch and `openbsd-git` is the newly generated filtered branch.
|
||||
|
||||
In the cutover repository:
|
||||
|
||||
```sh
|
||||
cd /path/to/tmux-openbsd-cutover
|
||||
git checkout master
|
||||
git cherry-pick origin/openbsd-git..openbsd-git
|
||||
git push origin master openbsd-git
|
||||
```
|
||||
|
||||
Do not put workflow files on cutover `master`; keep them on the orphan
|
||||
`automation` branch.
|
||||
|
||||
# Keeping an eye on libutil in OpenBSD
|
||||
|
||||
A lot of the `compat/` code in tmux comes from OpenBSD libraries, especially
|
||||
imsg. Sometimes APIs change in OpenBSD in ways that require corresponding
|
||||
portable changes. It is worth checking periodically for relevant OpenBSD
|
||||
libutil changes and syncing those files into `compat/` as appropriate.
|
||||
|
||||
# Release tmux for next version
|
||||
|
||||
1. Update and commit README and CHANGES. The former should be checked for
|
||||
anything outdated and updated with a list of things that might break
|
||||
upgrades and the latter should mention all the major changes since the last
|
||||
version.
|
||||
2. Make sure `configure.ac` has the new version number.
|
||||
3. Tag with:
|
||||
|
||||
```sh
|
||||
% git tag -a 2.X
|
||||
```
|
||||
|
||||
Where `2.X` is the next version.
|
||||
|
||||
Push the tag out with:
|
||||
|
||||
```sh
|
||||
% git push --tags
|
||||
```
|
||||
|
||||
4. Build the tarball with `make dist`.
|
||||
5. Check the tarball. If it is good, go here to select the tag just pushed:
|
||||
|
||||
```text
|
||||
https://github.com/tmux/tmux/tags
|
||||
```
|
||||
|
||||
Click "Add release notes", upload the tarball and add a link in the
|
||||
description field to the CHANGES file.
|
||||
6. Clone the tmux.github.io repository, and change the RELEASE version in the
|
||||
Makefile. Commit it, and run `make` to replace `%%RELEASE%%`. Push the
|
||||
result out.
|
||||
7. Change version back to master in `configure.ac`.
|
||||
8
alerts.c
8
alerts.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: alerts.c,v 1.35 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -205,7 +205,7 @@ alerts_check_bell(struct window *w)
|
||||
}
|
||||
if (!alerts_action_applies(wl, "bell-action"))
|
||||
continue;
|
||||
notify_winlink("alert-bell", wl);
|
||||
events_fire_winlink("alert-bell", wl);
|
||||
|
||||
if (s->flags & SESSION_ALERTED)
|
||||
continue;
|
||||
@@ -241,7 +241,7 @@ alerts_check_activity(struct window *w)
|
||||
}
|
||||
if (!alerts_action_applies(wl, "activity-action"))
|
||||
continue;
|
||||
notify_winlink("alert-activity", wl);
|
||||
events_fire_winlink("alert-activity", wl);
|
||||
|
||||
if (s->flags & SESSION_ALERTED)
|
||||
continue;
|
||||
@@ -277,7 +277,7 @@ alerts_check_silence(struct window *w)
|
||||
}
|
||||
if (!alerts_action_applies(wl, "silence-action"))
|
||||
continue;
|
||||
notify_winlink("alert-silence", wl);
|
||||
events_fire_winlink("alert-silence", wl);
|
||||
|
||||
if (s->flags & SESSION_ALERTED)
|
||||
continue;
|
||||
|
||||
201
arguments.c
201
arguments.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: arguments.c,v 1.67 2026/08/25 06:04:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -51,13 +51,6 @@ struct args {
|
||||
struct args_value *values;
|
||||
};
|
||||
|
||||
/* Prepared command state. */
|
||||
struct args_command_state {
|
||||
struct cmd_list *cmdlist;
|
||||
char *cmd;
|
||||
struct cmd_parse_input pi;
|
||||
};
|
||||
|
||||
static struct args_entry *args_find(struct args *, u_char);
|
||||
|
||||
static int args_cmp(struct args_entry *, struct args_entry *);
|
||||
@@ -89,8 +82,7 @@ args_copy_value(struct args_value *to, struct args_value *from)
|
||||
case ARGS_NONE:
|
||||
break;
|
||||
case ARGS_COMMANDS:
|
||||
to->cmdlist = from->cmdlist;
|
||||
to->cmdlist->references++;
|
||||
to->cmd = cmd_parse_add_ref(from->cmd);
|
||||
break;
|
||||
case ARGS_STRING:
|
||||
to->string = xstrdup(from->string);
|
||||
@@ -123,7 +115,7 @@ args_value_as_string(struct args_value *value)
|
||||
return ("");
|
||||
case ARGS_COMMANDS:
|
||||
if (value->cached == NULL)
|
||||
value->cached = cmd_list_print(value->cmdlist, 0);
|
||||
value->cached = cmd_parse_print(value->cmd, 0);
|
||||
return (value->cached);
|
||||
case ARGS_STRING:
|
||||
return (value->string);
|
||||
@@ -149,7 +141,7 @@ args_parse_flag_argument(struct args_value *values, u_int count, char **cause,
|
||||
int optional_argument)
|
||||
{
|
||||
struct args_value *argument, *new;
|
||||
const char *s;
|
||||
const char *s, *as;
|
||||
|
||||
new = xcalloc(1, sizeof *new);
|
||||
if (*string != '\0') {
|
||||
@@ -180,12 +172,24 @@ args_parse_flag_argument(struct args_value *values, u_int count, char **cause,
|
||||
xasprintf(cause, "-%c expects an argument", flag);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (optional_argument && argument->type == ARGS_STRING) {
|
||||
as = argument->string;
|
||||
if (as[0] == '-' && (as[1] == '-' || isalpha((u_char)as[1]))) {
|
||||
args_free_value(new);
|
||||
free(new);
|
||||
log_debug("%s: -%c (optional)", __func__, flag);
|
||||
args_set(args, flag, NULL, ARGS_ENTRY_OPTIONAL_VALUE);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
args_copy_value(new, argument);
|
||||
(*i)++;
|
||||
|
||||
out:
|
||||
s = args_value_as_string(new);
|
||||
log_debug("%s: -%c = %s", __func__, flag, s);
|
||||
|
||||
args_set(args, flag, new, 0);
|
||||
return (0);
|
||||
}
|
||||
@@ -355,7 +359,7 @@ args_copy_copy_value(struct args_value *to, struct args_value *from, int argc,
|
||||
to->string = expanded;
|
||||
break;
|
||||
case ARGS_COMMANDS:
|
||||
to->cmdlist = cmd_list_copy(from->cmdlist, argc, argv);
|
||||
to->cmd = cmd_parse_add_ref(from->cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -406,7 +410,7 @@ args_free_value(struct args_value *value)
|
||||
free(value->string);
|
||||
break;
|
||||
case ARGS_COMMANDS:
|
||||
cmd_list_free(value->cmdlist);
|
||||
cmd_parse_free(value->cmd);
|
||||
break;
|
||||
}
|
||||
free(value->cached);
|
||||
@@ -465,7 +469,7 @@ args_to_vector(struct args *args, int *argc, char ***argv)
|
||||
cmd_append_argv(argc, argv, args->values[i].string);
|
||||
break;
|
||||
case ARGS_COMMANDS:
|
||||
s = cmd_list_print(args->values[i].cmdlist, 0);
|
||||
s = cmd_parse_print(args->values[i].cmd, 0);
|
||||
cmd_append_argv(argc, argv, s);
|
||||
free(s);
|
||||
break;
|
||||
@@ -520,7 +524,7 @@ args_print_add_value(char **buf, size_t *len, struct args_value *value)
|
||||
case ARGS_NONE:
|
||||
break;
|
||||
case ARGS_COMMANDS:
|
||||
expanded = cmd_list_print(value->cmdlist, 0);
|
||||
expanded = cmd_parse_print(value->cmd, 0);
|
||||
args_print_add(buf, len, "{ %s }", expanded);
|
||||
break;
|
||||
case ARGS_STRING:
|
||||
@@ -735,144 +739,53 @@ args_string(struct args *args, u_int idx)
|
||||
return (args_value_as_string(&args->values[idx]));
|
||||
}
|
||||
|
||||
/* Make a command now. */
|
||||
struct cmd_list *
|
||||
args_make_commands_now(struct cmd *self, struct cmdq_item *item, u_int idx,
|
||||
int expand)
|
||||
{
|
||||
struct args_command_state *state;
|
||||
char *error;
|
||||
struct cmd_list *cmdlist;
|
||||
|
||||
state = args_make_commands_prepare(self, item, idx, NULL, 0, expand);
|
||||
cmdlist = args_make_commands(state, 0, NULL, &error);
|
||||
if (cmdlist == NULL) {
|
||||
cmdq_error(item, "%s", error);
|
||||
free(error);
|
||||
}
|
||||
else
|
||||
cmdlist->references++;
|
||||
args_make_commands_free(state);
|
||||
return (cmdlist);
|
||||
}
|
||||
|
||||
/* Save bits to make a command later. */
|
||||
struct args_command_state *
|
||||
args_make_commands_prepare(struct cmd *self, struct cmdq_item *item, u_int idx,
|
||||
const char *default_command, int wait, int expand)
|
||||
/*
|
||||
* Convert one command argument into a parse tree. A string value is parsed;
|
||||
* existing commands are referenced.
|
||||
*/
|
||||
struct cmd_parse_tree *
|
||||
args_to_commands(struct cmd *self, struct cmdq_item *item, u_int idx,
|
||||
const char *default_command, int expand, char **cause)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct args_value *value;
|
||||
struct args_command_state *state;
|
||||
const char *cmd;
|
||||
const char *file;
|
||||
struct cmd_parse_input pi = { 0 };
|
||||
const char *cmd = NULL, *file;
|
||||
char *expanded;
|
||||
struct cmd_parse_tree *tree;
|
||||
|
||||
state = xcalloc(1, sizeof *state);
|
||||
*cause = NULL;
|
||||
|
||||
if (idx < args->count) {
|
||||
value = &args->values[idx];
|
||||
if (value->type == ARGS_COMMANDS) {
|
||||
state->cmdlist = value->cmdlist;
|
||||
state->cmdlist->references++;
|
||||
return (state);
|
||||
}
|
||||
cmd = value->string;
|
||||
} else {
|
||||
if (default_command == NULL)
|
||||
fatalx("argument out of range");
|
||||
if (idx >= args->count)
|
||||
cmd = default_command;
|
||||
else {
|
||||
value = &args->values[idx];
|
||||
switch (value->type) {
|
||||
case ARGS_COMMANDS:
|
||||
return (cmd_parse_add_ref(value->cmd));
|
||||
case ARGS_STRING:
|
||||
cmd = value->string;
|
||||
break;
|
||||
case ARGS_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (cmd == NULL)
|
||||
fatalx("argument out of range");
|
||||
|
||||
if (expand)
|
||||
state->cmd = format_single_from_target(item, cmd);
|
||||
expanded = format_single_from_target(item, cmd);
|
||||
else
|
||||
state->cmd = xstrdup(cmd);
|
||||
log_debug("%s: %s", __func__, state->cmd);
|
||||
expanded = xstrdup(cmd);
|
||||
log_debug("%s: %s", __func__, expanded);
|
||||
|
||||
if (wait)
|
||||
state->pi.item = item;
|
||||
cmd_get_source(self, &file, &state->pi.line);
|
||||
cmd_get_source(self, &file, &pi.line);
|
||||
if (file != NULL)
|
||||
state->pi.file = xstrdup(file);
|
||||
state->pi.c = tc;
|
||||
if (state->pi.c != NULL)
|
||||
state->pi.c->references++;
|
||||
cmd_find_copy_state(&state->pi.fs, target);
|
||||
|
||||
return (state);
|
||||
}
|
||||
|
||||
/* Return argument as command. */
|
||||
struct cmd_list *
|
||||
args_make_commands(struct args_command_state *state, int argc, char **argv,
|
||||
char **error)
|
||||
{
|
||||
struct cmd_parse_result *pr;
|
||||
char *cmd, *new_cmd;
|
||||
int i;
|
||||
|
||||
if (state->cmdlist != NULL) {
|
||||
if (argc == 0)
|
||||
return (state->cmdlist);
|
||||
return (cmd_list_copy(state->cmdlist, argc, argv));
|
||||
}
|
||||
|
||||
cmd = xstrdup(state->cmd);
|
||||
log_debug("%s: %s", __func__, cmd);
|
||||
cmd_log_argv(argc, argv, __func__);
|
||||
for (i = 0; i < argc; i++) {
|
||||
new_cmd = cmd_template_replace(cmd, argv[i], i + 1);
|
||||
log_debug("%s: %%%u %s: %s", __func__, i + 1, argv[i], new_cmd);
|
||||
free(cmd);
|
||||
cmd = new_cmd;
|
||||
}
|
||||
log_debug("%s: %s", __func__, cmd);
|
||||
|
||||
pr = cmd_parse_from_string(cmd, &state->pi);
|
||||
free(cmd);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_ERROR:
|
||||
*error = pr->error;
|
||||
return (NULL);
|
||||
case CMD_PARSE_SUCCESS:
|
||||
return (pr->cmdlist);
|
||||
}
|
||||
fatalx("invalid parse return state");
|
||||
}
|
||||
|
||||
/* Free commands state. */
|
||||
void
|
||||
args_make_commands_free(struct args_command_state *state)
|
||||
{
|
||||
if (state->cmdlist != NULL)
|
||||
cmd_list_free(state->cmdlist);
|
||||
if (state->pi.c != NULL)
|
||||
server_client_unref(state->pi.c);
|
||||
free((void *)state->pi.file);
|
||||
free(state->cmd);
|
||||
free(state);
|
||||
}
|
||||
|
||||
/* Get prepared command. */
|
||||
char *
|
||||
args_make_commands_get_command(struct args_command_state *state)
|
||||
{
|
||||
struct cmd *first;
|
||||
int n;
|
||||
char *s;
|
||||
|
||||
if (state->cmdlist != NULL) {
|
||||
first = cmd_list_first(state->cmdlist);
|
||||
if (first == NULL)
|
||||
return (xstrdup(""));
|
||||
return (xstrdup(cmd_get_entry(first)->name));
|
||||
}
|
||||
n = strcspn(state->cmd, " ,");
|
||||
xasprintf(&s, "%.*s", n, state->cmd);
|
||||
return (s);
|
||||
pi.file = file;
|
||||
pi.flags = cmd_get_parse_flags(self);
|
||||
tree = cmd_parse_from_string(expanded, &pi, cause);
|
||||
free(expanded);
|
||||
return (tree);
|
||||
}
|
||||
|
||||
/* Get first value in argument. */
|
||||
@@ -998,7 +911,7 @@ args_string_percentage(const char *value, long long minval, long long maxval,
|
||||
copy = xstrdup(value);
|
||||
copy[valuelen - 1] = '\0';
|
||||
|
||||
ll = strtonum(copy, 0, 100, &errstr);
|
||||
ll = strtonum(copy, 0, 1000, &errstr);
|
||||
free(copy);
|
||||
if (errstr != NULL) {
|
||||
*cause = xstrdup(errstr);
|
||||
@@ -1066,7 +979,7 @@ args_string_percentage_and_expand(const char *value, long long minval,
|
||||
copy[valuelen - 1] = '\0';
|
||||
|
||||
f = format_single_from_target(item, copy);
|
||||
ll = strtonum(f, 0, 100, &errstr);
|
||||
ll = strtonum(f, 0, 1000, &errstr);
|
||||
free(f);
|
||||
free(copy);
|
||||
if (errstr != NULL) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: attributes.c,v 1.13 2026/07/02 08:51:05 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org>
|
||||
@@ -31,7 +31,7 @@ attributes_tostring(int attr)
|
||||
if (attr == 0)
|
||||
return ("none");
|
||||
|
||||
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
(attr & GRID_ATTR_CHARSET) ? "acs," : "",
|
||||
(attr & GRID_ATTR_BRIGHT) ? "bright," : "",
|
||||
(attr & GRID_ATTR_DIM) ? "dim," : "",
|
||||
@@ -45,7 +45,8 @@ attributes_tostring(int attr)
|
||||
(attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "",
|
||||
(attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-underscore," : "",
|
||||
(attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : "",
|
||||
(attr & GRID_ATTR_OVERLINE) ? "overline," : "");
|
||||
(attr & GRID_ATTR_OVERLINE) ? "overline," : "",
|
||||
(attr & GRID_ATTR_NOATTR) ? "noattr," : "");
|
||||
if (len > 0)
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
|
||||
71
cfg.c
71
cfg.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cfg.c,v 1.91 2026/08/03 13:38:42 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -56,7 +56,7 @@ cfg_done(__unused struct cmdq_item *item, __unused void *data)
|
||||
if (cfg_item != NULL)
|
||||
cmdq_continue(cfg_item);
|
||||
|
||||
status_prompt_load_history();
|
||||
prompt_load_history();
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
@@ -87,20 +87,21 @@ start_cfg(void)
|
||||
if (cfg_quiet)
|
||||
flags = CMD_PARSE_QUIET;
|
||||
for (i = 0; i < cfg_nfiles; i++)
|
||||
load_cfg(cfg_files[i], c, NULL, NULL, flags, NULL);
|
||||
load_cfg(cfg_files[i], NULL, NULL, flags, NULL);
|
||||
|
||||
cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
|
||||
}
|
||||
|
||||
int
|
||||
load_cfg(const char *path, struct client *c, struct cmdq_item *item,
|
||||
load_cfg(const char *path, struct cmdq_item *item,
|
||||
struct cmd_find_state *current, int flags, struct cmdq_item **new_item)
|
||||
{
|
||||
FILE *f;
|
||||
struct cmd_parse_input pi;
|
||||
struct cmd_parse_result *pr;
|
||||
struct cmd_parse_tree *tree;
|
||||
struct cmdq_item *new_item0;
|
||||
struct cmdq_state *state;
|
||||
char *cause = NULL;
|
||||
|
||||
if (new_item != NULL)
|
||||
*new_item = NULL;
|
||||
@@ -117,18 +118,16 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item,
|
||||
pi.flags = flags;
|
||||
pi.file = path;
|
||||
pi.line = 1;
|
||||
pi.item = item;
|
||||
pi.c = c;
|
||||
|
||||
pr = cmd_parse_from_file(f, &pi);
|
||||
tree = cmd_parse_from_file(f, &pi, &cause);
|
||||
fclose(f);
|
||||
if (pr->status == CMD_PARSE_ERROR) {
|
||||
cfg_add_cause("%s", pr->error);
|
||||
free(pr->error);
|
||||
if (tree == NULL) {
|
||||
cfg_add_cause("%s", cause);
|
||||
free(cause);
|
||||
return (-1);
|
||||
}
|
||||
cmd_parse_log(__func__, tree);
|
||||
if (flags & CMD_PARSE_PARSEONLY) {
|
||||
cmd_list_free(pr->cmdlist);
|
||||
cmd_parse_free(tree);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -138,12 +137,12 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item,
|
||||
state = cmdq_new_state(NULL, NULL, 0);
|
||||
cmdq_add_format(state, "current_file", "%s", pi.file);
|
||||
|
||||
new_item0 = cmdq_get_command(pr->cmdlist, state);
|
||||
new_item0 = cmd_invoke_get(tree, state, NULL);
|
||||
if (item != NULL)
|
||||
new_item0 = cmdq_insert_after(item, new_item0);
|
||||
else
|
||||
new_item0 = cmdq_append(NULL, new_item0);
|
||||
cmd_list_free(pr->cmdlist);
|
||||
cmd_parse_free(tree);
|
||||
cmdq_free_state(state);
|
||||
|
||||
if (new_item != NULL)
|
||||
@@ -153,13 +152,14 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item,
|
||||
|
||||
int
|
||||
load_cfg_from_buffer(const void *buf, size_t len, const char *path,
|
||||
struct client *c, struct cmdq_item *item, struct cmd_find_state *current,
|
||||
int flags, struct cmdq_item **new_item)
|
||||
struct cmdq_item *item, struct cmd_find_state *current, int flags,
|
||||
struct cmdq_item **new_item)
|
||||
{
|
||||
struct cmd_parse_input pi;
|
||||
struct cmd_parse_result *pr;
|
||||
struct cmd_parse_tree *tree;
|
||||
struct cmdq_item *new_item0;
|
||||
struct cmdq_state *state;
|
||||
char *cause = NULL;
|
||||
|
||||
if (new_item != NULL)
|
||||
*new_item = NULL;
|
||||
@@ -170,17 +170,15 @@ load_cfg_from_buffer(const void *buf, size_t len, const char *path,
|
||||
pi.flags = flags;
|
||||
pi.file = path;
|
||||
pi.line = 1;
|
||||
pi.item = item;
|
||||
pi.c = c;
|
||||
|
||||
pr = cmd_parse_from_buffer(buf, len, &pi);
|
||||
if (pr->status == CMD_PARSE_ERROR) {
|
||||
cfg_add_cause("%s", pr->error);
|
||||
free(pr->error);
|
||||
tree = cmd_parse_from_buffer(buf, len, &pi, &cause);
|
||||
if (tree == NULL) {
|
||||
cfg_add_cause("%s", cause);
|
||||
free(cause);
|
||||
return (-1);
|
||||
}
|
||||
cmd_parse_log(__func__, tree);
|
||||
if (flags & CMD_PARSE_PARSEONLY) {
|
||||
cmd_list_free(pr->cmdlist);
|
||||
cmd_parse_free(tree);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -190,12 +188,12 @@ load_cfg_from_buffer(const void *buf, size_t len, const char *path,
|
||||
state = cmdq_new_state(NULL, NULL, 0);
|
||||
cmdq_add_format(state, "current_file", "%s", pi.file);
|
||||
|
||||
new_item0 = cmdq_get_command(pr->cmdlist, state);
|
||||
new_item0 = cmd_invoke_get(tree, state, NULL);
|
||||
if (item != NULL)
|
||||
new_item0 = cmdq_insert_after(item, new_item0);
|
||||
else
|
||||
new_item0 = cmdq_append(NULL, new_item0);
|
||||
cmd_list_free(pr->cmdlist);
|
||||
cmd_parse_free(tree);
|
||||
cmdq_free_state(state);
|
||||
|
||||
if (new_item != NULL)
|
||||
@@ -223,13 +221,15 @@ cfg_print_causes(struct cmdq_item *item)
|
||||
{
|
||||
struct client *c = cmdq_get_client(item);
|
||||
u_int i;
|
||||
char *cause;
|
||||
|
||||
for (i = 0; i < cfg_ncauses; i++) {
|
||||
cause = cfg_causes[i];
|
||||
if (c != NULL && (c->flags & CLIENT_CONTROL))
|
||||
control_write(c, "%%config-error %s", cfg_causes[i]);
|
||||
control_notify_write(c, "%%config-error %s", cause);
|
||||
else
|
||||
cmdq_print(item, "%s", cfg_causes[i]);
|
||||
free(cfg_causes[i]);
|
||||
cmdq_print(item, "%s", cause);
|
||||
free(cause);
|
||||
}
|
||||
|
||||
free(cfg_causes);
|
||||
@@ -244,14 +244,16 @@ cfg_show_causes(struct session *s)
|
||||
struct window_pane *wp;
|
||||
struct window_mode_entry *wme;
|
||||
u_int i;
|
||||
char *cause;
|
||||
|
||||
if (cfg_ncauses == 0)
|
||||
return;
|
||||
|
||||
if (c != NULL && (c->flags & CLIENT_CONTROL)) {
|
||||
for (i = 0; i < cfg_ncauses; i++) {
|
||||
control_write(c, "%%config-error %s", cfg_causes[i]);
|
||||
free(cfg_causes[i]);
|
||||
cause = cfg_causes[i];
|
||||
control_notify_write(c, "%%config-error %s", cause);
|
||||
free(cause);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
@@ -268,7 +270,8 @@ cfg_show_causes(struct session *s)
|
||||
|
||||
wme = TAILQ_FIRST(&wp->modes);
|
||||
if (wme == NULL || wme->mode != &window_view_mode)
|
||||
window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL);
|
||||
window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL,
|
||||
NULL);
|
||||
for (i = 0; i < cfg_ncauses; i++) {
|
||||
window_copy_add(wp, 0, "%s", cfg_causes[i]);
|
||||
free(cfg_causes[i]);
|
||||
|
||||
74
client.c
74
client.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: client.c,v 1.168 2026/08/17 20:14:31 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -69,6 +69,25 @@ static void client_dispatch_attached(struct imsg *);
|
||||
static void client_dispatch_wait(struct imsg *);
|
||||
static const char *client_exit_message(void);
|
||||
|
||||
/* Does any command have a flag? */
|
||||
static int
|
||||
client_command_has_flag(int argc, char **argv, int flag)
|
||||
{
|
||||
struct args_value *values;
|
||||
struct cmd_parse_tree *tree;
|
||||
int found;
|
||||
|
||||
values = args_from_vector(argc, argv);
|
||||
tree = cmd_parse_from_arguments(values, argc, NULL);
|
||||
found = cmd_parse_any_have(tree, flag);
|
||||
|
||||
cmd_parse_free(tree);
|
||||
args_free_values(values, argc);
|
||||
free(values);
|
||||
|
||||
return (found);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get server create lock. If already held then server start is happening in
|
||||
* another client, so block until the lock is released and return -2 to
|
||||
@@ -232,18 +251,15 @@ int
|
||||
client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
||||
int feat)
|
||||
{
|
||||
struct cmd_parse_result *pr;
|
||||
struct msg_command *data;
|
||||
int fd, i;
|
||||
const char *ttynam, *termname, *cwd;
|
||||
pid_t ppid;
|
||||
enum msgtype msg;
|
||||
struct termios tio, saved_tio;
|
||||
size_t size, linesize = 0;
|
||||
ssize_t linelen;
|
||||
char *line = NULL, **caps = NULL, *cause;
|
||||
size_t size;
|
||||
char **caps = NULL, *cause;
|
||||
u_int ncaps = 0;
|
||||
struct args_value *values;
|
||||
|
||||
/* Set up the initial command. */
|
||||
if (shell_command != NULL) {
|
||||
@@ -254,22 +270,8 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
||||
flags |= CLIENT_STARTSERVER;
|
||||
} else {
|
||||
msg = MSG_COMMAND;
|
||||
|
||||
/*
|
||||
* It's annoying parsing the command string twice (in client
|
||||
* and later in server) but it is necessary to get the start
|
||||
* server flag.
|
||||
*/
|
||||
values = args_from_vector(argc, argv);
|
||||
pr = cmd_parse_from_arguments(values, argc, NULL);
|
||||
if (pr->status == CMD_PARSE_SUCCESS) {
|
||||
if (cmd_list_any_have(pr->cmdlist, CMD_STARTSERVER))
|
||||
if (client_command_has_flag(argc, argv, CMD_STARTSERVER))
|
||||
flags |= CLIENT_STARTSERVER;
|
||||
cmd_list_free(pr->cmdlist);
|
||||
} else
|
||||
free(pr->error);
|
||||
args_free_values(values, argc);
|
||||
free(values);
|
||||
}
|
||||
|
||||
/* Create client process structure (starts logging). */
|
||||
@@ -277,7 +279,7 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
||||
proc_set_signals(client_proc, client_signal);
|
||||
|
||||
/* Save the flags. */
|
||||
client_flags = flags;
|
||||
client_flags = flags|CLIENT_WRITE_ACK;
|
||||
log_debug("flags are %#llx", (unsigned long long)client_flags);
|
||||
|
||||
/* Initialize the client socket and start the server. */
|
||||
@@ -407,11 +409,6 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
||||
client_exec(client_execshell, client_execcmd);
|
||||
}
|
||||
|
||||
/* Restore streams to blocking. */
|
||||
setblocking(STDIN_FILENO, 1);
|
||||
setblocking(STDOUT_FILENO, 1);
|
||||
setblocking(STDERR_FILENO, 1);
|
||||
|
||||
/* Print the exit message, if any, and exit. */
|
||||
if (client_attached) {
|
||||
if (client_exitreason != CLIENT_EXIT_NONE)
|
||||
@@ -426,15 +423,8 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
||||
else
|
||||
printf("%%exit\n");
|
||||
fflush(stdout);
|
||||
if (client_flags & CLIENT_CONTROL_WAITEXIT) {
|
||||
setvbuf(stdin, NULL, _IOLBF, 0);
|
||||
for (;;) {
|
||||
linelen = getline(&line, &linesize, stdin);
|
||||
if (linelen <= 1)
|
||||
break;
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
if (client_flags & CLIENT_CONTROL_WAITEXIT)
|
||||
control_wait_exit(STDIN_FILENO);
|
||||
if (client_flags & CLIENT_CONTROLCONTROL) {
|
||||
printf("\033\\");
|
||||
fflush(stdout);
|
||||
@@ -442,6 +432,12 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
||||
}
|
||||
} else if (client_exitreason != CLIENT_EXIT_NONE)
|
||||
fprintf(stderr, "%s\n", client_exit_message());
|
||||
|
||||
/* Restore the streams to blocking. */
|
||||
setblocking(STDIN_FILENO, 1);
|
||||
setblocking(STDOUT_FILENO, 1);
|
||||
setblocking(STDERR_FILENO, 1);
|
||||
|
||||
return (client_exitval);
|
||||
}
|
||||
|
||||
@@ -719,6 +715,9 @@ client_dispatch_wait(struct imsg *imsg)
|
||||
fprintf(stderr, "server version is too old for client\n");
|
||||
proc_exit(client_proc);
|
||||
break;
|
||||
default:
|
||||
log_debug("unknown message type %u", imsg->hdr.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -805,5 +804,8 @@ client_dispatch_attached(struct imsg *imsg)
|
||||
system(data);
|
||||
proc_send(client_peer, MSG_UNLOCK, -1, NULL, 0);
|
||||
break;
|
||||
default:
|
||||
log_debug("unknown message type %u", imsg->hdr.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-attach-session.c,v 1.91 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -61,6 +61,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
|
||||
struct window_pane *wp;
|
||||
char *cwd, *cause;
|
||||
enum msgtype msgtype;
|
||||
uid_t uid;
|
||||
|
||||
if (RB_EMPTY(&sessions)) {
|
||||
cmdq_error(item, "no sessions");
|
||||
@@ -106,8 +107,16 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
|
||||
}
|
||||
if (fflag)
|
||||
server_client_set_flags(c, fflag);
|
||||
if (rflag)
|
||||
if (rflag) {
|
||||
if (c->flags & CLIENT_READONLY) {
|
||||
uid = proc_get_peer_uid(c->peer);
|
||||
if (uid != getuid()) {
|
||||
cmdq_error(item, "client is read-only");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
c->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE);
|
||||
}
|
||||
|
||||
c->last_session = c->session;
|
||||
if (c->session != NULL) {
|
||||
@@ -154,7 +163,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
|
||||
|
||||
if (~c->flags & CLIENT_CONTROL)
|
||||
proc_send(c->peer, MSG_READY, -1, NULL, 0);
|
||||
notify_client("client-attached", c);
|
||||
events_fire_client("client-attached", c);
|
||||
c->flags |= CLIENT_ATTACHED;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-bind-key.c,v 1.47 2025/04/09 07:03:04 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -56,11 +56,12 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
key_code key;
|
||||
const char *tablename, *note = args_get(args, 'N');
|
||||
struct cmd_parse_result *pr;
|
||||
const char *tablename, *note = args_get(args, 'N'), *file;
|
||||
int repeat;
|
||||
struct args_value *value;
|
||||
u_int count = args_count(args);
|
||||
struct cmd_parse_tree *cmd;
|
||||
struct cmd_parse_input pi;
|
||||
|
||||
key = key_string_lookup_string(args_string(args, 0));
|
||||
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
|
||||
@@ -83,25 +84,18 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
value = args_value(args, 1);
|
||||
if (count == 2 && value->type == ARGS_COMMANDS) {
|
||||
key_bindings_add(tablename, key, note, repeat, value->cmdlist);
|
||||
value->cmdlist->references++;
|
||||
cmd = cmd_parse_add_ref(value->cmd);
|
||||
key_bindings_add(tablename, key, note, repeat, cmd);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (count == 2)
|
||||
pr = cmd_parse_from_string(args_string(args, 1), NULL);
|
||||
else {
|
||||
pr = cmd_parse_from_arguments(args_values(args) + 1, count - 1,
|
||||
NULL);
|
||||
}
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_ERROR:
|
||||
cmdq_error(item, "%s", pr->error);
|
||||
free(pr->error);
|
||||
return (CMD_RETURN_ERROR);
|
||||
case CMD_PARSE_SUCCESS:
|
||||
break;
|
||||
}
|
||||
key_bindings_add(tablename, key, note, repeat, pr->cmdlist);
|
||||
memset(&pi, 0, sizeof pi);
|
||||
cmd_get_source(self, &file, &pi.line);
|
||||
if (file != NULL)
|
||||
pi.file = file;
|
||||
pi.flags = cmd_get_parse_flags(self);
|
||||
|
||||
cmd = cmd_parse_from_arguments(args_values(args) + 1, count - 1, &pi);
|
||||
key_bindings_add(tablename, key, note, repeat, cmd);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
102
cmd-break-pane.c
102
cmd-break-pane.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-break-pane.c,v 1.76 2026/08/17 07:04:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -34,9 +34,10 @@ const struct cmd_entry cmd_break_pane_entry = {
|
||||
.name = "break-pane",
|
||||
.alias = "breakp",
|
||||
|
||||
.args = { "abdPF:n:s:t:", 0, 0, NULL },
|
||||
.usage = "[-abdP] [-F format] [-n window-name] [-s src-pane] "
|
||||
"[-t dst-window]",
|
||||
.args = { "abdPF:n:s:t:Wx:X:y:Y:", 0, 0, NULL },
|
||||
.usage = "[-abdPW] [-F format] [-n window-name] [-s src-pane] "
|
||||
"[-t dst-window] [-x width] [-y height] [-X x-position] "
|
||||
"[-Y y-position]",
|
||||
|
||||
.source = { 's', CMD_FIND_PANE, 0 },
|
||||
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
|
||||
@@ -45,6 +46,46 @@ const struct cmd_entry cmd_break_pane_entry = {
|
||||
.exec = cmd_break_pane_exec
|
||||
};
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_break_pane_float(struct cmdq_item *item, struct args *args,
|
||||
struct window *w, struct window_pane *wp)
|
||||
{
|
||||
struct layout_cell *lc = wp->layout_cell;
|
||||
char *cause = NULL;
|
||||
enum pane_lines lines = window_get_pane_lines(w);
|
||||
struct layout_geometry *fg = &lc->fg;
|
||||
|
||||
if (window_pane_is_floating(wp)) {
|
||||
cmdq_error(item, "pane is already floating");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (w->flags & WINDOW_ZOOMED) {
|
||||
cmdq_error(item, "can't float a pane while window is zoomed");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (layout_floating_args_parse(item, args, lines, w, fg, &cause) != 0) {
|
||||
cmdq_error(item, "failed to float pane: %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
layout_remove_tile(w, lc);
|
||||
layout_set_size(lc, fg->sx, fg->sy, fg->xoff, fg->yoff);
|
||||
|
||||
lc->flags |= LAYOUT_CELL_FLOATING;
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
|
||||
|
||||
if (!args_has(args, 'd'))
|
||||
window_set_active_pane(w, wp, 1);
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
@@ -57,10 +98,23 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct session *src_s = source->s;
|
||||
struct session *dst_s = target->s;
|
||||
struct window_pane *wp = source->wp;
|
||||
struct window *w = wl->window;
|
||||
char *name, *cause, *cp;
|
||||
int idx = target->idx, before;
|
||||
const char *template;
|
||||
struct window *w = wl->window, *old_w = w;
|
||||
char *cause, *cp;
|
||||
int idx = target->idx, before, old_idx = wl->idx;
|
||||
const char *template, *name = args_get(args, 'n');
|
||||
|
||||
if (wp == w->modal) {
|
||||
cmdq_error(item, "pane is modal");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (args_has(args, 'W'))
|
||||
return (cmd_break_pane_float(item, args, w, wp));
|
||||
|
||||
if (name != NULL && !check_name(name)) {
|
||||
cmdq_error(item, "invalid window name: %s", name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
before = args_has(args, 'b');
|
||||
if (args_has(args, 'a') || before) {
|
||||
@@ -73,21 +127,22 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
server_unzoom_window(w);
|
||||
|
||||
if (window_count_panes(w) == 1) {
|
||||
if (window_count_panes(w, 1) == 1) {
|
||||
if (server_link_window(src_s, wl, dst_s, idx, 0,
|
||||
!args_has(args, 'd'), &cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (args_has(args, 'n')) {
|
||||
window_set_name(w, args_get(args, 'n'));
|
||||
if (name != NULL) {
|
||||
window_set_name(w, name, 0);
|
||||
options_set_number(w->options, "automatic-rename", 0);
|
||||
}
|
||||
server_unlink_window(src_s, wl);
|
||||
wl = winlink_find_by_window(&dst_s->windows, w);
|
||||
if (wl == NULL)
|
||||
return (CMD_RETURN_ERROR);
|
||||
window_fire_pane_moved(wp, old_w, old_idx, w, wl->idx);
|
||||
goto out;
|
||||
}
|
||||
if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) {
|
||||
@@ -96,33 +151,40 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&w->panes, wp, entry);
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
server_client_remove_pane(wp);
|
||||
window_lost_pane(w, wp);
|
||||
layout_close_pane(wp);
|
||||
|
||||
w = wp->window = window_create(w->sx, w->sy, w->xpixel, w->ypixel);
|
||||
window_add_ref(w, __func__);
|
||||
options_set_parent(wp->options, w->options);
|
||||
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
|
||||
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
|
||||
w->active = wp;
|
||||
w->latest = tc;
|
||||
|
||||
if (!args_has(args, 'n')) {
|
||||
name = default_window_name(w);
|
||||
window_set_name(w, name);
|
||||
free(name);
|
||||
} else {
|
||||
window_set_name(w, args_get(args, 'n'));
|
||||
free(w->name);
|
||||
if (name == NULL)
|
||||
w->name = default_window_name(w);
|
||||
else {
|
||||
w->name = clean_name(name, 0);
|
||||
options_set_number(w->options, "automatic-rename", 0);
|
||||
}
|
||||
window_set_fill_cells(w);
|
||||
|
||||
if (idx == -1)
|
||||
idx = -1 - options_get_number(dst_s->options, "base-index");
|
||||
wl = session_attach(dst_s, w, idx, &cause); /* can't fail */
|
||||
|
||||
layout_init(w, wp);
|
||||
wp->flags |= PANE_CHANGED;
|
||||
colour_palette_from_option(&wp->palette, wp->options);
|
||||
|
||||
if (idx == -1)
|
||||
idx = -1 - options_get_number(dst_s->options, "base-index");
|
||||
wl = session_attach(dst_s, w, idx, &cause); /* can't fail */
|
||||
window_remove_ref(w, __func__);
|
||||
events_fire_window("window-created", w);
|
||||
window_fire_pane_moved(wp, old_w, old_idx, w, wl->idx);
|
||||
if (!args_has(args, 'd')) {
|
||||
session_select(dst_s, wl->idx);
|
||||
cmd_find_from_session(current, dst_s, 0);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-capture-pane.c,v 1.68 2026/07/20 11:16:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Jonathan Alvarado <radobobo@users.sourceforge.net>
|
||||
@@ -29,18 +29,21 @@
|
||||
|
||||
static enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmdq_item *);
|
||||
|
||||
static char *cmd_capture_pane_append(char *, size_t *, char *, size_t);
|
||||
static char *cmd_capture_pane_append(char *, size_t *, const char *,
|
||||
size_t);
|
||||
static char *cmd_capture_pane_pending(struct args *, struct window_pane *,
|
||||
size_t *);
|
||||
static char *cmd_capture_pane_history(struct args *, struct cmdq_item *,
|
||||
struct window_pane *, size_t *);
|
||||
static char *cmd_capture_pane_hyperlinks(struct grid *, struct screen *,
|
||||
u_int, u_int *, u_int *, size_t *);
|
||||
|
||||
const struct cmd_entry cmd_capture_pane_entry = {
|
||||
.name = "capture-pane",
|
||||
.alias = "capturep",
|
||||
|
||||
.args = { "ab:CeE:JMNpPqS:Tt:", 0, 0, NULL },
|
||||
.usage = "[-aCeJMNpPqT] " CMD_BUFFER_USAGE " [-E end-line] "
|
||||
.args = { "ab:CeE:FHJLMNpPqRS:Tt:", 0, 0, NULL },
|
||||
.usage = "[-aCeFHJLMNpPqRT] " CMD_BUFFER_USAGE " [-E end-line] "
|
||||
"[-S start-line] " CMD_TARGET_PANE_USAGE,
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
@@ -63,7 +66,8 @@ const struct cmd_entry cmd_clear_history_entry = {
|
||||
};
|
||||
|
||||
static char *
|
||||
cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen)
|
||||
cmd_capture_pane_append(char *buf, size_t *len, const char *line,
|
||||
size_t linelen)
|
||||
{
|
||||
buf = xrealloc(buf, *len + linelen + 1);
|
||||
memcpy(buf + *len, line, linelen);
|
||||
@@ -71,6 +75,108 @@ cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen)
|
||||
return (buf);
|
||||
}
|
||||
|
||||
static char *
|
||||
cmd_capture_pane_cell(struct screen *s, u_int xx, u_int yy)
|
||||
{
|
||||
struct grid *gd = s->grid;
|
||||
struct hyperlinks *hl = s->hyperlinks;
|
||||
struct grid_cell gc;
|
||||
char *line, *data, *link, *linkid, *f, *b, *u;
|
||||
char c[UTF8_SIZE + 1];
|
||||
const char *uri, *iid;
|
||||
u_int flags;
|
||||
|
||||
grid_get_cell(gd, xx, yy, &gc);
|
||||
|
||||
memcpy(c, gc.data.data, gc.data.size);
|
||||
c[gc.data.size] = '\0';
|
||||
utf8_stravis(&data, c, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL);
|
||||
|
||||
if (gc.link != 0 && hyperlinks_get(hl, gc.link, &uri, &iid, NULL)) {
|
||||
xasprintf(&link, "%s", uri);
|
||||
if (iid != NULL && *iid != '\0')
|
||||
xasprintf(&linkid, "%s", iid);
|
||||
else
|
||||
xasprintf(&linkid, "NONE");
|
||||
} else {
|
||||
xasprintf(&link, "NONE");
|
||||
xasprintf(&linkid, "NONE");
|
||||
}
|
||||
|
||||
flags = gc.flags;
|
||||
if (gc.fg & COLOUR_FLAG_256)
|
||||
flags |= GRID_FLAG_FG256;
|
||||
if (gc.bg & COLOUR_FLAG_256)
|
||||
flags |= GRID_FLAG_BG256;
|
||||
|
||||
xasprintf(&f, "%s[%x]", colour_tostring(gc.fg), gc.fg);
|
||||
xasprintf(&b, "%s[%x]", colour_tostring(gc.bg), gc.bg);
|
||||
xasprintf(&u, "%s[%x]", colour_tostring(gc.us), gc.us);
|
||||
|
||||
xasprintf(&line, "\t\tC %u,%u data=(%u,%u,%s) flags=%s[%x] "
|
||||
"attr=%s[%x] fg=%s bg=%s us=%s link=%s linkid=%s\n",
|
||||
yy, xx, gc.data.width, gc.data.size, data,
|
||||
grid_cell_flags_string(flags), flags,
|
||||
grid_cell_attr_string(gc.attr), gc.attr, f, b, u, link, linkid);
|
||||
|
||||
free(f);
|
||||
free(b);
|
||||
free(u);
|
||||
free(link);
|
||||
free(linkid);
|
||||
free(data);
|
||||
return (line);
|
||||
}
|
||||
|
||||
static char *
|
||||
cmd_capture_pane_grid(struct window_pane *wp, size_t *len)
|
||||
{
|
||||
struct screen *s = &wp->base;
|
||||
struct grid *gd = s->grid;
|
||||
struct grid_line *gl;
|
||||
struct osc133_data *od;
|
||||
char *buf = xstrdup(""), *line;
|
||||
char p[11];
|
||||
u_int yy, xx, total = gd->hsize + gd->sy;
|
||||
|
||||
xasprintf(&line, "G %ux%u (%u/%u)\n", gd->sx, gd->sy, gd->hsize,
|
||||
gd->hlimit);
|
||||
buf = cmd_capture_pane_append(buf, len, line, strlen(line));
|
||||
free(line);
|
||||
|
||||
for (yy = 0; yy < total; yy++) {
|
||||
gl = grid_get_line(gd, yy);
|
||||
if (yy < gd->hsize)
|
||||
snprintf(p, sizeof p, "-");
|
||||
else
|
||||
snprintf(p, sizeof p, "%u", yy - gd->hsize);
|
||||
od = &gl->osc133_data;
|
||||
if (gl->flags & GRID_LINE_OSC133_FLAGS) {
|
||||
xasprintf(&line, "\tL %u (%s) flags=%s[%x] "
|
||||
"%u/%u osc133=%u,%u,%u,%u,%u\n", yy, p,
|
||||
grid_line_flags_string(gl->flags), gl->flags,
|
||||
gl->cellused, gl->cellsize, od->prompt_col,
|
||||
od->cmd_col, od->out_start_col,
|
||||
od->out_end_col, od->exit_status);
|
||||
} else {
|
||||
xasprintf(&line, "\tL %u (%s) flags=%s[%x] "
|
||||
"%u/%u\n", yy, p,
|
||||
grid_line_flags_string(gl->flags), gl->flags,
|
||||
gl->cellused, gl->cellsize);
|
||||
}
|
||||
buf = cmd_capture_pane_append(buf, len, line, strlen(line));
|
||||
free(line);
|
||||
|
||||
for (xx = 0; xx < gd->sx; xx++) {
|
||||
line = cmd_capture_pane_cell(s, xx, yy);
|
||||
buf = cmd_capture_pane_append(buf, len, line,
|
||||
strlen(line));
|
||||
free(line);
|
||||
}
|
||||
}
|
||||
return (buf);
|
||||
}
|
||||
|
||||
static char *
|
||||
cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
|
||||
size_t *len)
|
||||
@@ -103,6 +209,46 @@ cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
|
||||
return (buf);
|
||||
}
|
||||
|
||||
static char *
|
||||
cmd_capture_pane_hyperlinks(struct grid *gd, struct screen *s, u_int py,
|
||||
u_int *links, u_int *nlinks, size_t *len)
|
||||
{
|
||||
const struct grid_line *gl = grid_peek_line(gd, py);
|
||||
struct grid_cell gc;
|
||||
const char *uri;
|
||||
char *line = xstrdup("");
|
||||
u_int i, j;
|
||||
|
||||
*len = 0;
|
||||
|
||||
if (s->hyperlinks == NULL || (~gl->flags & GRID_LINE_HYPERLINK))
|
||||
return (line);
|
||||
|
||||
for (i = 0; i < gl->cellused; i++) {
|
||||
grid_get_cell(gd, i, py, &gc);
|
||||
if (gc.link == 0)
|
||||
continue;
|
||||
for (j = 0; j < *nlinks; j++) {
|
||||
if (links[j] == gc.link)
|
||||
break;
|
||||
}
|
||||
if (j != *nlinks)
|
||||
continue;
|
||||
|
||||
if (!hyperlinks_get(s->hyperlinks, gc.link, &uri, NULL, NULL))
|
||||
continue;
|
||||
|
||||
if (*nlinks == gd->sx)
|
||||
break;
|
||||
links[(*nlinks)++] = gc.link;
|
||||
|
||||
if (*len != 0)
|
||||
line = cmd_capture_pane_append(line, len, " ", 1);
|
||||
line = cmd_capture_pane_append(line, len, uri, strlen(uri));
|
||||
}
|
||||
return (line);
|
||||
}
|
||||
|
||||
static char *
|
||||
cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
||||
struct window_pane *wp, size_t *len)
|
||||
@@ -112,9 +258,11 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
||||
struct screen *s;
|
||||
struct grid_cell *gc = NULL;
|
||||
struct window_mode_entry *wme;
|
||||
int n, join_lines, flags = 0;
|
||||
int n, join_lines, number_lines, flags = 0;
|
||||
int show_flags, hyperlinks;
|
||||
u_int *links = NULL, nlinks = 0;
|
||||
u_int i, sx, top, bottom, tmp;
|
||||
char *cause, *buf, *line;
|
||||
char *cause, *buf = NULL, *line, b[64], *cp;
|
||||
const char *Sflag, *Eflag;
|
||||
size_t linelen;
|
||||
|
||||
@@ -152,7 +300,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
||||
if (cause != NULL) {
|
||||
top = gd->hsize;
|
||||
free(cause);
|
||||
} else if (n < 0 && (u_int) -n > gd->hsize)
|
||||
} else if (n < 0 && (u_int)-n > gd->hsize)
|
||||
top = 0;
|
||||
else
|
||||
top = gd->hsize + n;
|
||||
@@ -169,7 +317,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
||||
if (cause != NULL) {
|
||||
bottom = gd->hsize + gd->sy - 1;
|
||||
free(cause);
|
||||
} else if (n < 0 && (u_int) -n > gd->hsize)
|
||||
} else if (n < 0 && (u_int)-n > gd->hsize)
|
||||
bottom = 0;
|
||||
else
|
||||
bottom = gd->hsize + n;
|
||||
@@ -192,12 +340,57 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
||||
flags |= GRID_STRING_EMPTY_CELLS;
|
||||
if (!join_lines && !args_has(args, 'N'))
|
||||
flags |= GRID_STRING_TRIM_SPACES;
|
||||
number_lines = args_has(args, 'L');
|
||||
show_flags = args_has(args, 'F');
|
||||
hyperlinks = args_has(args, 'H');
|
||||
if (hyperlinks)
|
||||
links = xreallocarray(NULL, gd->sx, sizeof *links);
|
||||
|
||||
buf = NULL;
|
||||
for (i = top; i <= bottom; i++) {
|
||||
if (hyperlinks) {
|
||||
line = cmd_capture_pane_hyperlinks(gd, s, i, links,
|
||||
&nlinks, &linelen);
|
||||
} else {
|
||||
line = grid_string_cells(gd, 0, i, sx, &gc, flags, s);
|
||||
linelen = strlen(line);
|
||||
}
|
||||
if (hyperlinks && linelen == 0) {
|
||||
free(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (number_lines) {
|
||||
if (i >= gd->hsize)
|
||||
n = i - gd->hsize;
|
||||
else
|
||||
n = (int)i - (int)gd->hsize;
|
||||
n = snprintf(b, sizeof b, "%d ", n);
|
||||
if (n >= 0)
|
||||
buf = cmd_capture_pane_append(buf, len, b, n);
|
||||
}
|
||||
if (show_flags) {
|
||||
cp = b;
|
||||
*cp = '\0';
|
||||
|
||||
gl = grid_peek_line(gd, i);
|
||||
if (gl->flags & GRID_LINE_DEAD)
|
||||
*cp++ = 'D';
|
||||
if (gl->flags & GRID_LINE_HYPERLINK)
|
||||
*cp++ = 'H';
|
||||
if (gl->flags & GRID_LINE_START_OUTPUT)
|
||||
*cp++ = 'O';
|
||||
if (gl->flags & GRID_LINE_START_PROMPT)
|
||||
*cp++ = 'P';
|
||||
if (gl->flags & GRID_LINE_WRAPPED)
|
||||
*cp++ = 'W';
|
||||
if (gl->flags & GRID_LINE_EXTENDED)
|
||||
*cp++ = 'X';
|
||||
if (b == cp)
|
||||
*cp++ = '-';
|
||||
*cp++ = ' ';
|
||||
*cp = '\0';
|
||||
buf = cmd_capture_pane_append(buf, len, b, strlen (b));
|
||||
}
|
||||
buf = cmd_capture_pane_append(buf, len, line, linelen);
|
||||
|
||||
gl = grid_peek_line(gd, i);
|
||||
@@ -206,6 +399,9 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
||||
|
||||
free(line);
|
||||
}
|
||||
free(links);
|
||||
if (buf == NULL)
|
||||
buf = xstrdup("");
|
||||
return (buf);
|
||||
}
|
||||
|
||||
@@ -224,11 +420,14 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
grid_clear_history(wp->base.grid);
|
||||
if (args_has(args, 'H'))
|
||||
screen_reset_hyperlinks(wp->screen);
|
||||
server_redraw_window(wp->window);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
len = 0;
|
||||
if (args_has(args, 'P'))
|
||||
if (args_has(args, 'R'))
|
||||
buf = cmd_capture_pane_grid(wp, &len);
|
||||
else if (args_has(args, 'P') && !args_has(args, 'H'))
|
||||
buf = cmd_capture_pane_pending(args, wp, &len);
|
||||
else
|
||||
buf = cmd_capture_pane_history(args, item, wp, &len);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-choose-tree.c,v 1.58 2026/07/14 17:17:17 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
|
||||
@@ -33,8 +33,8 @@ const struct cmd_entry cmd_choose_tree_entry = {
|
||||
.name = "choose-tree",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "F:f:GK:NO:rst:wyZ", 0, 1, cmd_choose_tree_args_parse },
|
||||
.usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] "
|
||||
.args = { "F:f:GhK:kNO:rst:wyZ", 0, 1, cmd_choose_tree_args_parse },
|
||||
.usage = "[-GhkNrswZ] [-F format] [-f filter] [-K key-format] "
|
||||
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
@@ -47,8 +47,8 @@ const struct cmd_entry cmd_choose_client_entry = {
|
||||
.name = "choose-client",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "F:f:K:NO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
|
||||
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
|
||||
.args = { "F:f:hiK:kNO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
|
||||
.usage = "[-hikNrZ] [-F format] [-f filter] [-K key-format] "
|
||||
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
@@ -61,8 +61,8 @@ const struct cmd_entry cmd_choose_buffer_entry = {
|
||||
.name = "choose-buffer",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "F:f:K:NO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
|
||||
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
|
||||
.args = { "F:f:K:kNO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
|
||||
.usage = "[-kNrZ] [-F format] [-f filter] [-K key-format] "
|
||||
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
@@ -75,8 +75,8 @@ const struct cmd_entry cmd_customize_mode_entry = {
|
||||
.name = "customize-mode",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "F:f:Nt:yZ", 0, 0, NULL },
|
||||
.usage = "[-NZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
|
||||
.args = { "F:f:kNt:yZ", 0, 0, NULL },
|
||||
.usage = "[-kNZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
@@ -84,6 +84,34 @@ const struct cmd_entry cmd_customize_mode_entry = {
|
||||
.exec = cmd_choose_tree_exec
|
||||
};
|
||||
|
||||
const struct cmd_entry cmd_switch_mode_entry = {
|
||||
.name = "switch-mode",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "F:kst:wZ", 0, 1, cmd_choose_tree_args_parse },
|
||||
.usage = "[-kswZ] [-F format] " CMD_TARGET_PANE_USAGE " [command]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
.flags = 0,
|
||||
.exec = cmd_choose_tree_exec
|
||||
};
|
||||
|
||||
const struct cmd_entry cmd_display_panes_entry = {
|
||||
.name = "display-panes",
|
||||
.alias = "displayp",
|
||||
|
||||
.args = { "d:kNs:t:Z", 0, 1, cmd_choose_tree_args_parse },
|
||||
.usage = "[-kNZ] [-d duration] [-s source-window] "
|
||||
CMD_TARGET_PANE_USAGE " [template]",
|
||||
|
||||
.source = { 's', CMD_FIND_WINDOW, 0 },
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.exec = cmd_choose_tree_exec
|
||||
};
|
||||
|
||||
static enum args_parse_type
|
||||
cmd_choose_tree_args_parse(__unused struct args *args, __unused u_int idx,
|
||||
__unused char **cause)
|
||||
@@ -98,6 +126,13 @@ cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct window_pane *wp = target->wp;
|
||||
const struct window_mode *mode;
|
||||
enum sort_order order;
|
||||
|
||||
order = sort_order_from_string(args_get(args, 'O'));
|
||||
if (order == SORT_END && args_has(args, 'O')) {
|
||||
cmdq_error(item, "invalid sort order");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (cmd_get_entry(self) == &cmd_choose_buffer_entry) {
|
||||
if (paste_is_empty())
|
||||
@@ -109,9 +144,13 @@ cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
|
||||
mode = &window_client_mode;
|
||||
} else if (cmd_get_entry(self) == &cmd_customize_mode_entry)
|
||||
mode = &window_customize_mode;
|
||||
else if (cmd_get_entry(self) == &cmd_switch_mode_entry)
|
||||
mode = &window_switch_mode;
|
||||
else if (cmd_get_entry(self) == &cmd_display_panes_entry)
|
||||
mode = &window_panes_mode;
|
||||
else
|
||||
mode = &window_tree_mode;
|
||||
|
||||
window_pane_set_mode(wp, NULL, mode, target, args);
|
||||
window_pane_set_mode(wp, NULL, mode, item, target, args);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-command-prompt.c,v 1.76 2026/08/25 06:04:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -34,16 +34,16 @@ static enum args_parse_type cmd_command_prompt_args_parse(struct args *,
|
||||
static enum cmd_retval cmd_command_prompt_exec(struct cmd *,
|
||||
struct cmdq_item *);
|
||||
|
||||
static int cmd_command_prompt_callback(struct client *, void *,
|
||||
const char *, int);
|
||||
static enum prompt_result cmd_command_prompt_callback(struct client *, void *,
|
||||
const char *, enum prompt_key_result);
|
||||
static void cmd_command_prompt_free(void *);
|
||||
|
||||
const struct cmd_entry cmd_command_prompt_entry = {
|
||||
.name = "command-prompt",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "1bFkliI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse },
|
||||
.usage = "[-1bFkliN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
|
||||
.args = { "1CbeFiklI:NPp:t:T:", 0, 1, cmd_command_prompt_args_parse },
|
||||
.usage = "[-1CbeFiklNP] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
|
||||
" [-T prompt-type] [template]",
|
||||
|
||||
.flags = CMD_CLIENT_TFLAG,
|
||||
@@ -57,11 +57,13 @@ struct cmd_command_prompt_prompt {
|
||||
|
||||
struct cmd_command_prompt_cdata {
|
||||
struct cmdq_item *item;
|
||||
struct args_command_state *state;
|
||||
struct cmd_parse_tree *tree;
|
||||
|
||||
int flags;
|
||||
enum prompt_type prompt_type;
|
||||
|
||||
struct window_pane *wp;
|
||||
|
||||
struct cmd_command_prompt_prompt *prompts;
|
||||
u_int count;
|
||||
u_int current;
|
||||
@@ -83,14 +85,19 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
const char *type, *s, *input;
|
||||
const char *type, *s, *input, *cmd;
|
||||
struct cmd_command_prompt_cdata *cdata;
|
||||
char *tmp, *prompts, *prompt, *next_prompt;
|
||||
char *inputs = NULL, *next_input;
|
||||
char *inputs = NULL, *next_input, *cause = NULL;
|
||||
struct window_pane *wp = target->wp;
|
||||
u_int count = args_count(args);
|
||||
int wait = !args_has(args, 'b'), space = 1;
|
||||
int wait = !args_has(args, 'b'), space = 1, n;
|
||||
int pane = args_has(args, 'P');
|
||||
|
||||
if (tc->prompt_string != NULL)
|
||||
if (pane) {
|
||||
if (wp == NULL || window_pane_has_prompt(wp))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
} else if (tc->prompt != NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (args_has(args, 'i'))
|
||||
wait = 0;
|
||||
@@ -98,14 +105,24 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cdata = xcalloc(1, sizeof *cdata);
|
||||
if (wait)
|
||||
cdata->item = item;
|
||||
cdata->state = args_make_commands_prepare(self, item, 0, "%1", wait,
|
||||
args_has(args, 'F'));
|
||||
if (pane)
|
||||
cdata->wp = wp;
|
||||
if (count != 0) {
|
||||
cdata->tree = args_to_commands(self, item, 0, NULL,
|
||||
args_has(args, 'F'), &cause);
|
||||
if (cdata->tree == NULL) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
free(cdata);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
if ((s = args_get(args, 'p')) == NULL) {
|
||||
if (count != 0) {
|
||||
tmp = args_make_commands_get_command(cdata->state);
|
||||
xasprintf(&prompts, "(%s)", tmp);
|
||||
free(tmp);
|
||||
cmd = args_string(args, 0);
|
||||
n = strcspn(cmd, " ,");
|
||||
xasprintf(&prompts, "(%.*s)", n, cmd);
|
||||
} else {
|
||||
prompts = xstrdup(":");
|
||||
space = 0;
|
||||
@@ -146,7 +163,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
|
||||
if ((type = args_get(args, 'T')) != NULL) {
|
||||
cdata->prompt_type = status_prompt_type(type);
|
||||
cdata->prompt_type = prompt_type(type);
|
||||
if (cdata->prompt_type == PROMPT_TYPE_INVALID) {
|
||||
cmdq_error(item, "unknown type: %s", type);
|
||||
cmd_command_prompt_free(cdata);
|
||||
@@ -163,72 +180,118 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cdata->flags |= PROMPT_INCREMENTAL;
|
||||
else if (args_has(args, 'k'))
|
||||
cdata->flags |= PROMPT_KEY;
|
||||
else if (args_has(args, 'e'))
|
||||
cdata->flags |= PROMPT_BSPACE_EXIT;
|
||||
if (args_has(args, 'C'))
|
||||
cdata->flags |= PROMPT_NOFREEZE;
|
||||
if (pane) {
|
||||
cdata->flags |= PROMPT_ISPANE;
|
||||
window_pane_set_prompt(wp, tc, target, cdata->prompts[0].prompt,
|
||||
cdata->prompts[0].input, cmd_command_prompt_callback,
|
||||
cmd_command_prompt_free, cdata, cdata->flags,
|
||||
cdata->prompt_type);
|
||||
} else {
|
||||
status_prompt_set(tc, target, cdata->prompts[0].prompt,
|
||||
cdata->prompts[0].input, cmd_command_prompt_callback,
|
||||
cmd_command_prompt_free, cdata, cdata->flags, cdata->prompt_type);
|
||||
cmd_command_prompt_free, cdata, cdata->flags,
|
||||
cdata->prompt_type);
|
||||
}
|
||||
|
||||
if (!wait)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
return (CMD_RETURN_WAIT);
|
||||
}
|
||||
|
||||
static int
|
||||
static enum prompt_result
|
||||
cmd_command_prompt_callback(struct client *c, void *data, const char *s,
|
||||
int done)
|
||||
enum prompt_key_result key)
|
||||
{
|
||||
struct cmd_command_prompt_cdata *cdata = data;
|
||||
char *error;
|
||||
struct cmdq_item *item = cdata->item, *new_item;
|
||||
struct cmd_list *cmdlist;
|
||||
struct cmdq_state *cs = NULL;
|
||||
struct cmd_command_prompt_prompt *prompt;
|
||||
struct cmd_invoke_input ci = { 0 };
|
||||
struct cmd_parse_tree *tree;
|
||||
struct cmd_parse_input pi = { 0 };
|
||||
int argc = 0;
|
||||
char **argv = NULL;
|
||||
|
||||
if (s == NULL)
|
||||
if (s == NULL || key == PROMPT_KEY_MOVE)
|
||||
goto out;
|
||||
|
||||
if (done) {
|
||||
if (key == PROMPT_KEY_CLOSE) {
|
||||
if (cdata->flags & PROMPT_INCREMENTAL)
|
||||
goto out;
|
||||
cmd_append_argv(&cdata->argc, &cdata->argv, s);
|
||||
if (++cdata->current != cdata->count) {
|
||||
prompt = &cdata->prompts[cdata->current];
|
||||
status_prompt_update(c, prompt->prompt, prompt->input);
|
||||
return (1);
|
||||
if (cdata->wp != NULL) {
|
||||
window_pane_update_prompt(cdata->wp,
|
||||
prompt->prompt, prompt->input);
|
||||
} else
|
||||
status_prompt_update(c, prompt->prompt,
|
||||
prompt->input);
|
||||
return (PROMPT_CONTINUE);
|
||||
}
|
||||
}
|
||||
|
||||
argc = cdata->argc;
|
||||
argv = cmd_copy_argv(cdata->argc, cdata->argv);
|
||||
if (!done)
|
||||
if (key != PROMPT_KEY_CLOSE)
|
||||
cmd_append_argv(&argc, &argv, s);
|
||||
|
||||
if (done) {
|
||||
else {
|
||||
cmd_free_argv(cdata->argc, cdata->argv);
|
||||
cdata->argc = argc;
|
||||
cdata->argv = cmd_copy_argv(argc, argv);
|
||||
}
|
||||
|
||||
cmdlist = args_make_commands(cdata->state, argc, argv, &error);
|
||||
if (cmdlist == NULL) {
|
||||
cmdq_append(c, cmdq_get_error(error));
|
||||
free(error);
|
||||
} else if (item == NULL) {
|
||||
new_item = cmdq_get_command(cmdlist, NULL);
|
||||
if (item != NULL)
|
||||
cs = cmdq_get_state(item);
|
||||
|
||||
if (cdata->tree != NULL) {
|
||||
/* Explicit body: prompt inputs become the template argv. */
|
||||
ci.argc = argc;
|
||||
ci.argv = argv;
|
||||
new_item = cmd_invoke_get(cdata->tree, cs, &ci);
|
||||
if (item == NULL)
|
||||
cmdq_append(c, new_item);
|
||||
} else {
|
||||
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
|
||||
else
|
||||
cmdq_insert_after(item, new_item);
|
||||
} else if (argc > 0 && argv[0] != NULL) {
|
||||
/* No body: parse the submitted text as command language. */
|
||||
tree = cmd_parse_from_string(argv[0], &pi, &error);
|
||||
if (tree == NULL) {
|
||||
if (item == NULL)
|
||||
cmdq_append(c, cmdq_get_error(error));
|
||||
else
|
||||
cmdq_error(item, "%s", error);
|
||||
free(error);
|
||||
} else {
|
||||
new_item = cmd_invoke_get(tree, cs, NULL);
|
||||
cmd_parse_free(tree);
|
||||
if (item == NULL)
|
||||
cmdq_append(c, new_item);
|
||||
else
|
||||
cmdq_insert_after(item, new_item);
|
||||
}
|
||||
}
|
||||
cmd_free_argv(argc, argv);
|
||||
|
||||
if (c->prompt_inputcb != cmd_command_prompt_callback)
|
||||
return (1);
|
||||
/*
|
||||
* An incremental prompt fires its callback on every edit but must stay
|
||||
* open for further typing; only an explicit close (handled above) ends
|
||||
* it.
|
||||
*/
|
||||
if (cdata->flags & PROMPT_INCREMENTAL)
|
||||
return (PROMPT_CONTINUE);
|
||||
|
||||
out:
|
||||
if (item != NULL)
|
||||
if (item != NULL) {
|
||||
cdata->item = NULL;
|
||||
cmdq_continue(item);
|
||||
return (0);
|
||||
}
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -237,12 +300,17 @@ cmd_command_prompt_free(void *data)
|
||||
struct cmd_command_prompt_cdata *cdata = data;
|
||||
u_int i;
|
||||
|
||||
if (cdata->item != NULL) {
|
||||
cmdq_continue(cdata->item);
|
||||
cdata->item = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < cdata->count; i++) {
|
||||
free(cdata->prompts[i].prompt);
|
||||
free(cdata->prompts[i].input);
|
||||
}
|
||||
free(cdata->prompts);
|
||||
cmd_free_argv(cdata->argc, cdata->argv);
|
||||
args_make_commands_free(cdata->state);
|
||||
cmd_parse_free(cdata->tree);
|
||||
free(cdata);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-confirm-before.c,v 1.61 2026/06/24 10:55:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
@@ -33,8 +33,8 @@ static enum args_parse_type cmd_confirm_before_args_parse(struct args *,
|
||||
static enum cmd_retval cmd_confirm_before_exec(struct cmd *,
|
||||
struct cmdq_item *);
|
||||
|
||||
static int cmd_confirm_before_callback(struct client *, void *,
|
||||
const char *, int);
|
||||
static enum prompt_result cmd_confirm_before_callback(struct client *, void *,
|
||||
const char *, enum prompt_key_result);
|
||||
static void cmd_confirm_before_free(void *);
|
||||
|
||||
const struct cmd_entry cmd_confirm_before_entry = {
|
||||
@@ -51,7 +51,7 @@ const struct cmd_entry cmd_confirm_before_entry = {
|
||||
|
||||
struct cmd_confirm_before_data {
|
||||
struct cmdq_item *item;
|
||||
struct cmd_list *cmdlist;
|
||||
struct cmd_parse_tree *tree;
|
||||
u_char confirm_key;
|
||||
int default_yes;
|
||||
};
|
||||
@@ -70,13 +70,15 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_confirm_before_data *cdata;
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
char *new_prompt;
|
||||
char *new_prompt, *cause = NULL;
|
||||
const char *confirm_key, *prompt, *cmd;
|
||||
int wait = !args_has(args, 'b');
|
||||
int wait = !args_has(args, 'b'), n;
|
||||
|
||||
cdata = xcalloc(1, sizeof *cdata);
|
||||
cdata->cmdlist = args_make_commands_now(self, item, 0, 1);
|
||||
if (cdata->cmdlist == NULL) {
|
||||
cdata->tree = args_to_commands(self, item, 0, NULL, 1, &cause);
|
||||
if (cdata->tree == NULL) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
free(cdata);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
@@ -92,7 +94,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cdata->confirm_key = confirm_key[0];
|
||||
else {
|
||||
cmdq_error(item, "invalid confirm key");
|
||||
free(cdata);
|
||||
cmd_confirm_before_free(cdata);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
@@ -102,8 +104,9 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if ((prompt = args_get(args, 'p')) != NULL)
|
||||
xasprintf(&new_prompt, "%s ", prompt);
|
||||
else {
|
||||
cmd = cmd_get_entry(cmd_list_first(cdata->cmdlist))->name;
|
||||
xasprintf(&new_prompt, "Confirm '%s'? (%c/n) ", cmd,
|
||||
cmd = args_string(args, 0);
|
||||
n = strcspn(cmd, " ,");
|
||||
xasprintf(&new_prompt, "Confirm '%.*s'? (%c/n) ", n, cmd,
|
||||
cdata->confirm_key);
|
||||
}
|
||||
|
||||
@@ -117,12 +120,13 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_WAIT);
|
||||
}
|
||||
|
||||
static int
|
||||
static enum prompt_result
|
||||
cmd_confirm_before_callback(struct client *c, void *data, const char *s,
|
||||
__unused int done)
|
||||
__unused enum prompt_key_result key)
|
||||
{
|
||||
struct cmd_confirm_before_data *cdata = data;
|
||||
struct cmdq_item *item = cdata->item, *new_item;
|
||||
struct cmdq_state *cs;
|
||||
int retcode = 1;
|
||||
|
||||
if (c->flags & CLIENT_DEAD)
|
||||
@@ -135,11 +139,11 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s,
|
||||
retcode = 0;
|
||||
|
||||
if (item == NULL) {
|
||||
new_item = cmdq_get_command(cdata->cmdlist, NULL);
|
||||
new_item = cmd_invoke_get(cdata->tree, NULL, NULL);
|
||||
cmdq_append(c, new_item);
|
||||
} else {
|
||||
new_item = cmdq_get_command(cdata->cmdlist,
|
||||
cmdq_get_state(item));
|
||||
cs = cmdq_get_state(item);
|
||||
new_item = cmd_invoke_get(cdata->tree, cs, NULL);
|
||||
cmdq_insert_after(item, new_item);
|
||||
}
|
||||
|
||||
@@ -150,7 +154,7 @@ out:
|
||||
cmdq_get_client(item)->retval = retcode;
|
||||
cmdq_continue(item);
|
||||
}
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -158,6 +162,6 @@ cmd_confirm_before_free(void *data)
|
||||
{
|
||||
struct cmd_confirm_before_data *cdata = data;
|
||||
|
||||
cmd_list_free(cdata->cmdlist);
|
||||
cmd_parse_free(cdata->tree);
|
||||
free(cdata);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-copy-mode.c,v 1.54 2026/07/14 17:17:17 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -30,13 +30,13 @@ const struct cmd_entry cmd_copy_mode_entry = {
|
||||
.name = "copy-mode",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "deHMqSs:t:u", 0, 0, NULL },
|
||||
.usage = "[-deHMqSu] [-s src-pane] " CMD_TARGET_PANE_USAGE,
|
||||
.args = { "dekHMqSs:t:u", 0, 0, NULL },
|
||||
.usage = "[-dekHMqSu] [-s src-pane] " CMD_TARGET_PANE_USAGE,
|
||||
|
||||
.source = { 's', CMD_FIND_PANE, 0 },
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.flags = CMD_AFTERHOOK|CMD_READONLY,
|
||||
.exec = cmd_copy_mode_exec
|
||||
};
|
||||
|
||||
@@ -63,6 +63,8 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct client *c = cmdq_get_client(item);
|
||||
struct session *s;
|
||||
struct window_pane *wp = target->wp, *swp;
|
||||
u_int tty_ox, tty_oy, tty_sx, tty_sy;
|
||||
int line_numbers;
|
||||
|
||||
if (args_has(args, 'q')) {
|
||||
window_pane_reset_mode_all(wp);
|
||||
@@ -77,7 +79,8 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
|
||||
if (cmd_get_entry(self) == &cmd_clock_mode_entry) {
|
||||
window_pane_set_mode(wp, NULL, &window_clock_mode, NULL, NULL);
|
||||
window_pane_set_mode(wp, NULL, &window_clock_mode, item, NULL,
|
||||
NULL);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -85,17 +88,24 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
|
||||
swp = source->wp;
|
||||
else
|
||||
swp = wp;
|
||||
if (!window_pane_set_mode(wp, swp, &window_copy_mode, NULL, args)) {
|
||||
line_numbers = 1;
|
||||
if (event != NULL && KEYC_IS_MOUSE(event->key))
|
||||
line_numbers = 0;
|
||||
if (!window_pane_set_mode(wp, swp, &window_copy_mode, item, NULL,
|
||||
args)) {
|
||||
window_copy_set_line_numbers(wp, line_numbers);
|
||||
if (args_has(args, 'M'))
|
||||
window_copy_start_drag(c, &event->m);
|
||||
}
|
||||
} else
|
||||
window_copy_set_line_numbers(wp, line_numbers);
|
||||
if (args_has(args, 'u'))
|
||||
window_copy_pageup(wp, 0);
|
||||
if (args_has(args, 'd'))
|
||||
window_copy_pagedown(wp, 0, args_has(args, 'e'));
|
||||
if (args_has(args, 'S')) {
|
||||
tty_window_offset(&c->tty, &tty_ox, &tty_oy, &tty_sx, &tty_sy);
|
||||
window_copy_scroll(wp, c->tty.mouse_slider_mpos, event->m.y,
|
||||
args_has(args, 'e'));
|
||||
tty_oy, args_has(args, 'e'));
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-detach-client.c,v 1.39 2026/05/22 15:22:43 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -59,6 +59,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *source = cmdq_get_source(item);
|
||||
struct client *c = cmdq_get_client(item);
|
||||
struct client *tc = cmdq_get_target_client(item), *loop;
|
||||
struct session *s;
|
||||
enum msgtype msgtype;
|
||||
@@ -69,6 +70,13 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (c->flags & CLIENT_READONLY) {
|
||||
if (args_has(args, 's') || args_has(args, 'a') || c != tc) {
|
||||
cmdq_error(item, "client is read-only");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
if (args_has(args, 'P'))
|
||||
msgtype = MSG_DETACHKILL;
|
||||
else
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-display-menu.c,v 1.53 2026/08/31 07:46:55 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -92,7 +92,7 @@ cmd_display_menu_args_parse(struct args *args, u_int idx, __unused char **cause)
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_display_menu_get_pos(struct client *tc, struct cmdq_item *item,
|
||||
cmd_display_menu_get_popup_pos(struct client *tc, struct cmdq_item *item,
|
||||
struct args *args, u_int *px, u_int *py, u_int w, u_int h)
|
||||
{
|
||||
struct tty *tty = &tc->tty;
|
||||
@@ -126,6 +126,10 @@ cmd_display_menu_get_pos(struct client *tc, struct cmdq_item *item,
|
||||
format_add(ft, "popup_mouse_y", "%u", event->m.y);
|
||||
}
|
||||
|
||||
/* Position of the previous menu, for -x/-y L. */
|
||||
format_add(ft, "popup_last_x", "%u", target->w->menu_last_px);
|
||||
format_add(ft, "popup_last_y", "%u", target->w->menu_last_py + h);
|
||||
|
||||
/*
|
||||
* If there are any status lines, add this window position and the
|
||||
* status line position.
|
||||
@@ -238,6 +242,8 @@ cmd_display_menu_get_pos(struct client *tc, struct cmdq_item *item,
|
||||
xp = "#{popup_pane_left}";
|
||||
else if (strcmp(xp, "M") == 0)
|
||||
xp = "#{popup_mouse_centre_x}";
|
||||
else if (strcmp(xp, "L") == 0)
|
||||
xp = "#{popup_last_x}";
|
||||
else if (strcmp(xp, "W") == 0)
|
||||
xp = "#{popup_window_status_line_x}";
|
||||
p = format_expand(ft, xp);
|
||||
@@ -258,6 +264,8 @@ cmd_display_menu_get_pos(struct client *tc, struct cmdq_item *item,
|
||||
yp = "#{popup_pane_bottom}";
|
||||
else if (strcmp(yp, "M") == 0)
|
||||
yp = "#{popup_mouse_top}";
|
||||
else if (strcmp(yp, "L") == 0)
|
||||
yp = "#{popup_last_y}";
|
||||
else if (strcmp(yp, "S") == 0)
|
||||
yp = "#{popup_status_line_y}";
|
||||
else if (strcmp(yp, "W") == 0)
|
||||
@@ -280,6 +288,184 @@ cmd_display_menu_get_pos(struct client *tc, struct cmdq_item *item,
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_display_menu_get_menu_pos(struct client *tc, struct cmdq_item *item,
|
||||
struct args *args, u_int *px, u_int *py, u_int w, u_int h)
|
||||
{
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct key_event *event = cmdq_get_event(item);
|
||||
struct session *s = tc->session;
|
||||
struct winlink *wl = target->wl;
|
||||
struct window *window = target->w;
|
||||
struct window_pane *wp = target->wp;
|
||||
struct style_ranges *ranges = NULL;
|
||||
struct style_range *sr = NULL;
|
||||
const char *xp, *yp;
|
||||
char *p;
|
||||
u_int line, ox, oy, sx, sy, lines, position;
|
||||
long n, max_x, max_y, mouse_x = 0, mouse_y = 0;
|
||||
struct format_tree *ft;
|
||||
|
||||
max_x = window->sx > w ? window->sx - w : 0;
|
||||
max_y = window->sy > h ? window->sy - h : 0;
|
||||
|
||||
tty_window_offset(&tc->tty, &ox, &oy, &sx, &sy);
|
||||
|
||||
ft = format_create_from_target(item);
|
||||
if (event->m.valid) {
|
||||
mouse_x = event->m.x + ox;
|
||||
if (event->m.statusat == 0) {
|
||||
if (event->m.y >= event->m.statuslines)
|
||||
mouse_y = event->m.y - event->m.statuslines + oy;
|
||||
else
|
||||
mouse_y = oy;
|
||||
} else if (event->m.statusat > 0 &&
|
||||
event->m.y >= (u_int)event->m.statusat) {
|
||||
mouse_y = oy + sy - 1;
|
||||
} else
|
||||
mouse_y = event->m.y + oy;
|
||||
format_add(ft, "popup_mouse_x", "%ld", mouse_x);
|
||||
format_add(ft, "popup_mouse_y", "%ld", mouse_y);
|
||||
}
|
||||
|
||||
format_add(ft, "popup_last_x", "%u", window->menu_last_px);
|
||||
format_add(ft, "popup_last_y", "%u", window->menu_last_py + h);
|
||||
|
||||
lines = status_line_size(tc);
|
||||
position = options_get_number(s->options, "status-position");
|
||||
if (status_at_line(tc) != -1 && lines != 0) {
|
||||
for (line = 0; line < lines; line++) {
|
||||
ranges = &tc->status.entries[line].ranges;
|
||||
TAILQ_FOREACH(sr, ranges, entry) {
|
||||
if (sr->type != STYLE_RANGE_WINDOW)
|
||||
continue;
|
||||
if (sr->argument == (u_int)wl->idx)
|
||||
break;
|
||||
}
|
||||
if (sr != NULL)
|
||||
break;
|
||||
}
|
||||
if (sr != NULL) {
|
||||
format_add(ft, "popup_window_status_line_x", "%u",
|
||||
sr->start + ox);
|
||||
if (position == 0) {
|
||||
format_add(ft, "popup_window_status_line_y",
|
||||
"%u", h);
|
||||
} else {
|
||||
format_add(ft, "popup_window_status_line_y",
|
||||
"%u", window->sy);
|
||||
}
|
||||
}
|
||||
if (position == 0)
|
||||
format_add(ft, "popup_status_line_y", "%u", h);
|
||||
else
|
||||
format_add(ft, "popup_status_line_y", "%u", window->sy);
|
||||
}
|
||||
|
||||
format_add(ft, "popup_width", "%u", w);
|
||||
format_add(ft, "popup_height", "%u", h);
|
||||
|
||||
n = ((long)window->sx - 1) / 2 - w / 2;
|
||||
if (n < 0)
|
||||
format_add(ft, "popup_centre_x", "%u", 0);
|
||||
else
|
||||
format_add(ft, "popup_centre_x", "%ld", n);
|
||||
n = ((long)window->sy - 1) / 2 + h / 2;
|
||||
if (n >= window->sy)
|
||||
format_add(ft, "popup_centre_y", "%ld", max_y);
|
||||
else
|
||||
format_add(ft, "popup_centre_y", "%ld", n);
|
||||
|
||||
if (event->m.valid) {
|
||||
n = mouse_x - w / 2;
|
||||
if (n < 0)
|
||||
format_add(ft, "popup_mouse_centre_x", "%u", 0);
|
||||
else
|
||||
format_add(ft, "popup_mouse_centre_x", "%ld", n);
|
||||
n = mouse_y - h / 2;
|
||||
if (n + h >= window->sy)
|
||||
format_add(ft, "popup_mouse_centre_y", "%ld", max_y);
|
||||
else
|
||||
format_add(ft, "popup_mouse_centre_y", "%ld", n);
|
||||
n = mouse_y + h;
|
||||
if (n >= window->sy)
|
||||
format_add(ft, "popup_mouse_top", "%u", window->sy - 1);
|
||||
else
|
||||
format_add(ft, "popup_mouse_top", "%ld", n);
|
||||
n = mouse_y - h;
|
||||
if (n < 0)
|
||||
format_add(ft, "popup_mouse_bottom", "%u", 0);
|
||||
else
|
||||
format_add(ft, "popup_mouse_bottom", "%ld", n);
|
||||
}
|
||||
|
||||
n = wp->yoff + h;
|
||||
if (n >= window->sy)
|
||||
format_add(ft, "popup_pane_top", "%ld", max_y);
|
||||
else
|
||||
format_add(ft, "popup_pane_top", "%ld", n);
|
||||
format_add(ft, "popup_pane_bottom", "%u", wp->yoff + wp->sy);
|
||||
format_add(ft, "popup_pane_left", "%u", wp->xoff);
|
||||
n = (long)wp->xoff + wp->sx - w;
|
||||
if (n < 0)
|
||||
format_add(ft, "popup_pane_right", "%u", 0);
|
||||
else
|
||||
format_add(ft, "popup_pane_right", "%ld", n);
|
||||
|
||||
xp = args_get(args, 'x');
|
||||
if (xp == NULL || strcmp(xp, "C") == 0)
|
||||
xp = "#{popup_centre_x}";
|
||||
else if (strcmp(xp, "R") == 0)
|
||||
xp = "#{popup_pane_right}";
|
||||
else if (strcmp(xp, "P") == 0)
|
||||
xp = "#{popup_pane_left}";
|
||||
else if (strcmp(xp, "M") == 0)
|
||||
xp = "#{popup_mouse_centre_x}";
|
||||
else if (strcmp(xp, "L") == 0)
|
||||
xp = "#{popup_last_x}";
|
||||
else if (strcmp(xp, "W") == 0)
|
||||
xp = "#{popup_window_status_line_x}";
|
||||
p = format_expand(ft, xp);
|
||||
n = strtol(p, NULL, 10);
|
||||
if (n < 0)
|
||||
n = 0;
|
||||
if (n > max_x)
|
||||
n = max_x;
|
||||
*px = n;
|
||||
log_debug("%s: -x: %s = %s = %u (-w %u)", __func__, xp, p, *px, w);
|
||||
free(p);
|
||||
|
||||
yp = args_get(args, 'y');
|
||||
if (yp == NULL || strcmp(yp, "C") == 0)
|
||||
yp = "#{popup_centre_y}";
|
||||
else if (strcmp(yp, "P") == 0)
|
||||
yp = "#{popup_pane_bottom}";
|
||||
else if (strcmp(yp, "M") == 0)
|
||||
yp = "#{popup_mouse_top}";
|
||||
else if (strcmp(yp, "L") == 0)
|
||||
yp = "#{popup_last_y}";
|
||||
else if (strcmp(yp, "S") == 0)
|
||||
yp = "#{popup_status_line_y}";
|
||||
else if (strcmp(yp, "W") == 0)
|
||||
yp = "#{popup_window_status_line_y}";
|
||||
p = format_expand(ft, yp);
|
||||
n = strtol(p, NULL, 10);
|
||||
if (n < h)
|
||||
n = 0;
|
||||
else
|
||||
n -= h;
|
||||
if (n < 0)
|
||||
n = 0;
|
||||
if (n > max_y)
|
||||
n = max_y;
|
||||
*py = n;
|
||||
log_debug("%s: -y: %s = %s = %u (-h %u)", __func__, yp, p, *py, h);
|
||||
free(p);
|
||||
|
||||
format_free(ft);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
@@ -294,16 +480,12 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
||||
const char *border_style = args_get(args, 'S');
|
||||
const char *selected_style = args_get(args, 'H');
|
||||
enum box_lines lines = BOX_LINES_DEFAULT;
|
||||
char *title, *cause;
|
||||
char *title, *cause = NULL;
|
||||
int flags = 0, starting_choice = 0;
|
||||
u_int px, py, i, count = args_count(args);
|
||||
struct options *o = target->s->curw->window->options;
|
||||
struct options_entry *oe;
|
||||
|
||||
|
||||
if (tc->overlay_draw != NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
if (args_has(args, 'C')) {
|
||||
if (strcmp(args_get(args, 'C'), "-") == 0)
|
||||
starting_choice = -1;
|
||||
@@ -312,8 +494,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
||||
&cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "starting choice %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,8 +515,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
if (count - i < 2) {
|
||||
cmdq_error(item, "not enough arguments");
|
||||
menu_free(menu);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
key = args_string(args, i++);
|
||||
|
||||
@@ -347,17 +527,13 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
if (menu == NULL) {
|
||||
cmdq_error(item, "invalid menu arguments");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (menu->count == 0) {
|
||||
menu_free(menu);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
if (!cmd_display_menu_get_pos(tc, item, args, &px, &py, menu->width + 4,
|
||||
menu->count + 2)) {
|
||||
menu_free(menu);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
goto fail;
|
||||
}
|
||||
if (menu->count == 0)
|
||||
goto out;
|
||||
if (!cmd_display_menu_get_menu_pos(tc, item, args, &px, &py,
|
||||
menu->width + 4, menu->count + 2))
|
||||
goto out;
|
||||
|
||||
value = args_get(args, 'b');
|
||||
if (value != NULL) {
|
||||
@@ -366,8 +542,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
||||
&cause);
|
||||
if (lines == -1) {
|
||||
cmdq_error(item, "menu-border-lines %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,8 +552,17 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
||||
flags |= MENU_NOMOUSE;
|
||||
if (menu_display(menu, flags, starting_choice, item, px, py, tc, lines,
|
||||
style, selected_style, border_style, target, NULL, NULL) != 0)
|
||||
goto out;
|
||||
return (CMD_RETURN_NORMAL);
|
||||
return (CMD_RETURN_WAIT);
|
||||
|
||||
out:
|
||||
menu_free(menu);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
free(cause);
|
||||
menu_free(menu);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
@@ -393,7 +577,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
const char *style = args_get(args, 's');
|
||||
const char *border_style = args_get(args, 'S');
|
||||
char *cwd = NULL, *cause = NULL, **argv = NULL;
|
||||
char *title;
|
||||
char *title = NULL;
|
||||
int modify = popup_present(tc);
|
||||
int flags = -1, argc = 0;
|
||||
enum box_lines lines = BOX_LINES_DEFAULT;
|
||||
@@ -407,6 +591,8 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
server_client_clear_overlay(tc);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
if (tc->flags & CLIENT_CONTROL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (!modify && tc->overlay_draw != NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
@@ -417,8 +603,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
&cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "height %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,8 +613,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
&cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "width %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,8 +621,9 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
w = tty->sx;
|
||||
if (h > tty->sy)
|
||||
h = tty->sy;
|
||||
if (!cmd_display_menu_get_pos(tc, item, args, &px, &py, w, h))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (!cmd_display_menu_get_popup_pos(tc, item, args, &px, &py,
|
||||
w, h))
|
||||
goto out;
|
||||
|
||||
value = args_get(args, 'd');
|
||||
if (value != NULL)
|
||||
@@ -478,8 +663,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
&cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "popup-border-lines %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,22 +691,29 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
if (modify) {
|
||||
popup_modify(tc, title, style, border_style, lines, flags);
|
||||
free(title);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
goto out;
|
||||
}
|
||||
if (popup_display(flags, lines, item, px, py, w, h, env, shellcmd, argc,
|
||||
argv, cwd, title, tc, s, style, border_style, NULL, NULL) != 0) {
|
||||
cmd_free_argv(argc, argv);
|
||||
if (env != NULL)
|
||||
environ_free(env);
|
||||
free(cwd);
|
||||
free(title);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
if (env != NULL)
|
||||
argv, cwd, title, tc, s, style, border_style, NULL, NULL) != 0)
|
||||
goto out;
|
||||
environ_free(env);
|
||||
free(cwd);
|
||||
free(title);
|
||||
cmd_free_argv(argc, argv);
|
||||
return (CMD_RETURN_WAIT);
|
||||
|
||||
out:
|
||||
cmd_free_argv(argc, argv);
|
||||
environ_free(env);
|
||||
free(cwd);
|
||||
free(title);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
free(cause);
|
||||
cmd_free_argv(argc, argv);
|
||||
environ_free(env);
|
||||
free(cwd);
|
||||
free(title);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-display-message.c,v 1.65 2026/02/23 08:46:57 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
@@ -131,6 +131,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
if (args_has(args, 'a')) {
|
||||
format_each(ft, cmd_display_message_each, item);
|
||||
format_free(ft);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -155,6 +156,5 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
|
||||
free(msg);
|
||||
|
||||
format_free(ft);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -1,312 +0,0 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* Display panes on a client.
|
||||
*/
|
||||
|
||||
static enum args_parse_type cmd_display_panes_args_parse(struct args *,
|
||||
u_int, char **);
|
||||
static enum cmd_retval cmd_display_panes_exec(struct cmd *,
|
||||
struct cmdq_item *);
|
||||
|
||||
const struct cmd_entry cmd_display_panes_entry = {
|
||||
.name = "display-panes",
|
||||
.alias = "displayp",
|
||||
|
||||
.args = { "bd:Nt:", 0, 1, cmd_display_panes_args_parse },
|
||||
.usage = "[-bN] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
|
||||
|
||||
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
|
||||
.exec = cmd_display_panes_exec
|
||||
};
|
||||
|
||||
struct cmd_display_panes_data {
|
||||
struct cmdq_item *item;
|
||||
struct args_command_state *state;
|
||||
};
|
||||
|
||||
static enum args_parse_type
|
||||
cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx,
|
||||
__unused char **cause)
|
||||
{
|
||||
return (ARGS_PARSE_COMMANDS_OR_STRING);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_display_panes_draw_pane(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;
|
||||
struct window *w = wp->window;
|
||||
struct grid_cell fgc, bgc;
|
||||
u_int pane, idx, px, py, i, j, xoff, yoff, sx, sy;
|
||||
int colour, active_colour;
|
||||
char buf[16], lbuf[16], rbuf[16], *ptr;
|
||||
size_t len, llen, rlen;
|
||||
|
||||
if (wp->xoff + wp->sx <= ctx->ox ||
|
||||
wp->xoff >= ctx->ox + ctx->sx ||
|
||||
wp->yoff + wp->sy <= ctx->oy ||
|
||||
wp->yoff >= ctx->oy + ctx->sy)
|
||||
return;
|
||||
|
||||
if (wp->xoff >= ctx->ox && wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
|
||||
/* All visible. */
|
||||
xoff = wp->xoff - ctx->ox;
|
||||
sx = wp->sx;
|
||||
} else if (wp->xoff < ctx->ox &&
|
||||
wp->xoff + wp->sx > ctx->ox + ctx->sx) {
|
||||
/* Both left and right not visible. */
|
||||
xoff = 0;
|
||||
sx = ctx->sx;
|
||||
} else if (wp->xoff < ctx->ox) {
|
||||
/* Left not visible. */
|
||||
xoff = 0;
|
||||
sx = wp->sx - (ctx->ox - wp->xoff);
|
||||
} else {
|
||||
/* Right not visible. */
|
||||
xoff = wp->xoff - ctx->ox;
|
||||
sx = wp->sx - xoff;
|
||||
}
|
||||
if (wp->yoff >= ctx->oy && wp->yoff + wp->sy <= ctx->oy + ctx->sy) {
|
||||
/* All visible. */
|
||||
yoff = wp->yoff - ctx->oy;
|
||||
sy = wp->sy;
|
||||
} else if (wp->yoff < ctx->oy &&
|
||||
wp->yoff + wp->sy > ctx->oy + ctx->sy) {
|
||||
/* Both top and bottom not visible. */
|
||||
yoff = 0;
|
||||
sy = ctx->sy;
|
||||
} else if (wp->yoff < ctx->oy) {
|
||||
/* Top not visible. */
|
||||
yoff = 0;
|
||||
sy = wp->sy - (ctx->oy - wp->yoff);
|
||||
} else {
|
||||
/* Bottom not visible. */
|
||||
yoff = wp->yoff - ctx->oy;
|
||||
sy = wp->sy - yoff;
|
||||
}
|
||||
|
||||
if (ctx->statustop)
|
||||
yoff += ctx->statuslines;
|
||||
px = sx / 2;
|
||||
py = sy / 2;
|
||||
|
||||
if (window_pane_index(wp, &pane) != 0)
|
||||
fatalx("index not found");
|
||||
len = xsnprintf(buf, sizeof buf, "%u", pane);
|
||||
|
||||
if (sx < len)
|
||||
return;
|
||||
colour = options_get_number(oo, "display-panes-colour");
|
||||
active_colour = options_get_number(oo, "display-panes-active-colour");
|
||||
|
||||
memcpy(&fgc, &grid_default_cell, sizeof fgc);
|
||||
memcpy(&bgc, &grid_default_cell, sizeof bgc);
|
||||
if (w->active == wp) {
|
||||
fgc.fg = active_colour;
|
||||
bgc.bg = active_colour;
|
||||
} else {
|
||||
fgc.fg = colour;
|
||||
bgc.bg = colour;
|
||||
}
|
||||
|
||||
rlen = xsnprintf(rbuf, sizeof rbuf, "%ux%u", wp->sx, wp->sy);
|
||||
if (pane > 9 && pane < 35)
|
||||
llen = xsnprintf(lbuf, sizeof lbuf, "%c", 'a' + (pane - 10));
|
||||
else
|
||||
llen = 0;
|
||||
|
||||
if (sx < len * 6 || sy < 5) {
|
||||
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
|
||||
if (sx >= len + llen + 1) {
|
||||
len += llen + 1;
|
||||
tty_cursor(tty, xoff + px - len / 2, yoff + py);
|
||||
tty_putn(tty, buf, len, len);
|
||||
tty_putn(tty, " ", 1, 1);
|
||||
tty_putn(tty, lbuf, llen, llen);
|
||||
} else {
|
||||
tty_cursor(tty, xoff + px - len / 2, yoff + py);
|
||||
tty_putn(tty, buf, len, len);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
px -= len * 3;
|
||||
py -= 2;
|
||||
|
||||
tty_attributes(tty, &bgc, &grid_default_cell, NULL, NULL);
|
||||
for (ptr = buf; *ptr != '\0'; ptr++) {
|
||||
if (*ptr < '0' || *ptr > '9')
|
||||
continue;
|
||||
idx = *ptr - '0';
|
||||
|
||||
for (j = 0; j < 5; j++) {
|
||||
for (i = px; i < px + 5; i++) {
|
||||
tty_cursor(tty, xoff + i, yoff + py + j);
|
||||
if (window_clock_table[idx][j][i - px])
|
||||
tty_putc(tty, ' ');
|
||||
}
|
||||
}
|
||||
px += 6;
|
||||
}
|
||||
|
||||
if (sy <= 6)
|
||||
goto out;
|
||||
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
|
||||
if (rlen != 0 && sx >= rlen) {
|
||||
tty_cursor(tty, xoff + sx - rlen, yoff);
|
||||
tty_putn(tty, rbuf, rlen, rlen);
|
||||
}
|
||||
if (llen != 0) {
|
||||
tty_cursor(tty, xoff + sx / 2 + len * 3 - llen - 1,
|
||||
yoff + py + 5);
|
||||
tty_putn(tty, lbuf, llen, llen);
|
||||
}
|
||||
|
||||
out:
|
||||
tty_cursor(tty, 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_display_panes_draw(struct client *c, __unused void *data,
|
||||
struct screen_redraw_ctx *ctx)
|
||||
{
|
||||
struct window *w = c->session->curw->window;
|
||||
struct window_pane *wp;
|
||||
|
||||
log_debug("%s: %s @%u", __func__, c->name, w->id);
|
||||
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (window_pane_visible(wp))
|
||||
cmd_display_panes_draw_pane(ctx, wp);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_display_panes_free(__unused struct client *c, void *data)
|
||||
{
|
||||
struct cmd_display_panes_data *cdata = data;
|
||||
|
||||
if (cdata->item != NULL)
|
||||
cmdq_continue(cdata->item);
|
||||
args_make_commands_free(cdata->state);
|
||||
free(cdata);
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_display_panes_key(struct client *c, void *data, struct key_event *event)
|
||||
{
|
||||
struct cmd_display_panes_data *cdata = data;
|
||||
char *expanded, *error;
|
||||
struct cmdq_item *item = cdata->item, *new_item;
|
||||
struct cmd_list *cmdlist;
|
||||
struct window *w = c->session->curw->window;
|
||||
struct window_pane *wp;
|
||||
u_int index;
|
||||
key_code key;
|
||||
|
||||
if (event->key >= '0' && event->key <= '9')
|
||||
index = event->key - '0';
|
||||
else if ((event->key & KEYC_MASK_MODIFIERS) == 0) {
|
||||
key = (event->key & KEYC_MASK_KEY);
|
||||
if (key >= 'a' && key <= 'z')
|
||||
index = 10 + (key - 'a');
|
||||
else
|
||||
return (-1);
|
||||
} else
|
||||
return (-1);
|
||||
|
||||
wp = window_pane_at_index(w, index);
|
||||
if (wp == NULL)
|
||||
return (1);
|
||||
window_unzoom(w, 1);
|
||||
|
||||
xasprintf(&expanded, "%%%u", wp->id);
|
||||
|
||||
cmdlist = args_make_commands(cdata->state, 1, &expanded, &error);
|
||||
if (cmdlist == NULL) {
|
||||
cmdq_append(c, cmdq_get_error(error));
|
||||
free(error);
|
||||
} else if (item == NULL) {
|
||||
new_item = cmdq_get_command(cmdlist, NULL);
|
||||
cmdq_append(c, new_item);
|
||||
} else {
|
||||
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
|
||||
cmdq_insert_after(item, new_item);
|
||||
}
|
||||
|
||||
free(expanded);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct session *s = tc->session;
|
||||
u_int delay;
|
||||
char *cause;
|
||||
struct cmd_display_panes_data *cdata;
|
||||
int wait = !args_has(args, 'b');
|
||||
|
||||
if (tc->overlay_draw != NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
if (args_has(args, 'd')) {
|
||||
delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "delay %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
} else
|
||||
delay = options_get_number(s->options, "display-panes-time");
|
||||
|
||||
cdata = xcalloc(1, sizeof *cdata);
|
||||
if (wait)
|
||||
cdata->item = item;
|
||||
cdata->state = args_make_commands_prepare(self, item, 0,
|
||||
"select-pane -t \"%%%\"", wait, 0);
|
||||
|
||||
if (args_has(args, 'N')) {
|
||||
server_client_set_overlay(tc, delay, NULL, NULL,
|
||||
cmd_display_panes_draw, NULL, cmd_display_panes_free, NULL,
|
||||
cdata);
|
||||
} else {
|
||||
server_client_set_overlay(tc, delay, NULL, NULL,
|
||||
cmd_display_panes_draw, cmd_display_panes_key,
|
||||
cmd_display_panes_free, NULL, cdata);
|
||||
}
|
||||
|
||||
if (!wait)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
return (CMD_RETURN_WAIT);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-find-window.c,v 1.57 2026/07/14 17:17:17 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -109,7 +109,8 @@ cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
args_set(new_args, 'Z', NULL, 0);
|
||||
args_set(new_args, 'f', filter, 0);
|
||||
|
||||
window_pane_set_mode(wp, NULL, &window_tree_mode, target, new_args);
|
||||
window_pane_set_mode(wp, NULL, &window_tree_mode, item, target,
|
||||
new_args);
|
||||
args_free(new_args);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
35
cmd-find.c
35
cmd-find.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-find.c,v 1.87 2026/07/17 12:42:51 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -147,6 +147,18 @@ cmd_find_session_better(struct session *s, struct session *than, int flags)
|
||||
return (timercmp(&s->activity_time, &than->activity_time, >));
|
||||
}
|
||||
|
||||
/* Can this session be usefully targeted? */
|
||||
static int
|
||||
cmd_find_session_valid(struct session *s)
|
||||
{
|
||||
if (!session_alive(s) ||
|
||||
s->curw == NULL ||
|
||||
s->curw->window == NULL ||
|
||||
s->curw->window->active == NULL)
|
||||
return (0);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Find best session from a list, or all if list is NULL. */
|
||||
static struct session *
|
||||
cmd_find_best_session(struct session **slist, u_int ssize, int flags)
|
||||
@@ -159,11 +171,15 @@ cmd_find_best_session(struct session **slist, u_int ssize, int flags)
|
||||
s = NULL;
|
||||
if (slist != NULL) {
|
||||
for (i = 0; i < ssize; i++) {
|
||||
if (!cmd_find_session_valid(slist[i]))
|
||||
continue;
|
||||
if (cmd_find_session_better(slist[i], s, flags))
|
||||
s = slist[i];
|
||||
}
|
||||
} else {
|
||||
RB_FOREACH(s_loop, sessions, &sessions) {
|
||||
if (!cmd_find_session_valid(s_loop))
|
||||
continue;
|
||||
if (cmd_find_session_better(s_loop, s, flags))
|
||||
s = s_loop;
|
||||
}
|
||||
@@ -868,7 +884,7 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
|
||||
if (c->session != NULL) {
|
||||
cmd_find_clear_state(fs, flags);
|
||||
|
||||
fs->wp = server_client_get_pane(c);
|
||||
fs->wp = c->session->curw->window->active;
|
||||
if (fs->wp == NULL) {
|
||||
cmd_find_from_session(fs, c->session, flags);
|
||||
return (0);
|
||||
@@ -924,6 +940,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
|
||||
const char *target, enum cmd_find_type type, int flags)
|
||||
{
|
||||
struct mouse_event *m;
|
||||
struct client *c;
|
||||
struct cmd_find_state current;
|
||||
char *colon, *period, *copy = NULL, tmp[256];
|
||||
const char *session, *window, *pane, *s;
|
||||
@@ -990,6 +1007,20 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
|
||||
if (target == NULL || *target == '\0')
|
||||
goto current;
|
||||
|
||||
if (strcmp(target, "@") == 0 ||
|
||||
strcmp(target, "{active}") == 0 ||
|
||||
strcmp(target, "{current}") == 0) {
|
||||
c = cmdq_get_client(item);
|
||||
if (c == NULL || c->session == NULL) {
|
||||
cmdq_error(item, "no current client");
|
||||
goto error;
|
||||
}
|
||||
fs->wl = c->session->curw;
|
||||
fs->wp = c->session->curw->window->active;
|
||||
fs->w = c->session->curw->window;
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* Mouse target is a plain = or {mouse}. */
|
||||
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
|
||||
m = &cmdq_get_event(item)->m;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-if-shell.c,v 1.87 2026/08/25 06:04:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
@@ -53,8 +53,9 @@ const struct cmd_entry cmd_if_shell_entry = {
|
||||
};
|
||||
|
||||
struct cmd_if_shell_data {
|
||||
struct args_command_state *cmd_if;
|
||||
struct args_command_state *cmd_else;
|
||||
struct cmd_parse_tree *cmd_if;
|
||||
struct cmd_parse_tree *cmd_else;
|
||||
|
||||
|
||||
struct client *client;
|
||||
struct cmdq_item *item;
|
||||
@@ -76,45 +77,58 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct cmd_if_shell_data *cdata;
|
||||
struct cmdq_item *new_item;
|
||||
char *shellcmd;
|
||||
struct cmd_parse_tree *tree;
|
||||
char *shellcmd, *cause = NULL;
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct session *s = target->s;
|
||||
struct cmd_list *cmdlist;
|
||||
u_int count = args_count(args);
|
||||
u_int count = args_count(args), idx;
|
||||
int wait = !args_has(args, 'b');
|
||||
|
||||
shellcmd = format_single_from_target(item, args_string(args, 0));
|
||||
if (args_has(args, 'F')) {
|
||||
if (*shellcmd != '0' && *shellcmd != '\0')
|
||||
cmdlist = args_make_commands_now(self, item, 1, 0);
|
||||
idx = 1;
|
||||
else if (count == 3)
|
||||
cmdlist = args_make_commands_now(self, item, 2, 0);
|
||||
idx = 2;
|
||||
else {
|
||||
free(shellcmd);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
free(shellcmd);
|
||||
if (cmdlist == NULL)
|
||||
|
||||
tree = args_to_commands(self, item, idx, NULL, 0, &cause);
|
||||
if (tree == NULL) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
|
||||
}
|
||||
new_item = cmd_invoke_get(tree, cmdq_get_state(item), NULL);
|
||||
cmd_parse_free(tree);
|
||||
cmdq_insert_after(item, new_item);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
cdata = xcalloc(1, sizeof *cdata);
|
||||
|
||||
cdata->cmd_if = args_make_commands_prepare(self, item, 1, NULL, wait,
|
||||
0);
|
||||
cdata->cmd_if = args_to_commands(self, item, 1, NULL, 0, &cause);
|
||||
if (cdata->cmd_if == NULL) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
goto fail;
|
||||
}
|
||||
if (count == 3) {
|
||||
cdata->cmd_else = args_make_commands_prepare(self, item, 2,
|
||||
NULL, wait, 0);
|
||||
cdata->cmd_else = args_to_commands(self, item, 2, NULL, 0,
|
||||
&cause);
|
||||
if (cdata->cmd_else == NULL) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (wait) {
|
||||
if (!wait)
|
||||
cdata->client = tc;
|
||||
else {
|
||||
cdata->client = cmdq_get_client(item);
|
||||
cdata->item = item;
|
||||
} else
|
||||
cdata->client = tc;
|
||||
}
|
||||
if (cdata->client != NULL)
|
||||
cdata->client->references++;
|
||||
|
||||
@@ -123,15 +137,19 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cmd_if_shell_callback, cmd_if_shell_free, cdata, 0, -1,
|
||||
-1) == NULL) {
|
||||
cmdq_error(item, "failed to run command: %s", shellcmd);
|
||||
free(shellcmd);
|
||||
cmd_if_shell_free(cdata);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
free(shellcmd);
|
||||
|
||||
if (!wait)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
return (CMD_RETURN_WAIT);
|
||||
|
||||
fail:
|
||||
free(cause);
|
||||
free(shellcmd);
|
||||
cmd_if_shell_free(cdata);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -140,32 +158,22 @@ cmd_if_shell_callback(struct job *job)
|
||||
struct cmd_if_shell_data *cdata = job_get_data(job);
|
||||
struct client *c = cdata->client;
|
||||
struct cmdq_item *item = cdata->item, *new_item;
|
||||
struct args_command_state *state;
|
||||
struct cmd_list *cmdlist;
|
||||
char *error;
|
||||
struct cmd_parse_tree *tree;
|
||||
int status;
|
||||
|
||||
status = job_get_status(job);
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||
state = cdata->cmd_else;
|
||||
tree = cdata->cmd_else;
|
||||
else
|
||||
state = cdata->cmd_if;
|
||||
if (state == NULL)
|
||||
tree = cdata->cmd_if;
|
||||
if (tree == NULL)
|
||||
goto out;
|
||||
|
||||
cmdlist = args_make_commands(state, 0, NULL, &error);
|
||||
if (cmdlist == NULL) {
|
||||
if (cdata->item == NULL) {
|
||||
*error = toupper((u_char)*error);
|
||||
status_message_set(c, -1, 1, 0, 0, "%s", error);
|
||||
} else
|
||||
cmdq_error(cdata->item, "%s", error);
|
||||
free(error);
|
||||
} else if (item == NULL) {
|
||||
new_item = cmdq_get_command(cmdlist, NULL);
|
||||
if (item == NULL) {
|
||||
new_item = cmd_invoke_get(tree, NULL, NULL);
|
||||
cmdq_append(c, new_item);
|
||||
} else {
|
||||
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
|
||||
new_item = cmd_invoke_get(tree, cmdq_get_state(item), NULL);
|
||||
cmdq_insert_after(item, new_item);
|
||||
}
|
||||
|
||||
@@ -183,8 +191,8 @@ cmd_if_shell_free(void *data)
|
||||
server_client_unref(cdata->client);
|
||||
|
||||
if (cdata->cmd_else != NULL)
|
||||
args_make_commands_free(cdata->cmd_else);
|
||||
args_make_commands_free(cdata->cmd_if);
|
||||
|
||||
cmd_parse_free(cdata->cmd_else);
|
||||
if (cdata->cmd_if != NULL)
|
||||
cmd_parse_free(cdata->cmd_if);
|
||||
free(cdata);
|
||||
}
|
||||
|
||||
594
cmd-invoke.c
Normal file
594
cmd-invoke.c
Normal file
@@ -0,0 +1,594 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
#include "tmux-parser.h"
|
||||
|
||||
/* One frame in the parse tree stack. */
|
||||
struct cmd_invoke_frame {
|
||||
struct cmd_parse_tree *tree;
|
||||
struct cmd_parse_node *node;
|
||||
struct cmd_parse_node *next;
|
||||
struct cmd_parse_node *end;
|
||||
};
|
||||
|
||||
/* Shared state for a parsed command tree invocation. */
|
||||
struct cmd_invoke_state {
|
||||
u_int references;
|
||||
struct cmd_parse_tree *tree;
|
||||
struct cmd_parse_tree *current_tree;
|
||||
|
||||
struct cmd_invoke_frame *stack;
|
||||
u_int nstack;
|
||||
|
||||
enum cmd_retval last;
|
||||
int have_last;
|
||||
|
||||
int argc;
|
||||
char **argv;
|
||||
};
|
||||
|
||||
static void cmd_invoke_push(struct cmd_invoke_state *,
|
||||
struct cmd_parse_tree *, struct cmd_parse_node *,
|
||||
struct cmd_parse_node *, struct cmd_parse_node *);
|
||||
static struct cmd_parse_tree *cmd_invoke_tree(struct cmd_invoke_state *);
|
||||
static struct cmd_parse_node *cmd_invoke_next(struct cmd_invoke_state *);
|
||||
static void cmd_invoke_skip_sequence(struct cmd_invoke_state *);
|
||||
static int cmd_invoke_expand_string(struct cmdq_item *,
|
||||
struct cmd_invoke_state *, struct cmd_parse_node *,
|
||||
char **);
|
||||
static int cmd_invoke_assignment(struct cmdq_item *,
|
||||
struct cmd_invoke_state *, struct cmd_parse_node *);
|
||||
static int cmd_invoke_if(struct cmdq_item *, struct cmd_invoke_state *,
|
||||
struct cmd_parse_node *);
|
||||
static struct cmd *cmd_invoke_build_command(struct cmdq_item *,
|
||||
struct cmd_invoke_state *, struct cmd_parse_node *);
|
||||
static int cmd_invoke_read_only(struct cmdq_item *, struct cmd *);
|
||||
|
||||
/* Push a node's child range onto the traversal stack. */
|
||||
static void
|
||||
cmd_invoke_push(struct cmd_invoke_state *is, struct cmd_parse_tree *tree,
|
||||
struct cmd_parse_node *node, struct cmd_parse_node *first,
|
||||
struct cmd_parse_node *end)
|
||||
{
|
||||
u_int n = is->nstack + 1;
|
||||
|
||||
is->stack = xreallocarray(is->stack, n, sizeof *is->stack);
|
||||
is->stack[is->nstack].tree = cmd_parse_add_ref(tree);
|
||||
is->stack[is->nstack].node = node;
|
||||
is->stack[is->nstack].next = first;
|
||||
is->stack[is->nstack].end = end;
|
||||
is->nstack = n;
|
||||
}
|
||||
|
||||
static struct cmd_parse_tree *
|
||||
cmd_invoke_tree(struct cmd_invoke_state *is)
|
||||
{
|
||||
if (is->current_tree != NULL)
|
||||
return (is->current_tree);
|
||||
return (is->tree);
|
||||
}
|
||||
|
||||
/* Return the next node to execute from the traversal stack. */
|
||||
static struct cmd_parse_node *
|
||||
cmd_invoke_next(struct cmd_invoke_state *is)
|
||||
{
|
||||
struct cmd_invoke_frame *frame;
|
||||
struct cmd_parse_node *node;
|
||||
|
||||
for (;;) {
|
||||
if (is->nstack == 0)
|
||||
return (NULL);
|
||||
frame = &is->stack[is->nstack - 1];
|
||||
if (frame->next != NULL && frame->next != frame->end)
|
||||
break;
|
||||
cmd_parse_free(frame->tree);
|
||||
is->nstack--;
|
||||
}
|
||||
|
||||
node = frame->next;
|
||||
frame->next = cmd_parse_node_next(node);
|
||||
is->current_tree = frame->tree;
|
||||
return (node);
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip the rest of the active sequence after a command failure. Failure scope
|
||||
* is the active CMD_PARSE_SEQUENCE. Discard nested frames and advance only as
|
||||
* far as the end of that sequence.
|
||||
*/
|
||||
static void
|
||||
cmd_invoke_skip_sequence(struct cmd_invoke_state *is)
|
||||
{
|
||||
enum cmd_parse_node_type type;
|
||||
u_int i;
|
||||
|
||||
for (i = is->nstack; i > 0; i--) {
|
||||
type = cmd_parse_node_type(is->stack[i - 1].node);
|
||||
if (type == CMD_PARSE_SEQUENCE) {
|
||||
is->stack[i - 1].next = is->stack[i - 1].end;
|
||||
while (is->nstack > i)
|
||||
cmd_parse_free(is->stack[--is->nstack].tree);
|
||||
is->nstack = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
is->have_last = 0;
|
||||
}
|
||||
|
||||
/* Append a string to a dynamically allocated buffer. */
|
||||
static void
|
||||
cmd_invoke_append(char **buf, size_t *len, const char *s)
|
||||
{
|
||||
size_t slen;
|
||||
|
||||
if (s != NULL) {
|
||||
slen = strlen(s);
|
||||
*buf = xrealloc(*buf, *len + slen + 1);
|
||||
memcpy(*buf + *len, s, slen + 1);
|
||||
*len += slen;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look up an environment variable. */
|
||||
static const char *
|
||||
cmd_invoke_getenv(struct cmdq_item *item, const char *name)
|
||||
{
|
||||
struct client *c = cmdq_get_client(item);
|
||||
struct environ_entry *envent;
|
||||
|
||||
if (c != NULL && c->environ != NULL) {
|
||||
envent = environ_find(c->environ, name);
|
||||
if (envent != NULL && envent->value != NULL)
|
||||
return (envent->value);
|
||||
}
|
||||
envent = environ_find(global_environ, name);
|
||||
if (envent != NULL && envent->value != NULL)
|
||||
return (envent->value);
|
||||
return ("");
|
||||
}
|
||||
|
||||
/* Resolve a tilde expansion to a home directory. */
|
||||
static const char *
|
||||
cmd_invoke_tilde(const char *name)
|
||||
{
|
||||
struct passwd *pw;
|
||||
|
||||
if (name == NULL || *name == '\0')
|
||||
return (find_home());
|
||||
if ((pw = getpwnam(name)) == NULL)
|
||||
return ("");
|
||||
return (pw->pw_dir);
|
||||
}
|
||||
|
||||
/* Expand a parsed string node into an argv string. */
|
||||
static int
|
||||
cmd_invoke_expand_string(struct cmdq_item *item, struct cmd_invoke_state *is,
|
||||
struct cmd_parse_node *node, char **out)
|
||||
{
|
||||
struct cmd_parse_node *child;
|
||||
const char *s, *value;
|
||||
char *buf = NULL, *new;
|
||||
size_t len = 0;
|
||||
int i;
|
||||
|
||||
child = cmd_parse_node_first_child(node);
|
||||
while (child != NULL) {
|
||||
value = cmd_parse_node_value(child);
|
||||
switch (cmd_parse_node_type(child)) {
|
||||
case CMD_PARSE_TEXT:
|
||||
s = value;
|
||||
break;
|
||||
case CMD_PARSE_ENVIRONMENT:
|
||||
s = cmd_invoke_getenv(item, value);
|
||||
break;
|
||||
case CMD_PARSE_TILDE:
|
||||
s = cmd_invoke_tilde(value);
|
||||
break;
|
||||
default:
|
||||
fatalx("unexpected node type in string");
|
||||
}
|
||||
cmd_invoke_append(&buf, &len, s);
|
||||
child = cmd_parse_node_next(child);
|
||||
}
|
||||
if (buf == NULL)
|
||||
buf = xstrdup("");
|
||||
for (i = 0; i < is->argc; i++) {
|
||||
new = cmd_template_replace(buf, is->argv[i], i + 1);
|
||||
free(buf);
|
||||
buf = new;
|
||||
}
|
||||
*out = buf;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Execute an assignment node by updating the environment. */
|
||||
static int
|
||||
cmd_invoke_assignment(struct cmdq_item *item, struct cmd_invoke_state *is,
|
||||
struct cmd_parse_node *node)
|
||||
{
|
||||
struct cmd_parse_node *value;
|
||||
const char *name;
|
||||
char *expanded;
|
||||
int flags = 0;
|
||||
|
||||
value = cmd_parse_node_first_child(node);
|
||||
if (value == NULL)
|
||||
return (-1);
|
||||
if (cmd_invoke_expand_string(item, is, value, &expanded) != 0)
|
||||
return (-1);
|
||||
|
||||
name = cmd_parse_node_value(node);
|
||||
if (cmd_parse_node_type(node) == CMD_PARSE_HIDDEN_ASSIGN)
|
||||
flags |= ENVIRON_HIDDEN;
|
||||
environ_set(global_environ, name, flags, "%s", expanded);
|
||||
free(expanded);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Expand and evaluate a conditional expression. */
|
||||
static int
|
||||
cmd_invoke_is_true(struct cmdq_item *item,
|
||||
struct cmd_invoke_state *is, struct cmd_parse_node *node, int *result)
|
||||
{
|
||||
struct format_tree *ft;
|
||||
char *s, *expanded;
|
||||
|
||||
if (cmd_invoke_expand_string(item, is, node, &s) != 0)
|
||||
return (-1);
|
||||
ft = format_create_from_target(item);
|
||||
|
||||
expanded = format_expand(ft, s);
|
||||
*result = format_true(expanded);
|
||||
free(expanded);
|
||||
|
||||
format_free(ft);
|
||||
free(s);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Skip else branches. */
|
||||
static struct cmd_parse_node *
|
||||
cmd_invoke_if_branch_end(struct cmd_parse_node *first)
|
||||
{
|
||||
struct cmd_parse_node *node;
|
||||
|
||||
for (node = first; node != NULL; node = cmd_parse_node_next(node)) {
|
||||
switch (cmd_parse_node_type(node)) {
|
||||
case CMD_PARSE_ELIF:
|
||||
case CMD_PARSE_ELSE:
|
||||
return (node);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Select and queue the branch for a conditional node. */
|
||||
static int
|
||||
cmd_invoke_if(struct cmdq_item *item, struct cmd_invoke_state *is,
|
||||
struct cmd_parse_node *node)
|
||||
{
|
||||
struct cmd_parse_tree *tree = cmd_invoke_tree(is);
|
||||
struct cmd_parse_node *child, *first, *next;
|
||||
int r;
|
||||
|
||||
next = cmd_parse_node_first_child(node);
|
||||
if (next == NULL)
|
||||
return (0);
|
||||
first = cmd_parse_node_next(next);
|
||||
if (cmd_invoke_is_true(item, is, next, &r) != 0)
|
||||
return (-1);
|
||||
if (r) {
|
||||
next = cmd_invoke_if_branch_end(first);
|
||||
cmd_invoke_push(is, tree, node, first, next);
|
||||
return (0);
|
||||
}
|
||||
|
||||
for (child = first; child != NULL; child = cmd_parse_node_next(child)) {
|
||||
switch (cmd_parse_node_type(child)) {
|
||||
case CMD_PARSE_ELIF:
|
||||
next = cmd_parse_node_first_child(child);
|
||||
if (next == NULL)
|
||||
break;
|
||||
if (cmd_invoke_is_true(item, is, next, &r) != 0)
|
||||
return (-1);
|
||||
if (r) {
|
||||
next = cmd_parse_node_next(next);
|
||||
cmd_invoke_push(is, tree, child, next, NULL);
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
case CMD_PARSE_ELSE:
|
||||
next = cmd_parse_node_first_child(child);
|
||||
cmd_invoke_push(is, tree, child, next, NULL);
|
||||
return (0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Report an error from an invoke item. */
|
||||
static void
|
||||
cmd_invoke_error(struct cmdq_item *item, struct cmd_invoke_state *is,
|
||||
struct cmd_parse_node *node, const char *cause)
|
||||
{
|
||||
struct client *c = cmdq_get_client(item);
|
||||
struct cmd_parse_tree *tree = cmd_invoke_tree(is);
|
||||
const char *file = cmd_parse_file(tree);
|
||||
u_int line = cmd_parse_node_line(node);
|
||||
|
||||
if (c != NULL && (~c->flags & CLIENT_CONTROL || file == NULL)) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
return;
|
||||
}
|
||||
|
||||
if (file != NULL)
|
||||
cfg_add_cause("%s:%u: %s", file, line, cause);
|
||||
else
|
||||
cfg_add_cause("%s", cause);
|
||||
}
|
||||
|
||||
/* Build one command from a parsed command node. */
|
||||
static struct cmd *
|
||||
cmd_invoke_build_command(struct cmdq_item *item, struct cmd_invoke_state *is,
|
||||
struct cmd_parse_node *node)
|
||||
{
|
||||
struct cmd_parse_tree *tree = cmd_invoke_tree(is);
|
||||
struct cmd_parse_node *child;
|
||||
struct args_value *values = NULL;
|
||||
struct cmd *cmd;
|
||||
const char *file = cmd_parse_file(tree);
|
||||
u_int line = cmd_parse_node_line(node);
|
||||
int flags = cmd_parse_flags(tree);
|
||||
char *cause = NULL;
|
||||
u_int count = 0;
|
||||
|
||||
child = cmd_parse_node_first_child(node);
|
||||
while (child != NULL) {
|
||||
values = xreallocarray(values, count + 1, sizeof *values);
|
||||
memset(&values[count], 0, sizeof values[count]);
|
||||
switch (cmd_parse_node_type(child)) {
|
||||
case CMD_PARSE_STRING:
|
||||
values[count].type = ARGS_STRING;
|
||||
if (cmd_invoke_expand_string(item, is, child,
|
||||
&values[count].string) != 0)
|
||||
goto fail;
|
||||
break;
|
||||
case CMD_PARSE_COMMANDS:
|
||||
values[count].type = ARGS_COMMANDS;
|
||||
values[count].cmd = cmd_parse_from_node(tree, child);
|
||||
break;
|
||||
default:
|
||||
fatalx("unexpected node type in command");
|
||||
}
|
||||
count++;
|
||||
child = cmd_parse_node_next(child);
|
||||
}
|
||||
|
||||
cmd = cmd_parse(values, count, file, line, flags, &cause);
|
||||
if (cmd == NULL) {
|
||||
cmd_invoke_error(item, is, node, cause);
|
||||
free(cause);
|
||||
goto fail;
|
||||
}
|
||||
args_free_values(values, count);
|
||||
free(values);
|
||||
return (cmd);
|
||||
|
||||
fail:
|
||||
args_free_values(values, count);
|
||||
free(values);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_invoke_read_only(struct cmdq_item *item, struct cmd *cmd)
|
||||
{
|
||||
struct client *c = cmdq_get_client(item);
|
||||
const struct cmd_entry *entry = cmd_get_entry(cmd);
|
||||
|
||||
if (c == NULL || (~c->flags & CLIENT_READONLY))
|
||||
return (0);
|
||||
if (entry->flags & CMD_READONLY)
|
||||
return (0);
|
||||
cmdq_error(item, "client is read-only");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Create the first invoke queue item for a parsed tree. */
|
||||
struct cmdq_item *
|
||||
cmd_invoke_get(struct cmd_parse_tree *tree, struct cmdq_state *state,
|
||||
const struct cmd_invoke_input *input)
|
||||
{
|
||||
struct cmd_invoke_state *is;
|
||||
struct cmd_parse_node *root = cmd_parse_root(tree), *first;
|
||||
struct cmdq_item *item;
|
||||
struct cmd_invoke_input new_input = { 0 };
|
||||
int i;
|
||||
|
||||
if (input == NULL)
|
||||
input = &new_input;
|
||||
|
||||
is = xcalloc(1, sizeof *is);
|
||||
is->references = 1;
|
||||
is->tree = cmd_parse_add_ref(tree);
|
||||
|
||||
is->argc = input->argc;
|
||||
if (input->argc != 0) {
|
||||
is->argv = xreallocarray(NULL, input->argc, sizeof *is->argv);
|
||||
for (i = 0; i < input->argc; i++)
|
||||
is->argv[i] = xstrdup(input->argv[i]);
|
||||
}
|
||||
|
||||
first = cmd_parse_node_first_child(root);
|
||||
cmd_invoke_push(is, tree, root, first, NULL);
|
||||
|
||||
item = cmdq_get_invoke(is, state);
|
||||
cmd_invoke_state_free(is);
|
||||
return (item);
|
||||
}
|
||||
|
||||
/* Add a reference to shared invoke state. */
|
||||
struct cmd_invoke_state *
|
||||
cmd_invoke_state_add_ref(struct cmd_invoke_state *is)
|
||||
{
|
||||
is->references++;
|
||||
return (is);
|
||||
}
|
||||
|
||||
/* Release a reference to shared invoke state. */
|
||||
void
|
||||
cmd_invoke_state_free(struct cmd_invoke_state *is)
|
||||
{
|
||||
int i;
|
||||
u_int j;
|
||||
|
||||
if (is == NULL)
|
||||
return;
|
||||
if (--is->references != 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < is->argc; i++)
|
||||
free(is->argv[i]);
|
||||
free(is->argv);
|
||||
for (j = 0; j < is->nstack; j++)
|
||||
cmd_parse_free(is->stack[j].tree);
|
||||
|
||||
cmd_parse_free(is->tree);
|
||||
free(is->stack);
|
||||
free(is);
|
||||
}
|
||||
|
||||
/* Record the result from the last command item. */
|
||||
void
|
||||
cmd_invoke_result(struct cmd_invoke_state *is, enum cmd_retval retval)
|
||||
{
|
||||
is->last = retval;
|
||||
is->have_last = 1;
|
||||
}
|
||||
|
||||
/* Fire an invoke item and queue the next command plus continuation. */
|
||||
enum cmd_retval
|
||||
cmd_invoke_fire(struct cmdq_item *item, struct cmd_invoke_state *is)
|
||||
{
|
||||
struct cmd_parse_node *node, *first;
|
||||
struct cmd_parse_tree *tree, *alias;
|
||||
struct cmdq_item *new_item, *next;
|
||||
struct cmdq_state *state;
|
||||
struct client *c;
|
||||
struct cmd *cmd;
|
||||
const char *file;
|
||||
char *cause;
|
||||
int r;
|
||||
|
||||
if (is->have_last && is->last == CMD_RETURN_ERROR)
|
||||
cmd_invoke_skip_sequence(is);
|
||||
else
|
||||
is->have_last = 0;
|
||||
|
||||
for (;;) {
|
||||
node = cmd_invoke_next(is);
|
||||
if (node == NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
cmd_parse_log_node(__func__, node);
|
||||
|
||||
tree = cmd_invoke_tree(is);
|
||||
switch (cmd_parse_node_type(node)) {
|
||||
case CMD_PARSE_ROOT:
|
||||
case CMD_PARSE_SEQUENCE:
|
||||
first = cmd_parse_node_first_child(node);
|
||||
cmd_invoke_push(is, tree, node, first, NULL);
|
||||
break;
|
||||
case CMD_PARSE_ASSIGN:
|
||||
case CMD_PARSE_HIDDEN_ASSIGN:
|
||||
if (cmd_invoke_assignment(item, is, node) == 0)
|
||||
break;
|
||||
cmd_invoke_error(item, is, node, "bad assignment");
|
||||
cmd_invoke_skip_sequence(is);
|
||||
break;
|
||||
case CMD_PARSE_IF:
|
||||
if (cmd_invoke_if(item, is, node) == 0)
|
||||
break;
|
||||
cmd_invoke_error(item, is, node, "bad condition");
|
||||
cmd_invoke_skip_sequence(is);
|
||||
break;
|
||||
case CMD_PARSE_ELIF:
|
||||
case CMD_PARSE_ELSE:
|
||||
break;
|
||||
case CMD_PARSE_COMMAND:
|
||||
r = cmd_parse_expand_alias(tree, node, &alias, &cause);
|
||||
if (r == 1) {
|
||||
node = cmd_parse_root(alias);
|
||||
first = cmd_parse_node_first_child(node);
|
||||
cmd_invoke_push(is, alias, node, first, NULL);
|
||||
cmd_parse_free(alias);
|
||||
break;
|
||||
}
|
||||
if (r == -1) {
|
||||
c = cmdq_get_client(item);
|
||||
file = cmd_parse_file(tree);
|
||||
if (c != NULL &&
|
||||
(~c->flags & CLIENT_CONTROL || file == NULL))
|
||||
cmdq_error(item, "%s", cause);
|
||||
else
|
||||
cfg_add_cause("%s", cause);
|
||||
free(cause);
|
||||
cmd_invoke_skip_sequence(is);
|
||||
break;
|
||||
}
|
||||
|
||||
cmd = cmd_invoke_build_command(item, is, node);
|
||||
if (cmd == NULL) {
|
||||
cmd_invoke_skip_sequence(is);
|
||||
break;
|
||||
}
|
||||
if (cmd_invoke_read_only(item, cmd) != 0) {
|
||||
cmd_free(cmd);
|
||||
cmd_invoke_skip_sequence(is);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Queue one command followed by this walker. WAIT and
|
||||
* command-inserted items therefore run before resume.
|
||||
*/
|
||||
state = cmdq_get_state(item);
|
||||
new_item = cmdq_get_one_command(cmd, state, is);
|
||||
next = cmdq_get_invoke(is, state);
|
||||
cmdq_insert_after(item, next);
|
||||
cmdq_insert_after(item, new_item);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
case CMD_PARSE_STRING:
|
||||
case CMD_PARSE_COMMANDS:
|
||||
case CMD_PARSE_TEXT:
|
||||
case CMD_PARSE_ENVIRONMENT:
|
||||
case CMD_PARSE_TILDE:
|
||||
fatalx("unexpected node type");
|
||||
}
|
||||
}
|
||||
}
|
||||
449
cmd-join-pane.c
449
cmd-join-pane.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-join-pane.c,v 1.74 2026/08/03 20:29:52 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 George Nachman <tmux@georgester.com>
|
||||
@@ -30,6 +30,9 @@
|
||||
*/
|
||||
|
||||
static enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmdq_item *);
|
||||
static enum cmd_retval cmd_join_pane_mouse_update(struct cmdq_item *);
|
||||
static void cmd_join_pane_mouse_move(struct client *,
|
||||
struct mouse_event *);
|
||||
|
||||
const struct cmd_entry cmd_join_pane_entry = {
|
||||
.name = "join-pane",
|
||||
@@ -49,8 +52,10 @@ const struct cmd_entry cmd_move_pane_entry = {
|
||||
.name = "move-pane",
|
||||
.alias = "movep",
|
||||
|
||||
.args = { "bdfhvp:l:s:t:", 0, 0, NULL },
|
||||
.usage = "[-bdfhv] [-l size] " CMD_SRCDST_PANE_USAGE,
|
||||
.args = { "bdD::fhMvl:L::P:R::s:t:U::X:Y:z:", 0, 0, NULL },
|
||||
.usage = "[-bdfhMv] [-D lines] [-l size] [-L columns] [-P position] "
|
||||
"[-R columns] " CMD_SRCDST_PANE_USAGE " [-U lines] "
|
||||
"[-X x-position] [-Y y-position] [-z z-index]",
|
||||
|
||||
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
@@ -59,6 +64,348 @@ const struct cmd_entry cmd_move_pane_entry = {
|
||||
.exec = cmd_join_pane_exec
|
||||
};
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_join_pane_place(struct cmdq_item *item, struct winlink *wl,
|
||||
struct window_pane *wp, const char *position)
|
||||
{
|
||||
struct window *w = wl->window;
|
||||
struct layout_cell *lc = wp->layout_cell;
|
||||
struct window_pane *owp;
|
||||
int wx = w->sx, wy = w->sy;
|
||||
int px = lc->g.sx, py = lc->g.sy;
|
||||
int xoff = lc->g.xoff, yoff = lc->g.yoff;
|
||||
int border = 1;
|
||||
|
||||
if (window_pane_get_pane_lines(wp) == PANE_LINES_NONE)
|
||||
border = 0;
|
||||
|
||||
if (strcmp(position, "top-left") == 0) {
|
||||
xoff = border;
|
||||
yoff = border;
|
||||
} else if (strcmp(position, "top-centre") == 0 ||
|
||||
strcmp(position, "top-center") == 0) {
|
||||
xoff = (wx - px) / 2;
|
||||
yoff = border;
|
||||
} else if (strcmp(position, "top-right") == 0) {
|
||||
xoff = wx - px - border;
|
||||
yoff = border;
|
||||
} else if (strcmp(position, "centre-left") == 0 ||
|
||||
strcmp(position, "center-left") == 0) {
|
||||
xoff = border;
|
||||
yoff = (wy - py) / 2;
|
||||
} else if (strcmp(position, "centre") == 0 ||
|
||||
strcmp(position, "center") == 0) {
|
||||
xoff = (wx - px) / 2;
|
||||
yoff = (wy - py) / 2;
|
||||
} else if (strcmp(position, "centre-right") == 0 ||
|
||||
strcmp(position, "center-right") == 0) {
|
||||
xoff = wx - px - border;
|
||||
yoff = (wy - py) / 2;
|
||||
} else if (strcmp(position, "bottom-left") == 0) {
|
||||
xoff = border;
|
||||
yoff = wy - py - border;
|
||||
} else if (strcmp(position, "bottom-centre") == 0 ||
|
||||
strcmp(position, "bottom-center") == 0) {
|
||||
xoff = (wx - px) / 2;
|
||||
yoff = wy - py - border;
|
||||
} else if (strcmp(position, "bottom-right") == 0) {
|
||||
xoff = wx - px - border;
|
||||
yoff = wy - py - border;
|
||||
} else if (strcmp(position, "top-left-centre") == 0 ||
|
||||
strcmp(position, "top-left-center") == 0) {
|
||||
xoff = wx / 4 - px / 2;
|
||||
yoff = wy / 4 - py / 2;
|
||||
} else if (strcmp(position, "top-right-centre") == 0 ||
|
||||
strcmp(position, "top-right-center") == 0) {
|
||||
xoff = (3 * wx) / 4 - px / 2;
|
||||
yoff = wy / 4 - py / 2;
|
||||
} else if (strcmp(position, "bottom-left-centre") == 0 ||
|
||||
strcmp(position, "bottom-left-center") == 0) {
|
||||
xoff = wx / 4 - px / 2;
|
||||
yoff = (3 * wy) / 4 - py / 2;
|
||||
} else if (strcmp(position, "bottom-right-centre") == 0 ||
|
||||
strcmp(position, "bottom-right-center") == 0) {
|
||||
xoff = (3 * wx) / 4 - px / 2;
|
||||
yoff = (3 * wy) / 4 - py / 2;
|
||||
} else if (strcmp(position, "front") == 0) {
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
|
||||
} else if (strcmp(position, "back") == 0) {
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
TAILQ_FOREACH(owp, &w->z_index, zentry) {
|
||||
if (!window_pane_is_floating(owp))
|
||||
break;
|
||||
}
|
||||
if (owp != NULL)
|
||||
TAILQ_INSERT_BEFORE(owp, wp, zentry);
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
|
||||
} else if (strcmp(position, "forward") == 0) {
|
||||
owp = TAILQ_PREV(wp, window_panes_zindex, zentry);
|
||||
if (owp != NULL) {
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
TAILQ_INSERT_BEFORE(owp, wp, zentry);
|
||||
}
|
||||
} else if (strcmp(position, "backward") == 0) {
|
||||
owp = TAILQ_NEXT(wp, zentry);
|
||||
if (owp != NULL && window_pane_is_floating(owp)) {
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
TAILQ_INSERT_AFTER(&w->z_index, owp, wp, zentry);
|
||||
}
|
||||
} else if (strcmp(position, "forward-loop") == 0) {
|
||||
owp = TAILQ_PREV(wp, window_panes_zindex, zentry);
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
if (owp != NULL)
|
||||
TAILQ_INSERT_BEFORE(owp, wp, zentry);
|
||||
else {
|
||||
TAILQ_FOREACH(owp, &w->z_index, zentry) {
|
||||
if (!window_pane_is_floating(owp))
|
||||
break;
|
||||
}
|
||||
if (owp != NULL)
|
||||
TAILQ_INSERT_BEFORE(owp, wp, zentry);
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
|
||||
}
|
||||
} else if (strcmp(position, "backward-loop") == 0) {
|
||||
owp = TAILQ_NEXT(wp, zentry);
|
||||
if (owp != NULL && window_pane_is_floating(owp)) {
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
TAILQ_INSERT_AFTER(&w->z_index, owp, wp, zentry);
|
||||
} else {
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
|
||||
}
|
||||
} else {
|
||||
cmdq_error(item, "unknown position: %s", position);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (xoff != lc->g.xoff || yoff != lc->g.yoff) {
|
||||
lc->g.xoff = xoff;
|
||||
lc->g.yoff = yoff;
|
||||
layout_fix_panes(w, NULL);
|
||||
}
|
||||
redraw_invalidate_scene(w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_join_pane_move(struct cmdq_item *item, struct args *args,
|
||||
struct winlink *wl, struct window_pane *wp)
|
||||
{
|
||||
struct window *w = wl->window;
|
||||
struct layout_cell *lc = wp->layout_cell;
|
||||
const char *errstr, *argval;
|
||||
const char flags[] = { 'U', 'D', 'L', 'R' };
|
||||
char *cause = NULL, flag;
|
||||
int xoff = lc->g.xoff, yoff = lc->g.yoff, adjust;
|
||||
u_int i;
|
||||
enum pane_lines lines = window_pane_get_pane_lines(wp);
|
||||
|
||||
if (args_has(args, 'X')) {
|
||||
xoff = args_percentage_and_expand(args, 'X', -(int)w->sx,
|
||||
w->sx, w->sx, item, &cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "position %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (lines != PANE_LINES_NONE)
|
||||
xoff += 1;
|
||||
}
|
||||
if (args_has(args, 'Y')) {
|
||||
yoff = args_percentage_and_expand(args, 'Y', -(int)w->sy,
|
||||
w->sy, w->sy, item, &cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "position %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (lines != PANE_LINES_NONE)
|
||||
yoff += 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < nitems(flags); i++) {
|
||||
flag = flags[i];
|
||||
if (!args_has(args, flag))
|
||||
continue;
|
||||
|
||||
argval = args_get(args, flag);
|
||||
if (argval == NULL)
|
||||
argval = "1";
|
||||
adjust = strtonum(argval, INT_MIN, INT_MAX, &errstr);
|
||||
if (errstr != NULL) {
|
||||
cmdq_error(item, "offset %s", errstr);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (flag == 'U')
|
||||
yoff -= adjust;
|
||||
else if (flag == 'D')
|
||||
yoff += adjust;
|
||||
else if (flag == 'L')
|
||||
xoff -= adjust;
|
||||
else
|
||||
xoff += adjust;
|
||||
}
|
||||
|
||||
if (xoff != lc->g.xoff || yoff != lc->g.yoff) {
|
||||
lc->g.xoff = xoff;
|
||||
lc->g.yoff = yoff;
|
||||
layout_fix_panes(w, NULL);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_join_pane_mouse_update(struct cmdq_item *item)
|
||||
{
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct key_event *event = cmdq_get_event(item);
|
||||
struct client *c = cmdq_get_client(item);
|
||||
struct session *s = target->s;
|
||||
struct winlink *wl;
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
|
||||
if (!event->m.valid)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
wp = cmd_mouse_pane(&event->m, &s, &wl);
|
||||
if (wp == NULL || c == NULL || c->session != s)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (!window_pane_is_floating(wp))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
w = wl->window;
|
||||
window_redraw_active_switch(w, wp);
|
||||
window_set_active_pane(w, wp, 1);
|
||||
|
||||
c->tty.mouse_drag_update = cmd_join_pane_mouse_move;
|
||||
cmd_join_pane_mouse_move(c, &event->m);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_join_pane_mouse_move(struct client *c, struct mouse_event *m)
|
||||
{
|
||||
struct winlink *wl;
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
struct layout_cell *lc;
|
||||
int y, ly, x, lx;
|
||||
|
||||
wp = cmd_mouse_pane(m, NULL, &wl);
|
||||
if (wp == NULL) {
|
||||
c->tty.mouse_drag_update = NULL;
|
||||
return;
|
||||
}
|
||||
w = wl->window;
|
||||
lc = wp->layout_cell;
|
||||
|
||||
y = m->y + m->oy; x = m->x + m->ox;
|
||||
if (m->statusat == 0 && y >= (int)m->statuslines)
|
||||
y -= m->statuslines;
|
||||
else if (m->statusat > 0 && y >= m->statusat)
|
||||
y = m->statusat - 1;
|
||||
ly = m->ly + m->oy; lx = m->lx + m->ox;
|
||||
if (m->statusat == 0 && ly >= (int)m->statuslines)
|
||||
ly -= m->statuslines;
|
||||
else if (m->statusat > 0 && ly >= m->statusat)
|
||||
ly = m->statusat - 1;
|
||||
|
||||
if (x != lx || y != ly) {
|
||||
lc->g.xoff += x - lx;
|
||||
lc->g.yoff += y - ly;
|
||||
layout_fix_panes(w, NULL);
|
||||
server_redraw_window(w);
|
||||
server_redraw_window_borders(w);
|
||||
}
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_join_pane_zindex(struct cmdq_item *item, struct winlink *wl,
|
||||
struct window_pane *wp, const char *s)
|
||||
{
|
||||
struct window *w = wl->window;
|
||||
struct window_pane *owp;
|
||||
const char *errstr;
|
||||
u_int n, z;
|
||||
|
||||
z = strtonum(s, 0, UINT_MAX, &errstr);
|
||||
if (errstr != NULL) {
|
||||
cmdq_error(item, "z-index %s", errstr);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
|
||||
n = 0;
|
||||
TAILQ_FOREACH(owp, &w->z_index, zentry) {
|
||||
if (!window_pane_is_floating(owp))
|
||||
break;
|
||||
if (n >= z)
|
||||
break;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (owp != NULL)
|
||||
TAILQ_INSERT_BEFORE(owp, wp, zentry);
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
|
||||
|
||||
redraw_invalidate_scene(w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_join_pane_tile(struct cmdq_item *item, struct args *args, struct window *w,
|
||||
struct window_pane *wp)
|
||||
{
|
||||
struct layout_cell *lc = wp->layout_cell;
|
||||
|
||||
if (!window_pane_is_floating(wp)) {
|
||||
cmdq_error(item, "pane is not floating");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (w->flags & WINDOW_ZOOMED) {
|
||||
cmdq_error(item, "can't tile a pane while window is zoomed");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
lc->fg.sx = lc->g.sx;
|
||||
lc->fg.sy = lc->g.sy;
|
||||
lc->fg.xoff = lc->g.xoff;
|
||||
lc->fg.yoff = lc->g.yoff;
|
||||
|
||||
if (layout_insert_tile(w, lc) != 0) {
|
||||
cmdq_error(item, "no space for a new pane");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
lc->flags &= ~LAYOUT_CELL_FLOATING;
|
||||
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
|
||||
|
||||
if (!args_has(args, 'd'))
|
||||
window_set_active_pane(w, wp, 1);
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
redraw_invalidate_scene(w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
@@ -70,74 +417,71 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct winlink *src_wl, *dst_wl;
|
||||
struct window *src_w, *dst_w;
|
||||
struct window_pane *src_wp, *dst_wp;
|
||||
const char *s;
|
||||
char *cause = NULL;
|
||||
int size, dst_idx;
|
||||
int flags;
|
||||
enum layout_type type;
|
||||
int flags = 0, dst_idx;
|
||||
struct layout_cell *lc;
|
||||
u_int curval = 0;
|
||||
|
||||
dst_s = target->s;
|
||||
dst_wl = target->wl;
|
||||
dst_wp = target->wp;
|
||||
dst_w = dst_wl->window;
|
||||
dst_idx = dst_wl->idx;
|
||||
|
||||
if (cmd_get_entry(self) == &cmd_move_pane_entry) {
|
||||
if (args_has(args, 'M'))
|
||||
return (cmd_join_pane_mouse_update(item));
|
||||
if (args_has(args, 'P') ||
|
||||
args_has(args, 'z') ||
|
||||
args_has(args, 'X') ||
|
||||
args_has(args, 'Y') ||
|
||||
args_has(args, 'U') ||
|
||||
args_has(args, 'D') ||
|
||||
args_has(args, 'L') ||
|
||||
args_has(args, 'R')) {
|
||||
if (!window_pane_is_floating(dst_wp)) {
|
||||
cmdq_error(item, "pane is not floating");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
server_unzoom_window(dst_w);
|
||||
if ((s = args_get(args, 'P')) != NULL)
|
||||
return (cmd_join_pane_place(item, dst_wl, dst_wp, s));
|
||||
if ((s = args_get(args, 'z')) != NULL)
|
||||
return (cmd_join_pane_zindex(item, dst_wl, dst_wp, s));
|
||||
return (cmd_join_pane_move(item, args, dst_wl, dst_wp));
|
||||
}
|
||||
}
|
||||
|
||||
src_wl = source->wl;
|
||||
src_wp = source->wp;
|
||||
src_w = src_wl->window;
|
||||
|
||||
if (src_wp == src_w->modal || dst_wp == dst_w->modal) {
|
||||
cmdq_error(item, "pane is modal");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
server_unzoom_window(dst_w);
|
||||
server_unzoom_window(src_w);
|
||||
|
||||
if (src_wp == dst_wp) {
|
||||
if (window_pane_is_floating(src_wp))
|
||||
return (cmd_join_pane_tile(item, args, src_w, src_wp));
|
||||
cmdq_error(item, "source and target panes must be different");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
type = LAYOUT_TOPBOTTOM;
|
||||
if (args_has(args, 'h'))
|
||||
type = LAYOUT_LEFTRIGHT;
|
||||
|
||||
/* If the 'p' flag is dropped then this bit can be moved into 'l'. */
|
||||
if (args_has(args, 'l') || args_has(args, 'p')) {
|
||||
if (args_has(args, 'f')) {
|
||||
if (type == LAYOUT_TOPBOTTOM)
|
||||
curval = dst_w->sy;
|
||||
else
|
||||
curval = dst_w->sx;
|
||||
} else {
|
||||
if (type == LAYOUT_TOPBOTTOM)
|
||||
curval = dst_wp->sy;
|
||||
else
|
||||
curval = dst_wp->sx;
|
||||
}
|
||||
}
|
||||
|
||||
size = -1;
|
||||
if (args_has(args, 'l')) {
|
||||
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
|
||||
item, &cause);
|
||||
} else if (args_has(args, 'p')) {
|
||||
size = args_strtonum_and_expand(args, 'l', 0, 100, item,
|
||||
&cause);
|
||||
if (cause == NULL)
|
||||
size = curval * size / 100;
|
||||
}
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "size %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
flags |= SPAWN_HORIZONTAL;
|
||||
if (args_has(args, 'b'))
|
||||
flags |= SPAWN_BEFORE;
|
||||
if (args_has(args, 'f'))
|
||||
flags |= SPAWN_FULLSIZE;
|
||||
|
||||
lc = layout_split_pane(dst_wp, type, size, flags);
|
||||
if (lc == NULL) {
|
||||
cmdq_error(item, "create pane failed: pane too small");
|
||||
lc = layout_get_tiled_cell(item, args, dst_w, dst_wp, flags, &cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "size or position %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
@@ -146,14 +490,18 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
server_client_remove_pane(src_wp);
|
||||
window_lost_pane(src_w, src_wp);
|
||||
TAILQ_REMOVE(&src_w->panes, src_wp, entry);
|
||||
TAILQ_REMOVE(&src_w->z_index, src_wp, zentry);
|
||||
|
||||
src_wp->window = dst_w;
|
||||
options_set_parent(src_wp->options, dst_w->options);
|
||||
src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||
if (flags & SPAWN_BEFORE)
|
||||
if (flags & SPAWN_BEFORE) {
|
||||
TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry);
|
||||
else
|
||||
TAILQ_INSERT_BEFORE(dst_wp, src_wp, zentry);
|
||||
} else {
|
||||
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
|
||||
TAILQ_INSERT_AFTER(&dst_w->z_index, dst_wp, src_wp, zentry);
|
||||
}
|
||||
layout_assign_pane(lc, src_wp, 0);
|
||||
colour_palette_from_option(&src_wp->palette, src_wp->options);
|
||||
|
||||
@@ -170,11 +518,12 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
} else
|
||||
server_status_session(dst_s);
|
||||
|
||||
if (window_count_panes(src_w) == 0)
|
||||
window_fire_pane_moved(src_wp, src_w, src_wl->idx, dst_w, dst_idx);
|
||||
if (window_count_panes(src_w, 1) == 0)
|
||||
server_kill_window(src_w, 1);
|
||||
else
|
||||
notify_window("window-layout-changed", src_w);
|
||||
notify_window("window-layout-changed", dst_w);
|
||||
events_fire_window("window-layout-changed", src_w);
|
||||
events_fire_window("window-layout-changed", dst_w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-kill-pane.c,v 1.34 2026/06/09 21:22:22 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -27,13 +27,17 @@
|
||||
*/
|
||||
|
||||
static enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmdq_item *);
|
||||
static enum cmd_retval cmd_kill_pane_all(struct cmdq_item *, const char *);
|
||||
static int cmd_kill_pane_filter(struct cmdq_item *,
|
||||
struct session *, struct winlink *,
|
||||
struct window_pane *, const char *);
|
||||
|
||||
const struct cmd_entry cmd_kill_pane_entry = {
|
||||
.name = "kill-pane",
|
||||
.alias = "killp",
|
||||
|
||||
.args = { "at:", 0, 0, NULL },
|
||||
.usage = "[-a] " CMD_TARGET_PANE_USAGE,
|
||||
.args = { "af:t:", 0, 0, NULL },
|
||||
.usage = "[-a] [-f filter] " CMD_TARGET_PANE_USAGE,
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
@@ -46,22 +50,66 @@ cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct winlink *wl = target->wl;
|
||||
struct window_pane *loopwp, *tmpwp, *wp = target->wp;
|
||||
struct window_pane *wp = target->wp;
|
||||
const char *filter = args_get(args, 'f');
|
||||
|
||||
if (filter != NULL && !args_has(args, 'a')) {
|
||||
cmdq_error(item, "-f only valid with -a");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (args_has(args, 'a'))
|
||||
return (cmd_kill_pane_all(item, filter));
|
||||
|
||||
if (wp == NULL) {
|
||||
cmdq_error(item, "no active pane to kill");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
server_kill_pane(wp);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_kill_pane_all(struct cmdq_item *item, const char *filter)
|
||||
{
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct session *s = target->s;
|
||||
struct winlink *wl = target->wl;
|
||||
struct window_pane *wp = target->wp;
|
||||
struct window_pane *loopwp, *tmpwp;
|
||||
|
||||
if (args_has(args, 'a')) {
|
||||
server_unzoom_window(wl->window);
|
||||
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
|
||||
if (loopwp == wp)
|
||||
continue;
|
||||
if (!cmd_kill_pane_filter(item, s, wl, loopwp, filter))
|
||||
continue;
|
||||
server_client_remove_pane(loopwp);
|
||||
layout_close_pane(loopwp);
|
||||
window_remove_pane(wl->window, loopwp);
|
||||
}
|
||||
server_redraw_window(wl->window);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
server_kill_pane(wp);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_kill_pane_filter(struct cmdq_item *item, struct session *s,
|
||||
struct winlink *wl, struct window_pane *wp, const char *filter)
|
||||
{
|
||||
struct format_tree *ft;
|
||||
char *expanded;
|
||||
int flag;
|
||||
|
||||
if (filter == NULL)
|
||||
return (1);
|
||||
|
||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||
format_defaults(ft, NULL, s, wl, wp);
|
||||
|
||||
expanded = format_expand(ft, filter);
|
||||
flag = format_true(expanded);
|
||||
free(expanded);
|
||||
|
||||
format_free(ft);
|
||||
return (flag);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-kill-server.c,v 1.20 2021/08/21 10:22:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-kill-session.c,v 1.31 2026/06/09 12:57:40 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
@@ -28,13 +30,16 @@
|
||||
*/
|
||||
|
||||
static enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmdq_item *);
|
||||
static enum cmd_retval cmd_kill_session_all(struct cmdq_item *, const char *);
|
||||
static int cmd_kill_session_filter(struct cmdq_item *,
|
||||
struct session *, const char *);
|
||||
|
||||
const struct cmd_entry cmd_kill_session_entry = {
|
||||
.name = "kill-session",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "aCt:", 0, 0, NULL },
|
||||
.usage = "[-aC] " CMD_TARGET_SESSION_USAGE,
|
||||
.args = { "aCgf:t:", 0, 0, NULL },
|
||||
.usage = "[-aCg] [-f filter] " CMD_TARGET_SESSION_USAGE,
|
||||
|
||||
.target = { 't', CMD_FIND_SESSION, 0 },
|
||||
|
||||
@@ -48,7 +53,14 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct session *s = target->s, *sloop, *stmp;
|
||||
struct session_group *sg;
|
||||
struct winlink *wl;
|
||||
const char *filter = args_get(args, 'f');
|
||||
|
||||
if (filter != NULL && (!args_has(args, 'a') || args_has(args, 'C'))) {
|
||||
cmdq_error(item, "-f only valid with -a");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (args_has(args, 'C')) {
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
@@ -56,16 +68,56 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
wl->flags &= ~WINLINK_ALERTFLAGS;
|
||||
}
|
||||
server_redraw_session(s);
|
||||
} else if (args_has(args, 'a')) {
|
||||
RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) {
|
||||
if (sloop != s) {
|
||||
} else if (args_has(args, 'a'))
|
||||
return (cmd_kill_session_all(item, filter));
|
||||
else if (args_has(args, 'g') &&
|
||||
(sg = session_group_contains(s)) != NULL) {
|
||||
TAILQ_FOREACH_SAFE(sloop, &sg->sessions, gentry, stmp) {
|
||||
server_destroy_session(sloop);
|
||||
session_destroy(sloop, 1, __func__);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
server_destroy_session(s);
|
||||
session_destroy(s, 1, __func__);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_kill_session_all(struct cmdq_item *item, const char *filter)
|
||||
{
|
||||
struct session *s = cmdq_get_target(item)->s;
|
||||
struct session *sloop, *stmp;
|
||||
|
||||
RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) {
|
||||
if (sloop == s)
|
||||
continue;
|
||||
if (!cmd_kill_session_filter(item, sloop, filter))
|
||||
continue;
|
||||
server_destroy_session(sloop);
|
||||
session_destroy(sloop, 1, __func__);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_kill_session_filter(struct cmdq_item *item, struct session *s,
|
||||
const char *filter)
|
||||
{
|
||||
struct format_tree *ft;
|
||||
char *expanded;
|
||||
int flag;
|
||||
|
||||
if (filter == NULL)
|
||||
return (1);
|
||||
|
||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||
format_defaults(ft, NULL, s, NULL, NULL);
|
||||
|
||||
expanded = format_expand(ft, filter);
|
||||
flag = format_true(expanded);
|
||||
free(expanded);
|
||||
|
||||
format_free(ft);
|
||||
return (flag);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-kill-window.c,v 1.30 2026/06/09 12:57:40 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
@@ -25,13 +27,16 @@
|
||||
*/
|
||||
|
||||
static enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmdq_item *);
|
||||
static enum cmd_retval cmd_kill_window_all(struct cmdq_item *, const char *);
|
||||
static int cmd_kill_window_filter(struct cmdq_item *,
|
||||
struct session *, struct winlink *, const char *);
|
||||
|
||||
const struct cmd_entry cmd_kill_window_entry = {
|
||||
.name = "kill-window",
|
||||
.alias = "killw",
|
||||
|
||||
.args = { "at:", 0, 0, NULL },
|
||||
.usage = "[-a] " CMD_TARGET_WINDOW_USAGE,
|
||||
.args = { "af:t:", 0, 0, NULL },
|
||||
.usage = "[-a] [-f filter] " CMD_TARGET_WINDOW_USAGE,
|
||||
|
||||
.target = { 't', CMD_FIND_WINDOW, 0 },
|
||||
|
||||
@@ -57,10 +62,15 @@ cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct winlink *wl = target->wl, *loop;
|
||||
struct winlink *wl = target->wl;
|
||||
struct window *w = wl->window;
|
||||
struct session *s = target->s;
|
||||
u_int found;
|
||||
const char *filter = args_get(args, 'f');
|
||||
|
||||
if (filter != NULL && !args_has(args, 'a')) {
|
||||
cmdq_error(item, "-f only valid with -a");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (cmd_get_entry(self) == &cmd_unlink_window_entry) {
|
||||
if (!args_has(args, 'k') && !session_is_linked(s, w)) {
|
||||
@@ -72,7 +82,22 @@ cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (args_has(args, 'a')) {
|
||||
if (args_has(args, 'a'))
|
||||
return (cmd_kill_window_all(item, filter));
|
||||
|
||||
server_kill_window(wl->window, 1);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_kill_window_all(struct cmdq_item *item, const char *filter)
|
||||
{
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct session *s = target->s;
|
||||
struct winlink *wl = target->wl;
|
||||
struct winlink *loop;
|
||||
u_int found, kill_current;
|
||||
|
||||
if (RB_PREV(winlinks, &s->windows, wl) == NULL &&
|
||||
RB_NEXT(winlinks, &s->windows, wl) == NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
@@ -81,7 +106,8 @@ cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
do {
|
||||
found = 0;
|
||||
RB_FOREACH(loop, winlinks, &s->windows) {
|
||||
if (loop->window != wl->window) {
|
||||
if (loop->window != wl->window &&
|
||||
cmd_kill_window_filter(item, s, loop, filter)) {
|
||||
server_kill_window(loop->window, 0);
|
||||
found++;
|
||||
break;
|
||||
@@ -90,21 +116,42 @@ cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
} while (found != 0);
|
||||
|
||||
/*
|
||||
* If the current window appears in the session more than once,
|
||||
* kill it as well.
|
||||
* If the current window appears in the session more than once, kill it
|
||||
* as well if it matches the filter.
|
||||
*/
|
||||
found = 0;
|
||||
found = kill_current = 0;
|
||||
RB_FOREACH(loop, winlinks, &s->windows) {
|
||||
if (loop->window == wl->window)
|
||||
if (loop->window == wl->window) {
|
||||
found++;
|
||||
if (cmd_kill_window_filter(item, s, loop, filter))
|
||||
kill_current = 1;
|
||||
}
|
||||
if (found > 1)
|
||||
}
|
||||
if (kill_current && found > 1)
|
||||
server_kill_window(wl->window, 0);
|
||||
|
||||
server_renumber_all();
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
server_kill_window(wl->window, 1);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_kill_window_filter(struct cmdq_item *item, struct session *s,
|
||||
struct winlink *wl, const char *filter)
|
||||
{
|
||||
struct format_tree *ft;
|
||||
char *expanded;
|
||||
int flag;
|
||||
|
||||
if (filter == NULL)
|
||||
return (1);
|
||||
|
||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||
format_defaults(ft, NULL, s, wl, NULL);
|
||||
|
||||
expanded = format_expand(ft, filter);
|
||||
flag = format_true(expanded);
|
||||
free(expanded);
|
||||
|
||||
format_free(ft);
|
||||
return (flag);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-buffers.c,v 1.41 2026/02/27 08:25:12 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -36,8 +36,8 @@ const struct cmd_entry cmd_list_buffers_entry = {
|
||||
.name = "list-buffers",
|
||||
.alias = "lsb",
|
||||
|
||||
.args = { "F:f:", 0, 0, NULL },
|
||||
.usage = "[-F format] [-f filter]",
|
||||
.args = { "F:f:O:r", 0, 0, NULL },
|
||||
.usage = "[-F format] [-f filter] [-O order]",
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.exec = cmd_list_buffers_exec
|
||||
@@ -47,20 +47,29 @@ static enum cmd_retval
|
||||
cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct paste_buffer *pb;
|
||||
struct paste_buffer **l;
|
||||
struct format_tree *ft;
|
||||
const char *template, *filter;
|
||||
char *line, *expanded;
|
||||
int flag;
|
||||
u_int i, n;
|
||||
struct sort_criteria sort_crit;
|
||||
|
||||
if ((template = args_get(args, 'F')) == NULL)
|
||||
template = LIST_BUFFERS_TEMPLATE;
|
||||
filter = args_get(args, 'f');
|
||||
|
||||
pb = NULL;
|
||||
while ((pb = paste_walk(pb)) != NULL) {
|
||||
sort_crit.order = sort_order_from_string(args_get(args, 'O'));
|
||||
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
|
||||
cmdq_error(item, "invalid sort order");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
sort_crit.reversed = args_has(args, 'r');
|
||||
|
||||
l = sort_get_buffers(&n, &sort_crit);
|
||||
for (i = 0; i < n; i++) {
|
||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||
format_defaults_paste_buffer(ft, pb);
|
||||
format_defaults_paste_buffer(ft, l[i]);
|
||||
|
||||
if (filter != NULL) {
|
||||
expanded = format_expand(ft, filter);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-clients.c,v 1.42 2026/02/27 08:25:12 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -41,8 +41,8 @@ const struct cmd_entry cmd_list_clients_entry = {
|
||||
.name = "list-clients",
|
||||
.alias = "lsc",
|
||||
|
||||
.args = { "F:f:t:", 0, 0, NULL },
|
||||
.usage = "[-F format] [-f filter] " CMD_TARGET_SESSION_USAGE,
|
||||
.args = { "F:f:O:rt:", 0, 0, NULL },
|
||||
.usage = "[-F format] [-f filter] [-O order]" CMD_TARGET_SESSION_USAGE,
|
||||
|
||||
.target = { 't', CMD_FIND_SESSION, 0 },
|
||||
|
||||
@@ -55,13 +55,14 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct client *c;
|
||||
struct client **l;
|
||||
struct session *s;
|
||||
struct format_tree *ft;
|
||||
const char *template, *filter;
|
||||
u_int idx;
|
||||
u_int i, n;
|
||||
char *line, *expanded;
|
||||
int flag;
|
||||
struct sort_criteria sort_crit;
|
||||
|
||||
if (args_has(args, 't'))
|
||||
s = target->s;
|
||||
@@ -72,14 +73,21 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
|
||||
template = LIST_CLIENTS_TEMPLATE;
|
||||
filter = args_get(args, 'f');
|
||||
|
||||
idx = 0;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (c->session == NULL || (s != NULL && s != c->session))
|
||||
sort_crit.order = sort_order_from_string(args_get(args, 'O'));
|
||||
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
|
||||
cmdq_error(item, "invalid sort order");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
sort_crit.reversed = args_has(args, 'r');
|
||||
|
||||
l = sort_get_clients(&n, &sort_crit);
|
||||
for (i = 0; i < n; i++) {
|
||||
if (l[i]->session == NULL || (s != NULL && s != l[i]->session))
|
||||
continue;
|
||||
|
||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||
format_add(ft, "line", "%u", idx);
|
||||
format_defaults(ft, c, NULL, NULL, NULL);
|
||||
format_add(ft, "line", "%u", i);
|
||||
format_defaults(ft, l[i], NULL, NULL, NULL);
|
||||
|
||||
if (filter != NULL) {
|
||||
expanded = format_expand(ft, filter);
|
||||
@@ -94,8 +102,6 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
|
||||
format_free(ft);
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
107
cmd-list-commands.c
Normal file
107
cmd-list-commands.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/* $OpenBSD: cmd-list-commands.c,v 1.15 2026/02/24 08:22:13 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* List all commands.
|
||||
*/
|
||||
|
||||
#define LIST_COMMANDS_TEMPLATE \
|
||||
"#{command_list_name}" \
|
||||
"#{?command_list_alias, (#{command_list_alias}),} " \
|
||||
"#{command_list_usage}"
|
||||
|
||||
static enum cmd_retval cmd_list_commands(struct cmd *, struct cmdq_item *);
|
||||
|
||||
const struct cmd_entry cmd_list_commands_entry = {
|
||||
.name = "list-commands",
|
||||
.alias = "lscm",
|
||||
|
||||
.args = { "F:", 0, 1, NULL },
|
||||
.usage = "[-F format] [command]",
|
||||
|
||||
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
|
||||
.exec = cmd_list_commands
|
||||
};
|
||||
|
||||
static void
|
||||
cmd_list_single_command(const struct cmd_entry *entry, struct format_tree *ft,
|
||||
const char *template, struct cmdq_item *item)
|
||||
{
|
||||
const char *s;
|
||||
char *line;
|
||||
|
||||
format_add(ft, "command_list_name", "%s", entry->name);
|
||||
if (entry->alias != NULL)
|
||||
s = entry->alias;
|
||||
else
|
||||
s = "";
|
||||
format_add(ft, "command_list_alias", "%s", s);
|
||||
if (entry->usage != NULL)
|
||||
s = entry->usage;
|
||||
else
|
||||
s = "";
|
||||
format_add(ft, "command_list_usage", "%s", s);
|
||||
|
||||
line = format_expand(ft, template);
|
||||
if (*line != '\0')
|
||||
cmdq_print(item, "%s", line);
|
||||
free(line);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_list_commands(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
const struct cmd_entry **entryp;
|
||||
const struct cmd_entry *entry;
|
||||
struct format_tree *ft;
|
||||
const char *template, *command;
|
||||
char *cause;
|
||||
|
||||
if ((template = args_get(args, 'F')) == NULL)
|
||||
template = LIST_COMMANDS_TEMPLATE;
|
||||
|
||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||
format_defaults(ft, NULL, NULL, NULL, NULL);
|
||||
|
||||
command = args_string(args, 0);
|
||||
if (command == NULL) {
|
||||
for (entryp = cmd_table; *entryp != NULL; entryp++)
|
||||
cmd_list_single_command(*entryp, ft, template, item);
|
||||
} else {
|
||||
entry = cmd_find(command, &cause);
|
||||
if (entry != NULL)
|
||||
cmd_list_single_command(entry, ft, template, item);
|
||||
else {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
format_free(ft);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
format_free(ft);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
472
cmd-list-keys.c
472
cmd-list-keys.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-keys.c,v 1.78 2026/07/01 13:12:17 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -27,121 +27,149 @@
|
||||
* List key bindings.
|
||||
*/
|
||||
|
||||
static enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmdq_item *);
|
||||
#define LIST_KEYS_TEMPLATE \
|
||||
"#{?notes_only," \
|
||||
"#{key_prefix} " \
|
||||
"#{p|#{key_string_width}:key_string} " \
|
||||
"#{?key_note,#{key_note},#{key_command}}" \
|
||||
"," \
|
||||
"bind-key #{?key_has_repeat,#{?key_repeat,-r, },} " \
|
||||
"-T #{p|#{key_table_width}:key_table} " \
|
||||
"#{p|#{key_string_width}:#{q|a:key_string}} " \
|
||||
"#{key_command}}"
|
||||
#define LIST_KEYS_TEMPLATE_PRETTY \
|
||||
"#{?notes_only," \
|
||||
"#{key_prefix} " \
|
||||
"#{key_string} " \
|
||||
"#{?key_note,#{key_note},#{key_command}}" \
|
||||
"," \
|
||||
"bind-key #{?key_repeat,-r ,}" \
|
||||
"-T #{key_table} " \
|
||||
"#{q|a:key_string} " \
|
||||
"#{key_command}}"
|
||||
|
||||
static enum cmd_retval cmd_list_keys_commands(struct cmd *,
|
||||
struct cmdq_item *);
|
||||
static enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmdq_item *);
|
||||
|
||||
const struct cmd_entry cmd_list_keys_entry = {
|
||||
.name = "list-keys",
|
||||
.alias = "lsk",
|
||||
|
||||
.args = { "1aNP:T:", 0, 1, NULL },
|
||||
.usage = "[-1aN] [-P prefix-string] [-T key-table] [key]",
|
||||
.args = { "1aF:NO:P:prT:", 0, 1, NULL },
|
||||
.usage = "[-1aNpr] [-F format] [-O order] [-P prefix-string]"
|
||||
"[-T key-table] [key]",
|
||||
|
||||
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
|
||||
.exec = cmd_list_keys_exec
|
||||
};
|
||||
|
||||
const struct cmd_entry cmd_list_commands_entry = {
|
||||
.name = "list-commands",
|
||||
.alias = "lscm",
|
||||
static char *
|
||||
cmd_list_keys_get_prefix(struct args *args)
|
||||
{
|
||||
key_code prefix;
|
||||
|
||||
.args = { "F:", 0, 1, NULL },
|
||||
.usage = "[-F format] [command]",
|
||||
if (args_has(args, 'P'))
|
||||
return (xstrdup(args_get(args, 'P')));
|
||||
|
||||
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
|
||||
.exec = cmd_list_keys_exec
|
||||
};
|
||||
prefix = options_get_number(global_s_options, "prefix");
|
||||
if (prefix == KEYC_NONE)
|
||||
return (xstrdup(""));
|
||||
return (xstrdup(key_string_lookup_key(prefix, 0)));
|
||||
}
|
||||
|
||||
static u_int
|
||||
cmd_list_keys_get_width(const char *tablename, key_code only)
|
||||
cmd_list_keys_get_width(struct key_binding **l, u_int n)
|
||||
{
|
||||
struct key_table *table;
|
||||
struct key_binding *bd;
|
||||
u_int width, keywidth = 0;
|
||||
u_int i, width, keywidth = 0;
|
||||
|
||||
table = key_bindings_get_table(tablename, 0);
|
||||
if (table == NULL)
|
||||
return (0);
|
||||
bd = key_bindings_first(table);
|
||||
while (bd != NULL) {
|
||||
if ((only != KEYC_UNKNOWN && bd->key != only) ||
|
||||
KEYC_IS_MOUSE(bd->key) ||
|
||||
bd->note == NULL ||
|
||||
*bd->note == '\0') {
|
||||
bd = key_bindings_next(table, bd);
|
||||
continue;
|
||||
}
|
||||
width = utf8_cstrwidth(key_string_lookup_key(bd->key, 0));
|
||||
for (i = 0; i < n; i++) {
|
||||
width = utf8_cstrwidth(key_string_lookup_key(l[i]->key, 0));
|
||||
if (width > keywidth)
|
||||
keywidth = width;
|
||||
|
||||
bd = key_bindings_next(table, bd);
|
||||
}
|
||||
return (keywidth);
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
|
||||
const char *tablename, u_int keywidth, key_code only, const char *prefix)
|
||||
static u_int
|
||||
cmd_list_keys_get_table_width(struct key_binding **l, u_int n)
|
||||
{
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct key_table *table;
|
||||
struct key_binding *bd;
|
||||
const char *key;
|
||||
char *tmp, *note;
|
||||
int found = 0;
|
||||
u_int i, width, tablewidth = 0;
|
||||
|
||||
table = key_bindings_get_table(tablename, 0);
|
||||
if (table == NULL)
|
||||
return (0);
|
||||
bd = key_bindings_first(table);
|
||||
while (bd != NULL) {
|
||||
if ((only != KEYC_UNKNOWN && bd->key != only) ||
|
||||
KEYC_IS_MOUSE(bd->key) ||
|
||||
((bd->note == NULL || *bd->note == '\0') &&
|
||||
!args_has(args, 'a'))) {
|
||||
bd = key_bindings_next(table, bd);
|
||||
continue;
|
||||
for (i = 0; i < n; i++) {
|
||||
width = utf8_cstrwidth(l[i]->tablename);
|
||||
if (width > tablewidth)
|
||||
tablewidth = width;
|
||||
}
|
||||
found = 1;
|
||||
key = key_string_lookup_key(bd->key, 0);
|
||||
|
||||
if (bd->note == NULL || *bd->note == '\0')
|
||||
note = cmd_list_print(bd->cmdlist, 1);
|
||||
else
|
||||
note = xstrdup(bd->note);
|
||||
tmp = utf8_padcstr(key, keywidth + 1);
|
||||
if (args_has(args, '1') && tc != NULL) {
|
||||
status_message_set(tc, -1, 1, 0, 0, "%s%s%s", prefix,
|
||||
tmp, note);
|
||||
} else
|
||||
cmdq_print(item, "%s%s%s", prefix, tmp, note);
|
||||
free(tmp);
|
||||
free(note);
|
||||
|
||||
if (args_has(args, '1'))
|
||||
break;
|
||||
bd = key_bindings_next(table, bd);
|
||||
}
|
||||
return (found);
|
||||
return (tablewidth);
|
||||
}
|
||||
|
||||
static char *
|
||||
cmd_list_keys_get_prefix(struct args *args, key_code *prefix)
|
||||
static struct key_binding **
|
||||
cmd_list_keys_get_root_and_prefix(u_int *n, struct sort_criteria *sort_crit)
|
||||
{
|
||||
const char *tables[] = { "prefix", "root" };
|
||||
struct key_table *t;
|
||||
struct key_binding **lt;
|
||||
u_int i, ltsz, len = 0, offset = 0;
|
||||
static struct key_binding **l = NULL;
|
||||
static u_int lsz = 0;
|
||||
|
||||
for (i = 0; i < nitems(tables); i++) {
|
||||
t = key_bindings_get_table(tables[i], 0);
|
||||
lt = sort_get_key_bindings_table(t, <sz, sort_crit);
|
||||
len += ltsz;
|
||||
if (lsz <= len) {
|
||||
lsz = len + 100;
|
||||
l = xreallocarray(l, lsz, sizeof *l);
|
||||
}
|
||||
memcpy(l + offset, lt, ltsz * sizeof *l);
|
||||
offset += ltsz;
|
||||
}
|
||||
|
||||
*n = len;
|
||||
return (l);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_list_keys_do_filter(int filter_notes, int filter_key, key_code only,
|
||||
struct key_binding **l, u_int *n)
|
||||
{
|
||||
key_code key;
|
||||
u_int i, j = 0;
|
||||
|
||||
for (i = 0; i < *n; i++) {
|
||||
key = l[i]->key & (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS);
|
||||
if (filter_key && only != key)
|
||||
continue;
|
||||
if (filter_notes && l[i]->note == NULL)
|
||||
continue;
|
||||
l[j++] = l[i];
|
||||
}
|
||||
*n = j;
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_list_keys_format_key_binding(struct format_tree *ft,
|
||||
const struct key_binding *bd, const char *prefix, int flags)
|
||||
{
|
||||
char *s;
|
||||
|
||||
*prefix = options_get_number(global_s_options, "prefix");
|
||||
if (!args_has(args, 'P')) {
|
||||
if (*prefix != KEYC_NONE)
|
||||
xasprintf(&s, "%s ", key_string_lookup_key(*prefix, 0));
|
||||
if (bd->flags & KEY_BINDING_REPEAT)
|
||||
format_add(ft, "key_repeat", "1");
|
||||
else
|
||||
s = xstrdup("");
|
||||
} else
|
||||
s = xstrdup(args_get(args, 'P'));
|
||||
return (s);
|
||||
format_add(ft, "key_repeat", "0");
|
||||
|
||||
if (bd->note != NULL)
|
||||
format_add(ft, "key_note", "%s", bd->note);
|
||||
else
|
||||
format_add(ft, "key_note", "%s", "");
|
||||
|
||||
format_add(ft, "key_prefix", "%s", prefix);
|
||||
format_add(ft, "key_table", "%s", bd->tablename);
|
||||
|
||||
format_add(ft, "key_string", "%s", key_string_lookup_key(bd->key, 0));
|
||||
|
||||
s = cmd_parse_print(bd->cmd, flags);
|
||||
format_add(ft, "key_command", "%s", s);
|
||||
free(s);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
@@ -149,16 +177,17 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct key_table *table;
|
||||
struct key_binding *bd;
|
||||
const char *tablename, *r, *keystr;
|
||||
char *key, *cp, *tmp, *start, *empty;
|
||||
key_code prefix, only = KEYC_UNKNOWN;
|
||||
int repeat, width, tablewidth, keywidth, found = 0;
|
||||
size_t tmpsize, tmpused, cplen;
|
||||
|
||||
if (cmd_get_entry(self) == &cmd_list_commands_entry)
|
||||
return (cmd_list_keys_commands(self, item));
|
||||
struct format_tree *ft;
|
||||
struct key_table *table = NULL;
|
||||
struct key_binding **l;
|
||||
key_code only = KEYC_UNKNOWN;
|
||||
const char *template, *tablename, *keystr;
|
||||
char *line;
|
||||
char *prefix = NULL;
|
||||
u_int i, n;
|
||||
int single, notes_only, filter_notes, filter_key;
|
||||
int print_flags = 0;
|
||||
struct sort_criteria sort_crit;
|
||||
|
||||
if ((keystr = args_string(args, 0)) != NULL) {
|
||||
only = key_string_lookup_string(keystr);
|
||||
@@ -169,218 +198,75 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
only &= (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS);
|
||||
}
|
||||
|
||||
tablename = args_get(args, 'T');
|
||||
if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) {
|
||||
sort_crit.order = sort_order_from_string(args_get(args, 'O'));
|
||||
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
|
||||
cmdq_error(item, "invalid sort order");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
sort_crit.reversed = args_has(args, 'r');
|
||||
|
||||
if ((tablename = args_get(args, 'T')) != NULL) {
|
||||
table = key_bindings_get_table(tablename, 0);
|
||||
if (table == NULL) {
|
||||
cmdq_error(item, "table %s doesn't exist", tablename);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (args_has(args, 'N')) {
|
||||
if (tablename == NULL) {
|
||||
start = cmd_list_keys_get_prefix(args, &prefix);
|
||||
keywidth = cmd_list_keys_get_width("root", only);
|
||||
if (prefix != KEYC_NONE) {
|
||||
width = cmd_list_keys_get_width("prefix", only);
|
||||
if (width == 0)
|
||||
prefix = KEYC_NONE;
|
||||
else if (width > keywidth)
|
||||
keywidth = width;
|
||||
}
|
||||
empty = utf8_padcstr("", utf8_cstrwidth(start));
|
||||
|
||||
found = cmd_list_keys_print_notes(item, args, "root",
|
||||
keywidth, only, empty);
|
||||
if (prefix != KEYC_NONE) {
|
||||
if (cmd_list_keys_print_notes(item, args,
|
||||
"prefix", keywidth, only, start))
|
||||
found = 1;
|
||||
}
|
||||
free(empty);
|
||||
} else {
|
||||
if (args_has(args, 'P'))
|
||||
start = xstrdup(args_get(args, 'P'));
|
||||
else
|
||||
start = xstrdup("");
|
||||
keywidth = cmd_list_keys_get_width(tablename, only);
|
||||
found = cmd_list_keys_print_notes(item, args, tablename,
|
||||
keywidth, only, start);
|
||||
|
||||
}
|
||||
free(start);
|
||||
goto out;
|
||||
}
|
||||
|
||||
repeat = 0;
|
||||
tablewidth = keywidth = 0;
|
||||
table = key_bindings_first_table();
|
||||
while (table != NULL) {
|
||||
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
|
||||
table = key_bindings_next_table(table);
|
||||
continue;
|
||||
}
|
||||
bd = key_bindings_first(table);
|
||||
while (bd != NULL) {
|
||||
if (only != KEYC_UNKNOWN && bd->key != only) {
|
||||
bd = key_bindings_next(table, bd);
|
||||
continue;
|
||||
}
|
||||
key = args_escape(key_string_lookup_key(bd->key, 0));
|
||||
|
||||
if (bd->flags & KEY_BINDING_REPEAT)
|
||||
repeat = 1;
|
||||
|
||||
width = utf8_cstrwidth(table->name);
|
||||
if (width > tablewidth)
|
||||
tablewidth = width;
|
||||
width = utf8_cstrwidth(key);
|
||||
if (width > keywidth)
|
||||
keywidth = width;
|
||||
|
||||
free(key);
|
||||
bd = key_bindings_next(table, bd);
|
||||
}
|
||||
table = key_bindings_next_table(table);
|
||||
}
|
||||
|
||||
tmpsize = 256;
|
||||
tmp = xmalloc(tmpsize);
|
||||
|
||||
table = key_bindings_first_table();
|
||||
while (table != NULL) {
|
||||
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
|
||||
table = key_bindings_next_table(table);
|
||||
continue;
|
||||
}
|
||||
bd = key_bindings_first(table);
|
||||
while (bd != NULL) {
|
||||
if (only != KEYC_UNKNOWN && bd->key != only) {
|
||||
bd = key_bindings_next(table, bd);
|
||||
continue;
|
||||
}
|
||||
found = 1;
|
||||
key = args_escape(key_string_lookup_key(bd->key, 0));
|
||||
|
||||
if (!repeat)
|
||||
r = "";
|
||||
else if (bd->flags & KEY_BINDING_REPEAT)
|
||||
r = "-r ";
|
||||
else
|
||||
r = " ";
|
||||
tmpused = xsnprintf(tmp, tmpsize, "%s-T ", r);
|
||||
|
||||
cp = utf8_padcstr(table->name, tablewidth);
|
||||
cplen = strlen(cp) + 1;
|
||||
while (tmpused + cplen + 1 >= tmpsize) {
|
||||
tmpsize *= 2;
|
||||
tmp = xrealloc(tmp, tmpsize);
|
||||
}
|
||||
strlcat(tmp, cp, tmpsize);
|
||||
tmpused = strlcat(tmp, " ", tmpsize);
|
||||
free(cp);
|
||||
|
||||
cp = utf8_padcstr(key, keywidth);
|
||||
cplen = strlen(cp) + 1;
|
||||
while (tmpused + cplen + 1 >= tmpsize) {
|
||||
tmpsize *= 2;
|
||||
tmp = xrealloc(tmp, tmpsize);
|
||||
}
|
||||
strlcat(tmp, cp, tmpsize);
|
||||
tmpused = strlcat(tmp, " ", tmpsize);
|
||||
free(cp);
|
||||
|
||||
cp = cmd_list_print(bd->cmdlist, 1);
|
||||
cplen = strlen(cp);
|
||||
while (tmpused + cplen + 1 >= tmpsize) {
|
||||
tmpsize *= 2;
|
||||
tmp = xrealloc(tmp, tmpsize);
|
||||
}
|
||||
strlcat(tmp, cp, tmpsize);
|
||||
free(cp);
|
||||
|
||||
if (args_has(args, '1') && tc != NULL) {
|
||||
status_message_set(tc, -1, 1, 0, 0,
|
||||
"bind-key %s", tmp);
|
||||
} else
|
||||
cmdq_print(item, "bind-key %s", tmp);
|
||||
free(key);
|
||||
|
||||
if (args_has(args, '1'))
|
||||
break;
|
||||
bd = key_bindings_next(table, bd);
|
||||
}
|
||||
table = key_bindings_next_table(table);
|
||||
}
|
||||
|
||||
free(tmp);
|
||||
|
||||
out:
|
||||
if (only != KEYC_UNKNOWN && !found) {
|
||||
cmdq_error(item, "unknown key: %s", args_string(args, 0));
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_list_single_command(const struct cmd_entry *entry, struct format_tree *ft,
|
||||
const char *template, struct cmdq_item *item)
|
||||
{
|
||||
const char *s;
|
||||
char *line;
|
||||
|
||||
format_add(ft, "command_list_name", "%s", entry->name);
|
||||
if (entry->alias != NULL)
|
||||
s = entry->alias;
|
||||
else
|
||||
s = "";
|
||||
format_add(ft, "command_list_alias", "%s", s);
|
||||
if (entry->usage != NULL)
|
||||
s = entry->usage;
|
||||
else
|
||||
s = "";
|
||||
format_add(ft, "command_list_usage", "%s", s);
|
||||
|
||||
line = format_expand(ft, template);
|
||||
if (*line != '\0')
|
||||
cmdq_print(item, "%s", line);
|
||||
free(line);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
const struct cmd_entry **entryp;
|
||||
const struct cmd_entry *entry;
|
||||
struct format_tree *ft;
|
||||
const char *template, *command;
|
||||
char *cause;
|
||||
prefix = cmd_list_keys_get_prefix(args);
|
||||
single = args_has(args, '1');
|
||||
notes_only = args_has(args, 'N');
|
||||
if (args_has(args, 'p'))
|
||||
print_flags |= CMD_PARSE_PRINT_MULTILINE;
|
||||
|
||||
if ((template = args_get(args, 'F')) == NULL) {
|
||||
template = "#{command_list_name}"
|
||||
"#{?command_list_alias, (#{command_list_alias}),} "
|
||||
"#{command_list_usage}";
|
||||
if (print_flags & CMD_PARSE_PRINT_MULTILINE)
|
||||
template = LIST_KEYS_TEMPLATE_PRETTY;
|
||||
else
|
||||
template = LIST_KEYS_TEMPLATE;
|
||||
}
|
||||
|
||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||
format_defaults(ft, NULL, NULL, NULL, NULL);
|
||||
if (table)
|
||||
l = sort_get_key_bindings_table(table, &n, &sort_crit);
|
||||
else if (notes_only)
|
||||
l = cmd_list_keys_get_root_and_prefix(&n, &sort_crit);
|
||||
else
|
||||
l = sort_get_key_bindings(&n, &sort_crit);
|
||||
|
||||
command = args_string(args, 0);
|
||||
if (command == NULL) {
|
||||
for (entryp = cmd_table; *entryp != NULL; entryp++)
|
||||
cmd_list_single_command(*entryp, ft, template, item);
|
||||
} else {
|
||||
entry = cmd_find(command, &cause);
|
||||
if (entry != NULL)
|
||||
cmd_list_single_command(entry, ft, template, item);
|
||||
else {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
format_free(ft);
|
||||
filter_notes = notes_only && !args_has(args, 'a');
|
||||
filter_key = only != KEYC_UNKNOWN;
|
||||
if (filter_notes || filter_key)
|
||||
cmd_list_keys_do_filter(filter_notes, filter_key, only, l, &n);
|
||||
if (filter_key && n == 0) {
|
||||
cmdq_error(item, "unknown key: %s", keystr);
|
||||
free(prefix);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
if (single && n > 1)
|
||||
n = 1;
|
||||
|
||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||
format_defaults(ft, tc, NULL, NULL, NULL);
|
||||
format_add(ft, "notes_only", "%d", notes_only);
|
||||
format_add(ft, "key_has_repeat", "%d", key_bindings_has_repeat(l, n));
|
||||
format_add(ft, "key_string_width", "%u", cmd_list_keys_get_width(l, n));
|
||||
format_add(ft, "key_table_width", "%u",
|
||||
cmd_list_keys_get_table_width(l, n));
|
||||
for (i = 0; i < n; i++) {
|
||||
cmd_list_keys_format_key_binding(ft, l[i], prefix, print_flags);
|
||||
|
||||
line = format_expand(ft, template);
|
||||
if (single && tc != NULL && (~tc->flags & CLIENT_CONTROL))
|
||||
status_message_set(tc, -1, 1, 0, 0, "%s", line);
|
||||
else if (*line != '\0')
|
||||
cmdq_print(item, "%s", line);
|
||||
free(line);
|
||||
|
||||
if (single)
|
||||
break;
|
||||
}
|
||||
format_free(ft);
|
||||
free(prefix);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-panes.c,v 1.40 2026/06/01 14:01:09 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -38,8 +38,9 @@ const struct cmd_entry cmd_list_panes_entry = {
|
||||
.name = "list-panes",
|
||||
.alias = "lsp",
|
||||
|
||||
.args = { "asF:f:t:", 0, 0, NULL },
|
||||
.usage = "[-as] [-F format] [-f filter] " CMD_TARGET_WINDOW_USAGE,
|
||||
.args = { "aF:f:O:rst:", 0, 0, NULL },
|
||||
.usage = "[-asr] [-F format] [-f filter] [-O order]"
|
||||
CMD_TARGET_WINDOW_USAGE,
|
||||
|
||||
.target = { 't', CMD_FIND_WINDOW, 0 },
|
||||
|
||||
@@ -54,6 +55,13 @@ cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct session *s = target->s;
|
||||
struct winlink *wl = target->wl;
|
||||
enum sort_order order;
|
||||
|
||||
order = sort_order_from_string(args_get(args, 'O'));
|
||||
if (order == SORT_END && args_has(args, 'O')) {
|
||||
cmdq_error(item, "invalid sort order");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (args_has(args, 'a'))
|
||||
cmd_list_panes_server(self, item);
|
||||
@@ -89,34 +97,41 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
|
||||
struct cmdq_item *item, int type)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct window_pane *wp;
|
||||
u_int n;
|
||||
struct window_pane *wp, **l;
|
||||
u_int i, n;
|
||||
struct format_tree *ft;
|
||||
const char *template, *filter;
|
||||
char *line, *expanded;
|
||||
int flag;
|
||||
struct sort_criteria sort_crit;
|
||||
|
||||
template = args_get(args, 'F');
|
||||
if (template == NULL) {
|
||||
switch (type) {
|
||||
case 0:
|
||||
template = "#{pane_index}: "
|
||||
"[#{pane_width}x#{pane_height}] [history "
|
||||
"[#{pane_width}x#{pane_height}"
|
||||
"#{?pane_floating_flag, "
|
||||
"#{pane_x}#,#{pane_y}#,#{pane_z}}] [history "
|
||||
"#{history_size}/#{history_limit}, "
|
||||
"#{history_bytes} bytes] #{pane_id}"
|
||||
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
|
||||
break;
|
||||
case 1:
|
||||
template = "#{window_index}.#{pane_index}: "
|
||||
"[#{pane_width}x#{pane_height}] [history "
|
||||
"[#{pane_width}x#{pane_height}"
|
||||
"#{?pane_floating_flag, "
|
||||
"#{pane_x}#,#{pane_y}#,#{pane_z}}] [history "
|
||||
"#{history_size}/#{history_limit}, "
|
||||
"#{history_bytes} bytes] #{pane_id}"
|
||||
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
|
||||
break;
|
||||
case 2:
|
||||
template = "#{session_name}:#{window_index}."
|
||||
"#{pane_index}: [#{pane_width}x#{pane_height}] "
|
||||
"[history #{history_size}/#{history_limit}, "
|
||||
"#{pane_index}: [#{pane_width}x#{pane_height}"
|
||||
"#{?pane_floating_flag, "
|
||||
"#{pane_x}#,#{pane_y}#,#{pane_z}}] [history "
|
||||
"#{history_size}/#{history_limit}, "
|
||||
"#{history_bytes} bytes] #{pane_id}"
|
||||
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
|
||||
break;
|
||||
@@ -124,8 +139,12 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
|
||||
}
|
||||
filter = args_get(args, 'f');
|
||||
|
||||
n = 0;
|
||||
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
|
||||
sort_crit.order = sort_order_from_string(args_get(args, 'O'));
|
||||
sort_crit.reversed = args_has(args, 'r');
|
||||
|
||||
l = sort_get_panes_window(wl->window, &n, &sort_crit);
|
||||
for (i = 0; i < n; i++) {
|
||||
wp = l[i];
|
||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||
format_add(ft, "line", "%u", n);
|
||||
format_defaults(ft, NULL, s, wl, wp);
|
||||
@@ -143,6 +162,5 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
|
||||
}
|
||||
|
||||
format_free(ft);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-sessions.c,v 1.36 2026/02/27 08:25:12 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -42,8 +42,8 @@ const struct cmd_entry cmd_list_sessions_entry = {
|
||||
.name = "list-sessions",
|
||||
.alias = "ls",
|
||||
|
||||
.args = { "F:f:", 0, 0, NULL },
|
||||
.usage = "[-F format] [-f filter]",
|
||||
.args = { "F:f:O:r", 0, 0, NULL },
|
||||
.usage = "[-r] [-F format] [-f filter] [-O order]",
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.exec = cmd_list_sessions_exec
|
||||
@@ -53,22 +53,30 @@ static enum cmd_retval
|
||||
cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct session *s;
|
||||
u_int n;
|
||||
struct session **l;
|
||||
u_int n, i;
|
||||
struct format_tree *ft;
|
||||
const char *template, *filter;
|
||||
char *line, *expanded;
|
||||
int flag;
|
||||
struct sort_criteria sort_crit;
|
||||
|
||||
if ((template = args_get(args, 'F')) == NULL)
|
||||
template = LIST_SESSIONS_TEMPLATE;
|
||||
filter = args_get(args, 'f');
|
||||
|
||||
n = 0;
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
sort_crit.order = sort_order_from_string(args_get(args, 'O'));
|
||||
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
|
||||
cmdq_error(item, "invalid sort order");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
sort_crit.reversed = args_has(args, 'r');
|
||||
|
||||
l = sort_get_sessions(&n, &sort_crit);
|
||||
for (i = 0; i < n; i++) {
|
||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||
format_add(ft, "line", "%u", n);
|
||||
format_defaults(ft, NULL, s, NULL, NULL);
|
||||
format_add(ft, "line", "%u", i);
|
||||
format_defaults(ft, NULL, l[i], NULL, NULL);
|
||||
|
||||
if (filter != NULL) {
|
||||
expanded = format_expand(ft, filter);
|
||||
@@ -83,7 +91,6 @@ cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
|
||||
format_free(ft);
|
||||
n++;
|
||||
}
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-windows.c,v 1.50 2026/02/27 08:25:12 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -41,16 +41,13 @@
|
||||
|
||||
static enum cmd_retval cmd_list_windows_exec(struct cmd *, struct cmdq_item *);
|
||||
|
||||
static void cmd_list_windows_server(struct cmd *, struct cmdq_item *);
|
||||
static void cmd_list_windows_session(struct cmd *, struct session *,
|
||||
struct cmdq_item *, int);
|
||||
|
||||
const struct cmd_entry cmd_list_windows_entry = {
|
||||
.name = "list-windows",
|
||||
.alias = "lsw",
|
||||
|
||||
.args = { "F:f:at:", 0, 0, NULL },
|
||||
.usage = "[-a] [-F format] [-f filter] " CMD_TARGET_SESSION_USAGE,
|
||||
.args = { "aF:f:O:rt:", 0, 0, NULL },
|
||||
.usage = "[-ar] [-F format] [-f filter] [-O order]"
|
||||
CMD_TARGET_SESSION_USAGE,
|
||||
|
||||
.target = { 't', CMD_FIND_SESSION, 0 },
|
||||
|
||||
@@ -63,51 +60,38 @@ cmd_list_windows_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
|
||||
if (args_has(args, 'a'))
|
||||
cmd_list_windows_server(self, item);
|
||||
else
|
||||
cmd_list_windows_session(self, target->s, item, 0);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_list_windows_server(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct winlink *wl, **l;
|
||||
struct session *s;
|
||||
|
||||
RB_FOREACH(s, sessions, &sessions)
|
||||
cmd_list_windows_session(self, s, item, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_list_windows_session(struct cmd *self, struct session *s,
|
||||
struct cmdq_item *item, int type)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct winlink *wl;
|
||||
u_int n;
|
||||
u_int i, n;
|
||||
struct format_tree *ft;
|
||||
const char *template, *filter;
|
||||
char *line, *expanded;
|
||||
int flag;
|
||||
struct sort_criteria sort_crit;
|
||||
|
||||
template = args_get(args, 'F');
|
||||
if (template == NULL) {
|
||||
switch (type) {
|
||||
case 0:
|
||||
template = LIST_WINDOWS_TEMPLATE;
|
||||
break;
|
||||
case 1:
|
||||
template = LIST_WINDOWS_WITH_SESSION_TEMPLATE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
filter = args_get(args, 'f');
|
||||
|
||||
n = 0;
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
sort_crit.order = sort_order_from_string(args_get(args, 'O'));
|
||||
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
|
||||
cmdq_error(item, "invalid sort order");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
sort_crit.reversed = args_has(args, 'r');
|
||||
|
||||
if (args_has(args, 'a')) {
|
||||
l = sort_get_winlinks(&n, &sort_crit);
|
||||
if (template == NULL)
|
||||
template = LIST_WINDOWS_WITH_SESSION_TEMPLATE;
|
||||
} else {
|
||||
l = sort_get_winlinks_session(target->s, &n, &sort_crit);
|
||||
if (template == NULL)
|
||||
template = LIST_WINDOWS_TEMPLATE;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
wl = l[i];
|
||||
s = wl->session;
|
||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||
format_add(ft, "line", "%u", n);
|
||||
format_defaults(ft, NULL, s, wl, NULL);
|
||||
@@ -125,6 +109,7 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
|
||||
}
|
||||
|
||||
format_free(ft);
|
||||
n++;
|
||||
}
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-load-buffer.c,v 1.66 2025/10/28 07:32:26 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-lock-server.c,v 1.31 2021/08/21 10:22:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-move-window.c,v 1.34 2021/08/21 10:22:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-new-session.c,v 1.152 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -77,8 +77,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct termios tio, *tiop;
|
||||
struct session_group *sg = NULL;
|
||||
const char *errstr, *template, *group, *tmp;
|
||||
char *cause, *cwd = NULL, *cp, *newname = NULL;
|
||||
char *name, *prefix = NULL;
|
||||
char *cause, *cwd = NULL, *cp, *ename;
|
||||
char *wname = NULL, *sname = NULL, *prefix = NULL;
|
||||
int detached, already_attached, is_control = 0;
|
||||
u_int sx, sy, dsx, dsy, count = args_count(args);
|
||||
struct spawn_context sc = { 0 };
|
||||
@@ -99,32 +99,43 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
tmp = args_get(args, 's');
|
||||
if (tmp != NULL) {
|
||||
name = format_single(item, tmp, c, NULL, NULL, NULL);
|
||||
newname = session_check_name(name);
|
||||
if (newname == NULL) {
|
||||
cmdq_error(item, "invalid session: %s", name);
|
||||
free(name);
|
||||
if ((tmp = args_get(args, 'n')) != NULL) {
|
||||
ename = format_single(item, tmp, c, NULL, NULL, NULL);
|
||||
if (!check_name(ename)) {
|
||||
cmdq_error(item, "invalid window name: %s", ename);
|
||||
free(ename);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
free(name);
|
||||
wname = clean_name(ename, 0);
|
||||
free(ename);
|
||||
}
|
||||
if ((tmp = args_get(args, 's')) != NULL) {
|
||||
ename = format_single(item, tmp, c, NULL, NULL, NULL);
|
||||
if (!check_name(ename)) {
|
||||
cmdq_error(item, "invalid session name: %s", ename);
|
||||
free(ename);
|
||||
goto fail;
|
||||
}
|
||||
sname = clean_name(ename, 0);
|
||||
free(ename);
|
||||
}
|
||||
if (args_has(args, 'A')) {
|
||||
if (newname != NULL)
|
||||
as = session_find(newname);
|
||||
if (sname != NULL)
|
||||
as = session_find(sname);
|
||||
else
|
||||
as = target->s;
|
||||
if (as != NULL) {
|
||||
retval = cmd_attach_session(item, as->name,
|
||||
args_has(args, 'D'), args_has(args, 'X'), 0, NULL,
|
||||
args_has(args, 'E'), args_get(args, 'f'));
|
||||
free(newname);
|
||||
args_has(args, 'D'), args_has(args, 'X'), 0,
|
||||
args_get(args, 'c'), args_has(args, 'E'),
|
||||
args_get(args, 'f'));
|
||||
free(wname);
|
||||
free(sname);
|
||||
return (retval);
|
||||
}
|
||||
}
|
||||
if (newname != NULL && session_find(newname) != NULL) {
|
||||
cmdq_error(item, "duplicate session: %s", newname);
|
||||
if (sname != NULL && session_find(sname) != NULL) {
|
||||
cmdq_error(item, "duplicate session: %s", sname);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -141,12 +152,12 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
else if (groupwith != NULL)
|
||||
prefix = xstrdup(groupwith->name);
|
||||
else {
|
||||
prefix = session_check_name(group);
|
||||
if (prefix == NULL) {
|
||||
cmdq_error(item, "invalid session group: %s",
|
||||
group);
|
||||
if (!check_name(group)) {
|
||||
cmdq_error(item,
|
||||
"invalid session group name: %s", group);
|
||||
goto fail;
|
||||
}
|
||||
prefix = clean_name(group, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,7 +286,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
environ_put(env, av->string, 0);
|
||||
av = args_next_value(av);
|
||||
}
|
||||
s = session_create(prefix, newname, cwd, env, oo, tiop);
|
||||
s = session_create(prefix, sname, cwd, env, oo, tiop);
|
||||
|
||||
/* Spawn the initial window. */
|
||||
sc.item = item;
|
||||
@@ -283,7 +294,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (!detached)
|
||||
sc.tc = c;
|
||||
|
||||
sc.name = args_get(args, 'n');
|
||||
sc.name = wname;
|
||||
args_to_vector(args, &sc.argc, &sc.argv);
|
||||
|
||||
sc.idx = -1;
|
||||
@@ -314,7 +325,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
session_group_synchronize_to(s);
|
||||
session_select(s, RB_MIN(winlinks, &s->windows)->idx);
|
||||
}
|
||||
notify_session("session-created", s);
|
||||
events_fire_session("session-created", s);
|
||||
|
||||
/*
|
||||
* Set the client to the new session. If a command client exists, it is
|
||||
@@ -356,7 +367,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (sc.argv != NULL)
|
||||
cmd_free_argv(sc.argc, sc.argv);
|
||||
free(cwd);
|
||||
free(newname);
|
||||
free(wname);
|
||||
free(sname);
|
||||
free(prefix);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
@@ -364,7 +376,8 @@ fail:
|
||||
if (sc.argv != NULL)
|
||||
cmd_free_argv(sc.argc, sc.argv);
|
||||
free(cwd);
|
||||
free(newname);
|
||||
free(wname);
|
||||
free(sname);
|
||||
free(prefix);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-new-window.c,v 1.103 2026/07/08 08:07:42 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -38,8 +38,8 @@ const struct cmd_entry cmd_new_window_entry = {
|
||||
.name = "new-window",
|
||||
.alias = "neww",
|
||||
|
||||
.args = { "abc:de:F:kn:PSt:", 0, -1, NULL },
|
||||
.usage = "[-abdkPS] [-c start-directory] [-e environment] [-F format] "
|
||||
.args = { "abc:de:EF:kn:PSt:", 0, -1, NULL },
|
||||
.usage = "[-abdEkPS] [-c start-directory] [-e environment] [-F format] "
|
||||
"[-n window-name] " CMD_TARGET_WINDOW_USAGE
|
||||
" [shell-command [argument ...]]",
|
||||
|
||||
@@ -60,19 +60,36 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct session *s = target->s;
|
||||
struct winlink *wl = target->wl, *new_wl = NULL;
|
||||
int idx = target->idx, before;
|
||||
char *cause = NULL, *cp, *expanded;
|
||||
int idx = target->idx, before, count = args_count(args);
|
||||
char *cause = NULL, *cp, *expanded, *wname = NULL;
|
||||
const char *template, *name;
|
||||
struct cmd_find_state fs;
|
||||
struct args_value *av;
|
||||
|
||||
if (args_has(args, 'E') &&
|
||||
count != 0 &&
|
||||
(count != 1 || *args_string(args, 0) != '\0')) {
|
||||
cmdq_error(item, "command cannot be given for empty pane");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* If -S and -n are given and -t is not and a single window with this
|
||||
* name already exists, select it.
|
||||
*/
|
||||
name = args_get(args, 'n');
|
||||
if (args_has(args, 'S') && name != NULL && target->idx == -1) {
|
||||
if (name != NULL) {
|
||||
expanded = format_single(item, name, c, s, NULL, NULL);
|
||||
if (!check_name(expanded)) {
|
||||
cmdq_error(item, "invalid window name: %s", expanded);
|
||||
free(expanded);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
wname = clean_name(expanded, 0);
|
||||
free(expanded);
|
||||
}
|
||||
if (args_has(args, 'S') && wname != NULL && target->idx == -1) {
|
||||
expanded = format_single(item, wname, c, s, NULL, NULL);
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
if (strcmp(wl->window->name, expanded) != 0)
|
||||
continue;
|
||||
@@ -80,12 +97,14 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
new_wl = wl;
|
||||
continue;
|
||||
}
|
||||
cmdq_error(item, "multiple windows named %s", name);
|
||||
cmdq_error(item, "multiple windows named %s", wname);
|
||||
free(wname);
|
||||
free(expanded);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
free(expanded);
|
||||
if (new_wl != NULL) {
|
||||
free(wname);
|
||||
if (args_has(args, 'd'))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (session_set_current(s, new_wl) == 0)
|
||||
@@ -108,7 +127,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
sc.s = s;
|
||||
sc.tc = tc;
|
||||
|
||||
sc.name = args_get(args, 'n');
|
||||
sc.name = wname;
|
||||
args_to_vector(args, &sc.argc, &sc.argv);
|
||||
sc.environ = environ_create();
|
||||
|
||||
@@ -122,6 +141,8 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
sc.cwd = args_get(args, 'c');
|
||||
|
||||
sc.flags = 0;
|
||||
if (args_has(args, 'E') || (count == 1 && *args_string(args, 0) == '\0'))
|
||||
sc.flags |= SPAWN_EMPTY;
|
||||
if (args_has(args, 'd'))
|
||||
sc.flags |= SPAWN_DETACHED;
|
||||
if (args_has(args, 'k'))
|
||||
@@ -130,10 +151,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if ((new_wl = spawn_window(&sc, &cause)) == NULL) {
|
||||
cmdq_error(item, "create window failed: %s", cause);
|
||||
free(cause);
|
||||
if (sc.argv != NULL)
|
||||
cmd_free_argv(sc.argc, sc.argv);
|
||||
environ_free(sc.environ);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
if (!args_has(args, 'd') || new_wl == s->curw) {
|
||||
cmd_find_from_winlink(current, new_wl, 0);
|
||||
@@ -156,5 +174,13 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (sc.argv != NULL)
|
||||
cmd_free_argv(sc.argc, sc.argv);
|
||||
environ_free(sc.environ);
|
||||
free(wname);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
if (sc.argv != NULL)
|
||||
cmd_free_argv(sc.argc, sc.argv);
|
||||
environ_free(sc.environ);
|
||||
free(wname);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
2760
cmd-parse.y
2760
cmd-parse.y
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-paste-buffer.c,v 1.44 2026/03/04 07:19:32 tb Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -33,8 +33,8 @@ const struct cmd_entry cmd_paste_buffer_entry = {
|
||||
.name = "paste-buffer",
|
||||
.alias = "pasteb",
|
||||
|
||||
.args = { "db:prs:t:", 0, 0, NULL },
|
||||
.usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " "
|
||||
.args = { "db:prSs:t:", 0, 0, NULL },
|
||||
.usage = "[-dprS] [-s separator] " CMD_BUFFER_USAGE " "
|
||||
CMD_TARGET_PANE_USAGE,
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
@@ -43,6 +43,17 @@ const struct cmd_entry cmd_paste_buffer_entry = {
|
||||
.exec = cmd_paste_buffer_exec
|
||||
};
|
||||
|
||||
static void
|
||||
cmd_paste_buffer_paste(struct window_pane *wp, const char *buf, size_t len)
|
||||
{
|
||||
char *cp;
|
||||
size_t n;
|
||||
|
||||
n = utf8_stravisx(&cp, buf, len, VIS_SAFE|VIS_NOSLASH);
|
||||
bufferevent_write(wp->event, cp, n);
|
||||
free(cp);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
@@ -51,7 +62,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct window_pane *wp = target->wp;
|
||||
struct paste_buffer *pb;
|
||||
const char *sepstr, *bufname, *bufdata, *bufend, *line;
|
||||
size_t seplen, bufsize;
|
||||
size_t seplen, bufsize, len;
|
||||
int bracket = args_has(args, 'p');
|
||||
|
||||
if (window_pane_exited(wp)) {
|
||||
@@ -93,14 +104,22 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
line = memchr(bufdata, '\n', bufend - bufdata);
|
||||
if (line == NULL)
|
||||
break;
|
||||
|
||||
bufferevent_write(wp->event, bufdata, line - bufdata);
|
||||
len = line - bufdata;
|
||||
if (args_has(args, 'S'))
|
||||
bufferevent_write(wp->event, bufdata, len);
|
||||
else
|
||||
cmd_paste_buffer_paste(wp, bufdata, len);
|
||||
bufferevent_write(wp->event, sepstr, seplen);
|
||||
|
||||
bufdata = line + 1;
|
||||
}
|
||||
if (bufdata != bufend)
|
||||
bufferevent_write(wp->event, bufdata, bufend - bufdata);
|
||||
if (bufdata != bufend) {
|
||||
len = bufend - bufdata;
|
||||
if (args_has(args, 'S'))
|
||||
bufferevent_write(wp->event, bufdata, len);
|
||||
else
|
||||
cmd_paste_buffer_paste(wp, bufdata, len);
|
||||
}
|
||||
|
||||
if (bracket && (wp->screen->mode & MODE_BRACKETPASTE))
|
||||
bufferevent_write(wp->event, "\033[201~", 6);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-pipe-pane.c,v 1.64 2026/07/27 14:25:46 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -123,11 +123,13 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
/* Fork the child. */
|
||||
sigfillset(&set);
|
||||
sigprocmask(SIG_BLOCK, &set, &oldset);
|
||||
switch (fork()) {
|
||||
switch ((wp->pipe_pid = fork())) {
|
||||
case -1:
|
||||
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||
cmdq_error(item, "fork error: %s", strerror(errno));
|
||||
|
||||
close(pipe_fd[0]);
|
||||
close(pipe_fd[1]);
|
||||
free(cmd);
|
||||
return (CMD_RETURN_ERROR);
|
||||
case 0:
|
||||
@@ -136,6 +138,9 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||
close(pipe_fd[0]);
|
||||
|
||||
if (setpgid(0, 0) == -1)
|
||||
_exit(1);
|
||||
|
||||
null_fd = open(_PATH_DEVNULL, O_WRONLY);
|
||||
if (out) {
|
||||
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
|
||||
@@ -189,9 +194,13 @@ 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;
|
||||
struct evbuffer *evb;
|
||||
size_t available;
|
||||
|
||||
if (wp->pipe_event == NULL)
|
||||
return;
|
||||
evb = wp->pipe_event->input;
|
||||
|
||||
available = EVBUFFER_LENGTH(evb);
|
||||
log_debug("%%%u pipe read %zu", wp->id, available);
|
||||
|
||||
|
||||
201
cmd-queue.c
201
cmd-queue.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-queue.c,v 1.123 2026/08/24 20:34:26 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -35,6 +35,7 @@
|
||||
enum cmdq_type {
|
||||
CMDQ_COMMAND,
|
||||
CMDQ_CALLBACK,
|
||||
CMDQ_INVOKE,
|
||||
};
|
||||
|
||||
/* Command queue item. */
|
||||
@@ -47,7 +48,6 @@ struct cmdq_item {
|
||||
struct client *target_client;
|
||||
|
||||
enum cmdq_type type;
|
||||
u_int group;
|
||||
|
||||
u_int number;
|
||||
time_t time;
|
||||
@@ -58,8 +58,8 @@ struct cmdq_item {
|
||||
struct cmd_find_state source;
|
||||
struct cmd_find_state target;
|
||||
|
||||
struct cmd_list *cmdlist;
|
||||
struct cmd *cmd;
|
||||
struct cmd_invoke_state *invoke_state;
|
||||
|
||||
cmdq_cb cb;
|
||||
void *data;
|
||||
@@ -147,6 +147,13 @@ cmdq_get_name(struct cmdq_item *item)
|
||||
return (item->name);
|
||||
}
|
||||
|
||||
/* Get item command. */
|
||||
struct cmd *
|
||||
cmdq_get_cmd(struct cmdq_item *item)
|
||||
{
|
||||
return (item->cmd);
|
||||
}
|
||||
|
||||
/* Get item client. */
|
||||
struct client *
|
||||
cmdq_get_client(struct cmdq_item *item)
|
||||
@@ -350,74 +357,53 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
|
||||
|
||||
/* Insert a hook. */
|
||||
void
|
||||
cmdq_insert_hook(struct session *s, struct cmdq_item *item,
|
||||
cmdq_insert_hook(__unused struct session *s, struct cmdq_item *item,
|
||||
struct cmd_find_state *current, const char *fmt, ...)
|
||||
{
|
||||
struct cmdq_state *state = item->state;
|
||||
struct cmd *cmd = item->cmd;
|
||||
struct args *args = cmd_get_args(cmd);
|
||||
struct args_entry *ae;
|
||||
struct args_value *av;
|
||||
struct options *oo;
|
||||
struct event_payload *ep;
|
||||
va_list ap;
|
||||
char *name, tmp[32], flag, *arguments;
|
||||
u_int i;
|
||||
const char *value;
|
||||
struct cmdq_item *new_item;
|
||||
struct cmdq_state *new_state;
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
struct cmd_list *cmdlist;
|
||||
|
||||
if (item->state->flags & CMDQ_STATE_NOHOOKS)
|
||||
return;
|
||||
if (s == NULL)
|
||||
oo = global_s_options;
|
||||
else
|
||||
oo = s->options;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&name, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
o = options_get(oo, name);
|
||||
if (o == NULL) {
|
||||
free(name);
|
||||
return;
|
||||
}
|
||||
log_debug("running hook %s (parent %p)", name, item);
|
||||
|
||||
/*
|
||||
* The hooks get a new state because they should not update the current
|
||||
* target or formats for any subsequent commands.
|
||||
*/
|
||||
new_state = cmdq_new_state(current, &state->event, CMDQ_STATE_NOHOOKS);
|
||||
cmdq_add_format(new_state, "hook", "%s", name);
|
||||
ep = event_payload_create();
|
||||
if (current != NULL)
|
||||
event_payload_set_target(ep, current);
|
||||
event_payload_set_pointer(ep, "_cmdq_item", item, NULL, NULL);
|
||||
|
||||
arguments = args_print(args);
|
||||
cmdq_add_format(new_state, "hook_arguments", "%s", arguments);
|
||||
event_payload_set_string(ep, "arguments", "%s", arguments);
|
||||
free(arguments);
|
||||
|
||||
for (i = 0; i < args_count(args); i++) {
|
||||
xsnprintf(tmp, sizeof tmp, "hook_argument_%d", i);
|
||||
cmdq_add_format(new_state, tmp, "%s", args_string(args, i));
|
||||
xsnprintf(tmp, sizeof tmp, "argument_%u", i);
|
||||
event_payload_set_string(ep, tmp, "%s", args_string(args, i));
|
||||
}
|
||||
flag = args_first(args, &ae);
|
||||
while (flag != 0) {
|
||||
value = args_get(args, flag);
|
||||
if (value == NULL) {
|
||||
xsnprintf(tmp, sizeof tmp, "hook_flag_%c", flag);
|
||||
cmdq_add_format(new_state, tmp, "1");
|
||||
} else {
|
||||
xsnprintf(tmp, sizeof tmp, "hook_flag_%c", flag);
|
||||
cmdq_add_format(new_state, tmp, "%s", value);
|
||||
}
|
||||
xsnprintf(tmp, sizeof tmp, "flag_%c", flag);
|
||||
if (value == NULL)
|
||||
event_payload_set_string(ep, tmp, "1");
|
||||
else
|
||||
event_payload_set_string(ep, tmp, "%s", value);
|
||||
|
||||
i = 0;
|
||||
av = args_first_value(args, flag);
|
||||
while (av != NULL) {
|
||||
xsnprintf(tmp, sizeof tmp, "hook_flag_%c_%d", flag, i);
|
||||
cmdq_add_format(new_state, tmp, "%s", av->string);
|
||||
xsnprintf(tmp, sizeof tmp, "flag_%c_%u", flag, i);
|
||||
event_payload_set_string(ep, tmp, "%s", av->string);
|
||||
i++;
|
||||
av = args_next_value(av);
|
||||
}
|
||||
@@ -425,20 +411,7 @@ cmdq_insert_hook(struct session *s, struct cmdq_item *item,
|
||||
flag = args_next(&ae);
|
||||
}
|
||||
|
||||
a = options_array_first(o);
|
||||
while (a != NULL) {
|
||||
cmdlist = options_array_item_value(a)->cmdlist;
|
||||
if (cmdlist != NULL) {
|
||||
new_item = cmdq_get_command(cmdlist, new_state);
|
||||
if (item != NULL)
|
||||
item = cmdq_insert_after(item, new_item);
|
||||
else
|
||||
item = cmdq_append(NULL, new_item);
|
||||
}
|
||||
a = options_array_next(a);
|
||||
}
|
||||
|
||||
cmdq_free_state(new_state);
|
||||
events_fire(name, ep);
|
||||
free(name);
|
||||
}
|
||||
|
||||
@@ -455,8 +428,10 @@ cmdq_remove(struct cmdq_item *item)
|
||||
{
|
||||
if (item->client != NULL)
|
||||
server_client_unref(item->client);
|
||||
if (item->cmdlist != NULL)
|
||||
cmd_list_free(item->cmdlist);
|
||||
if (item->cmd != NULL)
|
||||
cmd_free(item->cmd);
|
||||
if (item->invoke_state != NULL)
|
||||
cmd_invoke_state_free(item->invoke_state);
|
||||
cmdq_free_state(item->state);
|
||||
|
||||
TAILQ_REMOVE(&item->queue->list, item, entry);
|
||||
@@ -465,75 +440,46 @@ cmdq_remove(struct cmdq_item *item)
|
||||
free(item);
|
||||
}
|
||||
|
||||
/* Remove all subsequent items that match this item's group. */
|
||||
static void
|
||||
cmdq_remove_group(struct cmdq_item *item)
|
||||
{
|
||||
struct cmdq_item *this, *next;
|
||||
|
||||
if (item->group == 0)
|
||||
return;
|
||||
this = TAILQ_NEXT(item, entry);
|
||||
while (this != NULL) {
|
||||
next = TAILQ_NEXT(this, entry);
|
||||
if (this->group == item->group)
|
||||
cmdq_remove(this);
|
||||
this = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Empty command callback. */
|
||||
static enum cmd_retval
|
||||
cmdq_empty_command(__unused struct cmdq_item *item, __unused void *data)
|
||||
{
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
/* Get a command for the command queue. */
|
||||
/* Get a single command for command queue with invoke state. */
|
||||
struct cmdq_item *
|
||||
cmdq_get_command(struct cmd_list *cmdlist, struct cmdq_state *state)
|
||||
cmdq_get_one_command(struct cmd *cmd, struct cmdq_state *state,
|
||||
struct cmd_invoke_state *invoke_state)
|
||||
{
|
||||
struct cmdq_item *item, *first = NULL, *last = NULL;
|
||||
struct cmd *cmd;
|
||||
const struct cmd_entry *entry;
|
||||
int created = 0;
|
||||
|
||||
if ((cmd = cmd_list_first(cmdlist)) == NULL)
|
||||
return (cmdq_get_callback(cmdq_empty_command, NULL));
|
||||
|
||||
if (state == NULL) {
|
||||
state = cmdq_new_state(NULL, NULL, 0);
|
||||
created = 1;
|
||||
}
|
||||
|
||||
while (cmd != NULL) {
|
||||
entry = cmd_get_entry(cmd);
|
||||
struct cmdq_item *item;
|
||||
const struct cmd_entry *entry = cmd_get_entry(cmd);
|
||||
|
||||
item = xcalloc(1, sizeof *item);
|
||||
xasprintf(&item->name, "[%s/%p]", entry->name, item);
|
||||
item->type = CMDQ_COMMAND;
|
||||
|
||||
item->group = cmd_get_group(cmd);
|
||||
item->state = cmdq_link_state(state);
|
||||
|
||||
item->cmdlist = cmdlist;
|
||||
item->cmd = cmd;
|
||||
|
||||
cmdlist->references++;
|
||||
log_debug("%s: %s group %u", __func__, item->name, item->group);
|
||||
if (state == NULL)
|
||||
item->state = cmdq_new_state(NULL, NULL, 0);
|
||||
else
|
||||
item->state = cmdq_link_state(state);
|
||||
|
||||
if (first == NULL)
|
||||
first = item;
|
||||
if (last != NULL)
|
||||
last->next = item;
|
||||
last = item;
|
||||
if (invoke_state != NULL)
|
||||
item->invoke_state = cmd_invoke_state_add_ref(invoke_state);
|
||||
|
||||
cmd = cmd_list_next(cmd);
|
||||
}
|
||||
log_debug("%s: %s", __func__, item->name);
|
||||
return (item);
|
||||
}
|
||||
|
||||
if (created)
|
||||
cmdq_free_state(state);
|
||||
return (first);
|
||||
/* Get an invoke continuation for command queue. */
|
||||
struct cmdq_item *
|
||||
cmdq_get_invoke(struct cmd_invoke_state *invoke_state, struct cmdq_state *state)
|
||||
{
|
||||
struct cmdq_item *item;
|
||||
|
||||
item = xcalloc(1, sizeof *item);
|
||||
xasprintf(&item->name, "[invoke/%p]", item);
|
||||
item->type = CMDQ_INVOKE;
|
||||
if (state == NULL)
|
||||
item->state = cmdq_new_state(NULL, NULL, 0);
|
||||
else
|
||||
item->state = cmdq_link_state(state);
|
||||
item->invoke_state = cmd_invoke_state_add_ref(invoke_state);
|
||||
return (item);
|
||||
}
|
||||
|
||||
/* Fill in flag for a command. */
|
||||
@@ -611,7 +557,7 @@ cmdq_fire_command(struct cmdq_item *item)
|
||||
cmdq_add_message(item);
|
||||
if (log_get_level() > 1) {
|
||||
tmp = cmd_print(cmd);
|
||||
log_debug("%s %s: (%u) %s", __func__, name, item->group, tmp);
|
||||
log_debug("%s %s: %s", __func__, name, tmp);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
@@ -690,7 +636,6 @@ cmdq_get_callback1(const char *name, cmdq_cb cb, void *data)
|
||||
xasprintf(&item->name, "[%s/%p]", name, item);
|
||||
item->type = CMDQ_CALLBACK;
|
||||
|
||||
item->group = 0;
|
||||
item->state = cmdq_new_state(NULL, NULL, 0);
|
||||
|
||||
item->cb = cb;
|
||||
@@ -772,17 +717,16 @@ cmdq_next(struct client *c)
|
||||
switch (item->type) {
|
||||
case CMDQ_COMMAND:
|
||||
retval = cmdq_fire_command(item);
|
||||
if (item->invoke_state != NULL)
|
||||
cmd_invoke_result(item->invoke_state, retval);
|
||||
|
||||
/*
|
||||
* If a command returns an error, remove any
|
||||
* subsequent commands in the same group.
|
||||
*/
|
||||
if (retval == CMD_RETURN_ERROR)
|
||||
cmdq_remove_group(item);
|
||||
break;
|
||||
case CMDQ_CALLBACK:
|
||||
retval = cmdq_fire_callback(item);
|
||||
break;
|
||||
case CMDQ_INVOKE:
|
||||
retval = cmd_invoke_fire(item, item->invoke_state);
|
||||
break;
|
||||
default:
|
||||
retval = CMD_RETURN_ERROR;
|
||||
break;
|
||||
@@ -829,7 +773,7 @@ cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
|
||||
u_int number = item->number;
|
||||
|
||||
if (c != NULL && (c->flags & CLIENT_CONTROL))
|
||||
control_write(c, "%%%s %ld %u %d", guard, t, number, flags);
|
||||
control_write_guard(c, guard, t, number, flags);
|
||||
}
|
||||
|
||||
/* Show message from command. */
|
||||
@@ -877,7 +821,18 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
|
||||
|
||||
if (c == NULL) {
|
||||
cmd_get_source(cmd, &file, &line);
|
||||
if (!cfg_finished) {
|
||||
if (file != NULL)
|
||||
cfg_add_cause("%s:%u: %s", file, line, msg);
|
||||
else
|
||||
cfg_add_cause("%s", msg);
|
||||
} else {
|
||||
if (file != NULL) {
|
||||
server_add_message("message: %s:%u: %s", file,
|
||||
line, msg);
|
||||
} else
|
||||
server_add_message("message: %s", msg);
|
||||
}
|
||||
} else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
|
||||
server_add_message("%s message: %s", c->name, msg);
|
||||
if (~c->flags & CLIENT_UTF8) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-refresh-client.c,v 1.55 2026/07/17 08:37:29 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -34,7 +34,7 @@ const struct cmd_entry cmd_refresh_client_entry = {
|
||||
.name = "refresh-client",
|
||||
.alias = "refresh",
|
||||
|
||||
.args = { "A:B:cC:Df:r:F:l::LRSt:U", 0, 1, NULL },
|
||||
.args = { "A:B:cC:Df:r:F:lLRSt:U", 0, 1, NULL },
|
||||
.usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] "
|
||||
"[-C XxY] [-f flags] [-r pane:report] " CMD_TARGET_CLIENT_USAGE
|
||||
" [adjustment]",
|
||||
@@ -46,36 +46,17 @@ const struct cmd_entry cmd_refresh_client_entry = {
|
||||
static void
|
||||
cmd_refresh_client_update_subscription(struct client *tc, const char *value)
|
||||
{
|
||||
char *copy, *split, *name, *what;
|
||||
enum control_sub_type subtype;
|
||||
int subid = -1;
|
||||
char *name, *format;
|
||||
enum monitor_type type;
|
||||
int id;
|
||||
|
||||
copy = name = xstrdup(value);
|
||||
if ((split = strchr(copy, ':')) == NULL) {
|
||||
control_remove_sub(tc, copy);
|
||||
goto out;
|
||||
if (monitor_parse(value, &name, &type, &id, &format) != 0) {
|
||||
control_remove_sub(tc, value);
|
||||
return;
|
||||
}
|
||||
*split++ = '\0';
|
||||
|
||||
what = split;
|
||||
if ((split = strchr(what, ':')) == NULL)
|
||||
goto out;
|
||||
*split++ = '\0';
|
||||
|
||||
if (strcmp(what, "%*") == 0)
|
||||
subtype = CONTROL_SUB_ALL_PANES;
|
||||
else if (sscanf(what, "%%%d", &subid) == 1 && subid >= 0)
|
||||
subtype = CONTROL_SUB_PANE;
|
||||
else if (strcmp(what, "@*") == 0)
|
||||
subtype = CONTROL_SUB_ALL_WINDOWS;
|
||||
else if (sscanf(what, "@%d", &subid) == 1 && subid >= 0)
|
||||
subtype = CONTROL_SUB_WINDOW;
|
||||
else
|
||||
subtype = CONTROL_SUB_SESSION;
|
||||
control_add_sub(tc, name, subtype, subid, split);
|
||||
|
||||
out:
|
||||
free(copy);
|
||||
control_add_sub(tc, name, type, id, format);
|
||||
free(name);
|
||||
free(format);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
@@ -85,7 +66,6 @@ cmd_refresh_client_control_client_size(struct cmd *self, struct cmdq_item *item)
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
const char *size = args_get(args, 'C');
|
||||
u_int w, x, y;
|
||||
struct client_window *cw;
|
||||
|
||||
if (sscanf(size, "@%u:%ux%u", &w, &x, &y) == 3) {
|
||||
if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
|
||||
@@ -95,22 +75,16 @@ cmd_refresh_client_control_client_size(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
log_debug("%s: client %s window @%u: size %ux%u", __func__,
|
||||
tc->name, w, x, y);
|
||||
cw = server_client_add_client_window(tc, w);
|
||||
cw->sx = x;
|
||||
cw->sy = y;
|
||||
control_set_window_size(tc, w, x, y);
|
||||
tc->flags |= CLIENT_WINDOWSIZECHANGED;
|
||||
recalculate_sizes_now(1);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
if (sscanf(size, "@%u:", &w) == 1) {
|
||||
cw = server_client_get_client_window(tc, w);
|
||||
if (cw != NULL) {
|
||||
log_debug("%s: client %s window @%u: no size", __func__,
|
||||
tc->name, w);
|
||||
cw->sx = 0;
|
||||
cw->sy = 0;
|
||||
control_clear_window_size(tc, w);
|
||||
recalculate_sizes_now(1);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -163,42 +137,12 @@ out:
|
||||
free(copy);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_refresh_client_clipboard(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
const char *p;
|
||||
u_int i;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
p = args_get(args, 'l');
|
||||
if (p == NULL) {
|
||||
if (tc->flags & CLIENT_CLIPBOARDBUFFER)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
tc->flags |= CLIENT_CLIPBOARDBUFFER;
|
||||
} else {
|
||||
if (cmd_find_target(&fs, item, p, CMD_FIND_PANE, 0) != 0)
|
||||
return (CMD_RETURN_ERROR);
|
||||
for (i = 0; i < tc->clipboard_npanes; i++) {
|
||||
if (tc->clipboard_panes[i] == fs.wp->id)
|
||||
break;
|
||||
}
|
||||
if (i != tc->clipboard_npanes)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
tc->clipboard_panes = xreallocarray(tc->clipboard_panes,
|
||||
tc->clipboard_npanes + 1, sizeof *tc->clipboard_panes);
|
||||
tc->clipboard_panes[tc->clipboard_npanes++] = fs.wp->id;
|
||||
}
|
||||
tty_clipboard_query(&tc->tty);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_refresh_report(struct tty *tty, const char *value)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
u_int pane;
|
||||
int fg, bg;
|
||||
size_t size = 0;
|
||||
char *copy, *split;
|
||||
|
||||
@@ -215,8 +159,14 @@ cmd_refresh_report(struct tty *tty, const char *value)
|
||||
if (wp == NULL)
|
||||
goto out;
|
||||
|
||||
tty_keys_colours(tty, split, strlen(split), &size, &wp->control_fg,
|
||||
&wp->control_bg);
|
||||
fg = wp->control_fg;
|
||||
bg = wp->control_bg;
|
||||
if (tty_keys_colours(tty, split, strlen(split), &size, &fg, &bg) == 0) {
|
||||
if (bg != wp->control_bg)
|
||||
wp->flags |= PANE_THEMECHANGED;
|
||||
wp->control_fg = fg;
|
||||
wp->control_bg = bg;
|
||||
}
|
||||
|
||||
out:
|
||||
free(copy);
|
||||
@@ -284,8 +234,10 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (args_has(args, 'l'))
|
||||
return (cmd_refresh_client_clipboard(self, item));
|
||||
if (args_has(args, 'l')) {
|
||||
tty_clipboard_query(&tc->tty);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (args_has(args, 'F')) /* -F is an alias for -f */
|
||||
server_client_set_flags(tc, args_get(args, 'F'));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-rename-session.c,v 1.39 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -49,15 +49,17 @@ cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct session *s = target->s;
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
char *newname, *tmp;
|
||||
|
||||
tmp = format_single_from_target(item, args_string(args, 0));
|
||||
newname = session_check_name(tmp);
|
||||
if (newname == NULL) {
|
||||
cmdq_error(item, "invalid session: %s", tmp);
|
||||
if (!check_name(tmp)) {
|
||||
cmdq_error(item, "invalid session name: %s", tmp);
|
||||
free(tmp);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
newname = clean_name(tmp, 0);
|
||||
free(tmp);
|
||||
if (strcmp(newname, s->name) == 0) {
|
||||
free(newname);
|
||||
@@ -69,13 +71,20 @@ cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_session(&fs, s, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_session(ep, "session", s);
|
||||
event_payload_set_string(ep, "old_name", "%s", s->name);
|
||||
event_payload_set_string(ep, "new_name", "%s", newname);
|
||||
|
||||
RB_REMOVE(sessions, &sessions, s);
|
||||
free(s->name);
|
||||
s->name = newname;
|
||||
RB_INSERT(sessions, &sessions, s);
|
||||
|
||||
server_status_session(s);
|
||||
notify_session("session-renamed", s);
|
||||
events_fire("session-renamed", ep);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-rename-window.c,v 1.30 2026/06/29 18:17:28 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -48,15 +48,21 @@ cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct winlink *wl = target->wl;
|
||||
char *newname;
|
||||
char *name;
|
||||
|
||||
newname = format_single_from_target(item, args_string(args, 0));
|
||||
window_set_name(wl->window, newname);
|
||||
name = format_single_from_target(item, args_string(args, 0));
|
||||
if (!check_name(name)) {
|
||||
cmdq_error(item, "invalid window name: %s", name);
|
||||
free(name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
window_set_name(wl->window, name, 0);
|
||||
options_set_number(wl->window->options, "automatic-rename", 0);
|
||||
free(name);
|
||||
|
||||
server_redraw_window_borders(wl->window);
|
||||
server_status_window(wl->window);
|
||||
free(newname);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-resize-pane.c,v 1.68 2026/08/31 07:44:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -29,16 +30,20 @@
|
||||
|
||||
static enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmdq_item *);
|
||||
|
||||
static void cmd_resize_pane_mouse_update(struct client *,
|
||||
static enum cmd_retval cmd_resize_pane_mouse_update(struct cmd *,
|
||||
struct cmdq_item *);
|
||||
static void cmd_resize_pane_mouse_resize_move_floating(
|
||||
struct client *, struct mouse_event *);
|
||||
static void cmd_resize_pane_mouse_resize_tiled(struct client *,
|
||||
struct mouse_event *);
|
||||
|
||||
const struct cmd_entry cmd_resize_pane_entry = {
|
||||
.name = "resize-pane",
|
||||
.alias = "resizep",
|
||||
|
||||
.args = { "DLMRTt:Ux:y:Z", 0, 1, NULL },
|
||||
.usage = "[-DLMRTUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
|
||||
"[adjustment]",
|
||||
.args = { "D::L::MR::Tt:U::x:y:Z", 0, 1, NULL },
|
||||
.usage = "[-MTZ] [-D lines] [-L columns] [-R columns] [-U lines] "
|
||||
"[-x width] [-y height] " CMD_TARGET_PANE_USAGE,
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
@@ -51,23 +56,23 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct key_event *event = cmdq_get_event(item);
|
||||
struct window_pane *wp = target->wp;
|
||||
struct winlink *wl = target->wl;
|
||||
struct window *w = wl->window;
|
||||
struct client *c = cmdq_get_client(item);
|
||||
struct session *s = target->s;
|
||||
const char *errstr;
|
||||
char *cause;
|
||||
u_int adjust;
|
||||
int x, y, status;
|
||||
struct layout_cell *lc = wp->layout_cell;
|
||||
enum layout_type type;
|
||||
const char *errstr, *argval;
|
||||
const char flags[4] = { 'U', 'D', 'L', 'R' };
|
||||
char *cause = NULL, flag;
|
||||
int adjust, x, y, status, opposite = 0;
|
||||
long unsigned i;
|
||||
struct grid *gd = wp->base.grid;
|
||||
|
||||
if (args_has(args, 'T')) {
|
||||
if (!TAILQ_EMPTY(&wp->modes))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
adjust = screen_size_y(&wp->base) - 1 - wp->base.cy;
|
||||
if (adjust > gd->hsize)
|
||||
if (adjust > (int)gd->hsize)
|
||||
adjust = gd->hsize;
|
||||
grid_remove_history(gd, adjust);
|
||||
wp->base.cy += adjust;
|
||||
@@ -75,15 +80,8 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (args_has(args, 'M')) {
|
||||
if (!event->m.valid || cmd_mouse_window(&event->m, &s) == NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (c == NULL || c->session != s)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update;
|
||||
cmd_resize_pane_mouse_update(c, &event->m);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
if (args_has(args, 'M'))
|
||||
return (cmd_resize_pane_mouse_update(self, item));
|
||||
|
||||
if (args_has(args, 'Z')) {
|
||||
if (w->flags & WINDOW_ZOOMED)
|
||||
@@ -94,34 +92,33 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
server_unzoom_window(w);
|
||||
|
||||
if (args_count(args) == 0)
|
||||
adjust = 1;
|
||||
else {
|
||||
adjust = strtonum(args_string(args, 0), 1, INT_MAX, &errstr);
|
||||
if (errstr != NULL) {
|
||||
cmdq_error(item, "adjustment %s", errstr);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
lc = wp->layout_cell; /* may have been replaced by unzoom */
|
||||
|
||||
if (args_has(args, 'x')) {
|
||||
x = args_percentage(args, 'x', 0, INT_MAX, w->sx, &cause);
|
||||
x = args_percentage(args, 'x', 0, PANE_MAXIMUM, w->sx, &cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "width %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (window_pane_is_floating(wp)) {
|
||||
if (layout_resize_floating_pane_to(wp, LAYOUT_LEFTRIGHT,
|
||||
x, &cause) != 0) {
|
||||
cmdq_error(item, "size %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
} else
|
||||
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
|
||||
}
|
||||
if (args_has(args, 'y')) {
|
||||
y = args_percentage(args, 'y', 0, INT_MAX, w->sy, &cause);
|
||||
y = args_percentage(args, 'y', 0, PANE_MAXIMUM, w->sy, &cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "height %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
status = options_get_number(w->options, "pane-border-status");
|
||||
status = window_get_pane_status(w);
|
||||
switch (status) {
|
||||
case PANE_STATUS_TOP:
|
||||
if (y != INT_MAX && wp->yoff == 1)
|
||||
@@ -132,24 +129,231 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
y++;
|
||||
break;
|
||||
}
|
||||
if (window_pane_is_floating(wp)) {
|
||||
if (layout_resize_floating_pane_to(wp, LAYOUT_TOPBOTTOM,
|
||||
y, &cause) != 0) {
|
||||
cmdq_error(item, "size %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
} else
|
||||
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
|
||||
}
|
||||
|
||||
if (args_has(args, 'L'))
|
||||
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust, 1);
|
||||
else if (args_has(args, 'R'))
|
||||
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust, 1);
|
||||
else if (args_has(args, 'U'))
|
||||
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, -adjust, 1);
|
||||
else if (args_has(args, 'D'))
|
||||
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust, 1);
|
||||
server_redraw_window(wl->window);
|
||||
for (i = 0; i < nitems(flags); i++) {
|
||||
flag = flags[i];
|
||||
if (!args_has(args, flag))
|
||||
continue;
|
||||
|
||||
argval = args_get(args, flag);
|
||||
if (argval == NULL) {
|
||||
if (args_count(args) == 0)
|
||||
argval = "1";
|
||||
else
|
||||
argval = args_string(args, 0);
|
||||
}
|
||||
|
||||
adjust = strtonum(argval, INT_MIN, INT_MAX, &errstr);
|
||||
if (errstr != NULL) {
|
||||
cmdq_error(item, "adjustment %s", errstr);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
type = LAYOUT_TOPBOTTOM;
|
||||
if (flag == 'L' || flag == 'R')
|
||||
type = LAYOUT_LEFTRIGHT;
|
||||
|
||||
if (window_pane_is_floating(wp)) {
|
||||
if (flag == 'L' || flag == 'U')
|
||||
opposite = 1;
|
||||
|
||||
if (layout_resize_floating_pane(wp, type, adjust,
|
||||
opposite, &cause) != 0) {
|
||||
cmdq_error(item, "adjustment %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
} else {
|
||||
if (flag == 'L' || flag == 'U')
|
||||
adjust = -adjust;
|
||||
layout_resize_pane(wp, type, adjust, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (lc->parent != NULL)
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_resize_pane_mouse_update(__unused struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct key_event *event = cmdq_get_event(item);
|
||||
struct window_pane *wp = target->wp;
|
||||
struct winlink *wl = target->wl;
|
||||
struct window *w = wl->window;
|
||||
struct client *c = cmdq_get_client(item);
|
||||
struct session *s = target->s;
|
||||
|
||||
if (!event->m.valid)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
wp = cmd_mouse_pane(&event->m, &s, NULL);
|
||||
if (wp == NULL || c == NULL || c->session != s)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
if (!window_pane_is_floating(wp)) {
|
||||
c->tty.mouse_drag_update = cmd_resize_pane_mouse_resize_tiled;
|
||||
cmd_resize_pane_mouse_resize_tiled(c, &event->m);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
window_redraw_active_switch(w, wp);
|
||||
window_set_active_pane(w, wp, 1);
|
||||
|
||||
c->tty.mouse_drag_update = cmd_resize_pane_mouse_resize_move_floating;
|
||||
cmd_resize_pane_mouse_resize_move_floating(c, &event->m);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Resizes or moves the pane by dragging. Resize a floating pane by dragging
|
||||
* the borders or corners. Grabbing an edge only resizes that axis (special
|
||||
* case). Moves the pane if dragging the top border. Since characters are
|
||||
* generally rectangular, to make it easier to grab the corner, the character
|
||||
* next to the corner is also considered the corner.
|
||||
*/
|
||||
static void
|
||||
cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m)
|
||||
cmd_resize_pane_mouse_resize_move_floating(struct client *c,
|
||||
struct mouse_event *m)
|
||||
{
|
||||
struct winlink *wl;
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
struct layout_cell *lc;
|
||||
int y, ly, x, lx, sx, sy, new_sx, new_sy;
|
||||
int left, right;
|
||||
int new_xoff, new_yoff, resizes = 0;
|
||||
|
||||
wp = cmd_mouse_pane(m, NULL, &wl);
|
||||
if (wp == NULL) {
|
||||
c->tty.mouse_drag_update = NULL;
|
||||
return;
|
||||
}
|
||||
w = wl->window;
|
||||
lc = wp->layout_cell;
|
||||
sx = wp->sx;
|
||||
sy = wp->sy;
|
||||
left = wp->xoff - 1;
|
||||
right = wp->xoff + sx;
|
||||
if (window_pane_scrollbar_reserve(wp) &&
|
||||
w->sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||
left -= wp->scrollbar_style.width + wp->scrollbar_style.pad;
|
||||
} else if (window_pane_scrollbar_reserve(wp) &&
|
||||
w->sb_pos == PANE_SCROLLBARS_RIGHT) {
|
||||
right += wp->scrollbar_style.width + wp->scrollbar_style.pad;
|
||||
}
|
||||
|
||||
y = m->y + m->oy; x = m->x + m->ox;
|
||||
if (m->statusat == 0 && y >= (int)m->statuslines)
|
||||
y -= m->statuslines;
|
||||
else if (m->statusat > 0 && y >= m->statusat)
|
||||
y = m->statusat - 1;
|
||||
ly = m->ly + m->oy; lx = m->lx + m->ox;
|
||||
if (m->statusat == 0 && ly >= (int)m->statuslines)
|
||||
ly -= m->statuslines;
|
||||
else if (m->statusat > 0 && ly >= m->statusat)
|
||||
ly = m->statusat - 1;
|
||||
|
||||
if ((lx == left || lx == left + 1) && ly == wp->yoff - 1) {
|
||||
/* Top left corner. */
|
||||
new_sx = lc->g.sx + (lx - x);
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
new_sx = PANE_MINIMUM;
|
||||
new_sy = lc->g.sy + (ly - y);
|
||||
if (new_sy < PANE_MINIMUM)
|
||||
new_sy = PANE_MINIMUM;
|
||||
new_xoff = x + 1; /* because mouse is on border at xoff - 1 */
|
||||
new_yoff = y + 1;
|
||||
layout_set_size(lc, new_sx, new_sy, new_xoff, new_yoff);
|
||||
resizes++;
|
||||
} else if ((lx == right + 1 || lx == right) &&
|
||||
ly == wp->yoff - 1) {
|
||||
/* Top right corner. */
|
||||
new_sx = x - lc->g.xoff;
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
new_sx = PANE_MINIMUM;
|
||||
new_sy = lc->g.sy + (ly - y);
|
||||
if (new_sy < PANE_MINIMUM)
|
||||
new_sy = PANE_MINIMUM;
|
||||
new_yoff = y + 1;
|
||||
layout_set_size(lc, new_sx, new_sy, lc->g.xoff, new_yoff);
|
||||
resizes++;
|
||||
} else if ((lx == left || lx == left + 1) &&
|
||||
ly == wp->yoff + sy) {
|
||||
/* Bottom left corner. */
|
||||
new_sx = lc->g.sx + (lx - x);
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
new_sx = PANE_MINIMUM;
|
||||
new_sy = y - lc->g.yoff;
|
||||
if (new_sy < PANE_MINIMUM)
|
||||
return;
|
||||
new_xoff = x + 1;
|
||||
layout_set_size(lc, new_sx, new_sy, new_xoff, lc->g.yoff);
|
||||
resizes++;
|
||||
} else if ((lx == right + 1 || lx == right) &&
|
||||
ly == wp->yoff + sy) {
|
||||
/* Bottom right corner. */
|
||||
new_sx = x - lc->g.xoff;
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
new_sx = PANE_MINIMUM;
|
||||
new_sy = y - lc->g.yoff;
|
||||
if (new_sy < PANE_MINIMUM)
|
||||
new_sy = PANE_MINIMUM;
|
||||
layout_set_size(lc, new_sx, new_sy, lc->g.xoff, lc->g.yoff);
|
||||
resizes++;
|
||||
} else if (lx == right) {
|
||||
/* Right border. */
|
||||
new_sx = x - lc->g.xoff;
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
return;
|
||||
layout_set_size(lc, new_sx, lc->g.sy, lc->g.xoff, lc->g.yoff);
|
||||
resizes++;
|
||||
} else if (lx == left) {
|
||||
/* Left border. */
|
||||
new_sx = lc->g.sx + (lx - x);
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
return;
|
||||
new_xoff = x + 1;
|
||||
layout_set_size(lc, new_sx, lc->g.sy, new_xoff, lc->g.yoff);
|
||||
resizes++;
|
||||
} else if (ly == wp->yoff + sy) {
|
||||
/* Bottom border. */
|
||||
new_sy = y - lc->g.yoff;
|
||||
if (new_sy < PANE_MINIMUM)
|
||||
return;
|
||||
layout_set_size(lc, lc->g.sx, new_sy, lc->g.xoff, lc->g.yoff);
|
||||
resizes++;
|
||||
} else if (ly == wp->yoff - 1) {
|
||||
/* Top border (move instead of resize). */
|
||||
new_xoff = lc->g.xoff + (x - lx);
|
||||
new_yoff = y + 1;
|
||||
layout_set_size(lc, lc->g.sx, lc->g.sy, new_xoff, new_yoff);
|
||||
resizes++;
|
||||
}
|
||||
if (resizes != 0) {
|
||||
layout_fix_panes(w, NULL);
|
||||
server_redraw_window(w);
|
||||
server_redraw_window_borders(w);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_resize_pane_mouse_resize_tiled(struct client *c, struct mouse_event *m)
|
||||
{
|
||||
struct winlink *wl;
|
||||
struct window *w;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-resize-window.c,v 1.10 2023/06/30 13:19:32 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-respawn-pane.c,v 1.40 2026/07/03 16:09:49 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -34,8 +34,8 @@ const struct cmd_entry cmd_respawn_pane_entry = {
|
||||
.name = "respawn-pane",
|
||||
.alias = "respawnp",
|
||||
|
||||
.args = { "c:e:kt:", 0, -1, NULL },
|
||||
.usage = "[-k] [-c start-directory] [-e environment] "
|
||||
.args = { "c:e:Ekt:", 0, -1, NULL },
|
||||
.usage = "[-Ek] [-c start-directory] [-e environment] "
|
||||
CMD_TARGET_PANE_USAGE " [shell-command [argument ...]]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
@@ -75,6 +75,8 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
sc.cwd = args_get(args, 'c');
|
||||
|
||||
sc.flags = SPAWN_RESPAWN;
|
||||
if (args_has(args, 'E'))
|
||||
sc.flags |= SPAWN_EMPTY;
|
||||
if (args_has(args, 'k'))
|
||||
sc.flags |= SPAWN_KILL;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-respawn-window.c,v 1.51 2026/07/03 16:09:49 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -34,8 +34,8 @@ const struct cmd_entry cmd_respawn_window_entry = {
|
||||
.name = "respawn-window",
|
||||
.alias = "respawnw",
|
||||
|
||||
.args = { "c:e:kt:", 0, -1, NULL },
|
||||
.usage = "[-k] [-c start-directory] [-e environment] "
|
||||
.args = { "c:e:Ekt:", 0, -1, NULL },
|
||||
.usage = "[-Ek] [-c start-directory] [-e environment] "
|
||||
CMD_TARGET_WINDOW_USAGE " [shell-command [argument ...]]",
|
||||
|
||||
.target = { 't', CMD_FIND_WINDOW, 0 },
|
||||
@@ -74,6 +74,8 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
sc.cwd = args_get(args, 'c');
|
||||
|
||||
sc.flags = SPAWN_RESPAWN;
|
||||
if (args_has(args, 'E'))
|
||||
sc.flags |= SPAWN_EMPTY;
|
||||
if (args_has(args, 'k'))
|
||||
sc.flags |= SPAWN_KILL;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-rotate-window.c,v 1.34 2026/06/22 08:47:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -109,6 +109,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
window_set_active_pane(w, wp, 1);
|
||||
cmd_find_from_winlink_pane(current, wl, wp, 0);
|
||||
window_pop_zoom(w);
|
||||
redraw_invalidate_scene(w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-run-shell.c,v 1.94 2026/08/25 06:04:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
@@ -44,9 +44,9 @@ const struct cmd_entry cmd_run_shell_entry = {
|
||||
.name = "run-shell",
|
||||
.alias = "run",
|
||||
|
||||
.args = { "bd:Ct:Es:c:", 0, 1, cmd_run_shell_args_parse },
|
||||
.args = { "bd:Ct:Es:c:", 0, -1, cmd_run_shell_args_parse },
|
||||
.usage = "[-bCE] [-c start-directory] [-d delay] " CMD_TARGET_PANE_USAGE
|
||||
" [shell-command]",
|
||||
" [shell-command [argument ...]]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||
|
||||
@@ -57,7 +57,7 @@ const struct cmd_entry cmd_run_shell_entry = {
|
||||
struct cmd_run_shell_data {
|
||||
struct client *client;
|
||||
char *cmd;
|
||||
struct args_command_state *state;
|
||||
struct cmd_parse_tree *tree;
|
||||
char *cwd;
|
||||
struct cmdq_item *item;
|
||||
struct session *s;
|
||||
@@ -90,8 +90,8 @@ cmd_run_shell_print(struct job *job, const char *msg)
|
||||
cmdq_print(cdata->item, "%s", msg);
|
||||
return;
|
||||
}
|
||||
if (cdata->item != NULL && cdata->client != NULL)
|
||||
wp = server_client_get_pane(cdata->client);
|
||||
if (cdata->client != NULL && cdata->client->session != NULL)
|
||||
wp = cdata->client->session->curw->window->active;
|
||||
if (wp == NULL && cmd_find_from_nothing(&fs, 0) == 0)
|
||||
wp = fs.wp;
|
||||
if (wp == NULL)
|
||||
@@ -100,7 +100,8 @@ cmd_run_shell_print(struct job *job, const char *msg)
|
||||
|
||||
wme = TAILQ_FIRST(&wp->modes);
|
||||
if (wme == NULL || wme->mode != &window_view_mode)
|
||||
window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL);
|
||||
window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL,
|
||||
NULL);
|
||||
window_copy_add(wp, 1, "%s", msg);
|
||||
}
|
||||
|
||||
@@ -115,9 +116,11 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct session *s = target->s;
|
||||
struct window_pane *wp = target->wp;
|
||||
const char *delay, *cmd;
|
||||
struct format_tree *ft;
|
||||
double d;
|
||||
struct timeval tv;
|
||||
char *end;
|
||||
char *end, key[16], *cause = NULL;
|
||||
u_int i;
|
||||
int wait = !args_has(args, 'b');
|
||||
|
||||
if ((delay = args_get(args, 'd')) != NULL) {
|
||||
@@ -126,17 +129,31 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cmdq_error(item, "invalid delay time: %s", delay);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
} else if (args_count(args) == 0)
|
||||
} else {
|
||||
if (args_count(args) == 0)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
cdata = xcalloc(1, sizeof *cdata);
|
||||
if (!args_has(args, 'C')) {
|
||||
cmd = args_string(args, 0);
|
||||
if (cmd != NULL)
|
||||
cdata->cmd = format_single_from_target(item, cmd);
|
||||
if (cmd != NULL) {
|
||||
ft = format_create_from_target(item);
|
||||
for (i = 1; i < args_count(args); i++) {
|
||||
xsnprintf(key, sizeof key, "%u", i);
|
||||
format_add(ft, key, "%s", args_string(args, i));
|
||||
}
|
||||
cdata->cmd = format_expand(ft, cmd);
|
||||
format_free(ft);
|
||||
}
|
||||
} else {
|
||||
cdata->state = args_make_commands_prepare(self, item, 0, NULL,
|
||||
wait, 1);
|
||||
cdata->tree = args_to_commands(self, item, 0, NULL, 1, &cause);
|
||||
if (cdata->tree == NULL) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
cmd_run_shell_free(cdata);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
if (args_has(args, 't') && wp != NULL)
|
||||
@@ -153,6 +170,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
if (cdata->client != NULL)
|
||||
cdata->client->references++;
|
||||
|
||||
if (args_has(args, 'c'))
|
||||
cdata->cwd = xstrdup(args_get(args, 'c'));
|
||||
else
|
||||
@@ -161,18 +179,20 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'E'))
|
||||
cdata->flags |= JOB_SHOWSTDERR;
|
||||
|
||||
if (s != NULL) {
|
||||
cdata->s = s;
|
||||
if (s != NULL)
|
||||
session_add_ref(s, __func__);
|
||||
}
|
||||
|
||||
evtimer_set(&cdata->timer, cmd_run_shell_timer, cdata);
|
||||
if (delay != NULL) {
|
||||
if (delay == NULL)
|
||||
event_active(&cdata->timer, EV_TIMEOUT, 1);
|
||||
else {
|
||||
timerclear(&tv);
|
||||
tv.tv_sec = (time_t)d;
|
||||
tv.tv_usec = (d - (double)tv.tv_sec) * 1000000U;
|
||||
evtimer_add(&cdata->timer, &tv);
|
||||
} else
|
||||
event_active(&cdata->timer, EV_TIMEOUT, 1);
|
||||
}
|
||||
|
||||
if (!wait)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
@@ -186,10 +206,9 @@ cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
|
||||
struct client *c = cdata->client;
|
||||
const char *cmd = cdata->cmd;
|
||||
struct cmdq_item *item = cdata->item, *new_item;
|
||||
struct cmd_list *cmdlist;
|
||||
char *error;
|
||||
struct cmdq_state *cs = NULL;
|
||||
|
||||
if (cdata->state == NULL) {
|
||||
if (cdata->tree == NULL) {
|
||||
if (cmd == NULL) {
|
||||
if (cdata->item != NULL)
|
||||
cmdq_continue(cdata->item);
|
||||
@@ -198,26 +217,27 @@ cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
|
||||
}
|
||||
if (job_run(cmd, 0, NULL, NULL, cdata->s, cdata->cwd, NULL,
|
||||
cmd_run_shell_callback, cmd_run_shell_free, cdata,
|
||||
cdata->flags, -1, -1) == NULL)
|
||||
cdata->flags, -1, -1) == NULL) {
|
||||
if (cdata->item == NULL)
|
||||
status_message_set(c, -1, 1, 0, 0,
|
||||
"failed to run command: %s", cmd);
|
||||
else {
|
||||
cmdq_error(cdata->item,
|
||||
"failed to run command: %s", cmd);
|
||||
cmdq_continue(cdata->item);
|
||||
}
|
||||
cmd_run_shell_free(cdata);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
cmdlist = args_make_commands(cdata->state, 0, NULL, &error);
|
||||
if (cmdlist == NULL) {
|
||||
if (cdata->item == NULL) {
|
||||
*error = toupper((u_char)*error);
|
||||
status_message_set(c, -1, 1, 0, 0, "%s", error);
|
||||
} else
|
||||
cmdq_error(cdata->item, "%s", error);
|
||||
free(error);
|
||||
} else if (item == NULL) {
|
||||
new_item = cmdq_get_command(cmdlist, NULL);
|
||||
if (item != NULL)
|
||||
cs = cmdq_get_state(item);
|
||||
new_item = cmd_invoke_get(cdata->tree, cs, NULL);
|
||||
if (item == NULL)
|
||||
cmdq_append(c, new_item);
|
||||
} else {
|
||||
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
|
||||
else
|
||||
cmdq_insert_after(item, new_item);
|
||||
}
|
||||
|
||||
if (cdata->item != NULL)
|
||||
cmdq_continue(cdata->item);
|
||||
@@ -285,8 +305,7 @@ cmd_run_shell_free(void *data)
|
||||
session_remove_ref(cdata->s, __func__);
|
||||
if (cdata->client != NULL)
|
||||
server_client_unref(cdata->client);
|
||||
if (cdata->state != NULL)
|
||||
args_make_commands_free(cdata->state);
|
||||
cmd_parse_free(cdata->tree);
|
||||
free(cdata->cwd);
|
||||
free(cdata->cmd);
|
||||
free(cdata);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-save-buffer.c,v 1.57 2025/10/28 07:32:26 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-select-layout.c,v 1.43 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -90,7 +90,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
|
||||
previous = 1;
|
||||
|
||||
oldlayout = w->old_layout;
|
||||
w->old_layout = layout_dump(w->layout_root);
|
||||
w->old_layout = layout_dump(w, w->layout_root);
|
||||
|
||||
if (next || previous) {
|
||||
if (next)
|
||||
@@ -139,7 +139,7 @@ changed:
|
||||
free(oldlayout);
|
||||
recalculate_sizes();
|
||||
server_redraw_window(w);
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
error:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-select-pane.c,v 1.78 2026/08/20 09:19:24 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -80,6 +80,69 @@ cmd_select_pane_redraw(struct window *w)
|
||||
}
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_select_pane_marked_pane(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
struct winlink *wl = target->wl;
|
||||
struct window_pane *wp = target->wp, *lwp = NULL, *mwp;
|
||||
struct session *s = target->s;
|
||||
|
||||
if (args_has(args, 'm') && !window_pane_is_visible(wp))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (server_check_marked())
|
||||
lwp = marked_pane.wp;
|
||||
|
||||
if (args_has(args, 'M') || server_is_marked(s, wl, wp))
|
||||
server_clear_marked();
|
||||
else
|
||||
server_set_marked(s, wl, wp);
|
||||
mwp = marked_pane.wp;
|
||||
|
||||
ep = event_payload_create();
|
||||
if (mwp != NULL)
|
||||
cmd_find_from_pane(&fs, mwp, 0);
|
||||
else if (lwp != NULL)
|
||||
cmd_find_from_pane(&fs, lwp, 0);
|
||||
else
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
if (mwp != NULL) {
|
||||
event_payload_set_pane(ep, "pane", mwp);
|
||||
event_payload_set_pane(ep, "new_pane", mwp);
|
||||
event_payload_set_window(ep, "window", mwp->window);
|
||||
} else if (lwp != NULL) {
|
||||
event_payload_set_pane(ep, "pane", lwp);
|
||||
event_payload_set_window(ep, "window", lwp->window);
|
||||
} else {
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
}
|
||||
if (lwp != NULL)
|
||||
event_payload_set_pane(ep, "old_pane", lwp);
|
||||
event_payload_set_int(ep, "marked", mwp != NULL);
|
||||
events_fire("marked-pane-changed", ep);
|
||||
|
||||
if (lwp != NULL) {
|
||||
lwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||
server_redraw_window_borders(lwp->window);
|
||||
server_status_window(lwp->window);
|
||||
}
|
||||
if (mwp != NULL) {
|
||||
mwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||
server_redraw_window_borders(mwp->window);
|
||||
server_status_window(mwp->window);
|
||||
}
|
||||
if (window_pane_is_floating(wp)) {
|
||||
window_redraw_active_switch(wp->window, wp);
|
||||
window_set_active_pane(wp->window, wp, 1);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
@@ -87,15 +150,17 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
const struct cmd_entry *entry = cmd_get_entry(self);
|
||||
struct cmd_find_state *current = cmdq_get_current(item);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct client *c = cmdq_get_client(item);
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
struct winlink *wl = target->wl;
|
||||
struct window *w = wl->window;
|
||||
struct session *s = target->s;
|
||||
struct window_pane *wp = target->wp, *activewp, *lastwp, *markedwp;
|
||||
struct window_pane *wp = target->wp, *lastwp;
|
||||
struct options *oo = wp->options;
|
||||
char *title;
|
||||
const char *style;
|
||||
struct options_entry *o;
|
||||
int visible, Zflag = args_has(args, 'Z');
|
||||
|
||||
if (entry == &cmd_last_pane_entry || args_has(args, 'l')) {
|
||||
/*
|
||||
@@ -103,7 +168,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
* spawned without being visited (for example split-window -d).
|
||||
*/
|
||||
lastwp = TAILQ_FIRST(&w->last_panes);
|
||||
if (lastwp == NULL && window_count_panes(w) == 2) {
|
||||
if (lastwp == NULL && window_count_panes(w, 1) == 2) {
|
||||
lastwp = TAILQ_PREV(w->active, window_panes, entry);
|
||||
if (lastwp == NULL)
|
||||
lastwp = TAILQ_NEXT(w->active, entry);
|
||||
@@ -121,47 +186,25 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
server_redraw_window_borders(lastwp->window);
|
||||
server_status_window(lastwp->window);
|
||||
} else {
|
||||
if (window_push_zoom(w, 0, args_has(args, 'Z')))
|
||||
if (w->modal != NULL && lastwp != w->modal)
|
||||
visible = 1;
|
||||
else
|
||||
visible = window_pane_is_visible(lastwp);
|
||||
if (!visible && window_push_zoom(w, 0, Zflag))
|
||||
server_redraw_window(w);
|
||||
window_redraw_active_switch(w, lastwp);
|
||||
if (window_set_active_pane(w, lastwp, 1)) {
|
||||
cmd_find_from_winlink(current, wl, 0);
|
||||
cmd_select_pane_redraw(w);
|
||||
}
|
||||
if (window_pop_zoom(w))
|
||||
if (!visible && window_pop_zoom(w))
|
||||
server_redraw_window(w);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (args_has(args, 'm') || args_has(args, 'M')) {
|
||||
if (args_has(args, 'm') && !window_pane_visible(wp))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (server_check_marked())
|
||||
lastwp = marked_pane.wp;
|
||||
else
|
||||
lastwp = NULL;
|
||||
|
||||
if (args_has(args, 'M') || server_is_marked(s, wl, wp))
|
||||
server_clear_marked();
|
||||
else
|
||||
server_set_marked(s, wl, wp);
|
||||
markedwp = marked_pane.wp;
|
||||
|
||||
if (lastwp != NULL) {
|
||||
lastwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
|
||||
PANE_THEMECHANGED);
|
||||
server_redraw_window_borders(lastwp->window);
|
||||
server_status_window(lastwp->window);
|
||||
}
|
||||
if (markedwp != NULL) {
|
||||
markedwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
|
||||
PANE_THEMECHANGED);
|
||||
server_redraw_window_borders(markedwp->window);
|
||||
server_status_window(markedwp->window);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
if (args_has(args, 'm') || args_has(args, 'M'))
|
||||
return (cmd_select_pane_marked_pane(self, item));
|
||||
|
||||
style = args_get(args, 'P');
|
||||
if (style != NULL) {
|
||||
@@ -213,8 +256,14 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
if (args_has(args, 'T')) {
|
||||
title = format_single_from_target(item, args_get(args, 'T'));
|
||||
if (screen_set_title(&wp->base, title)) {
|
||||
notify_pane("pane-title-changed", wp);
|
||||
if (screen_set_title(&wp->base, title, 0)) {
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
event_payload_set_string(ep, "new_title", "%s", title);
|
||||
events_fire("pane-title-changed", ep);
|
||||
server_redraw_window_borders(wp->window);
|
||||
server_status_window(wp->window);
|
||||
}
|
||||
@@ -222,22 +271,20 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE))
|
||||
activewp = server_client_get_pane(c);
|
||||
else
|
||||
activewp = w->active;
|
||||
if (wp == activewp)
|
||||
if (wp == w->active)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (window_push_zoom(w, 0, args_has(args, 'Z')))
|
||||
if (w->modal != NULL && wp != w->modal)
|
||||
visible = 1;
|
||||
else
|
||||
visible = window_pane_is_visible(wp);
|
||||
if (!visible && window_push_zoom(w, 0, Zflag))
|
||||
server_redraw_window(w);
|
||||
window_redraw_active_switch(w, wp);
|
||||
if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE))
|
||||
server_client_set_pane(c, wp);
|
||||
else if (window_set_active_pane(w, wp, 1))
|
||||
if (window_set_active_pane(w, wp, 1))
|
||||
cmd_find_from_winlink_pane(current, wl, wp, 0);
|
||||
cmdq_insert_hook(s, item, current, "after-select-pane");
|
||||
cmd_select_pane_redraw(w);
|
||||
if (window_pop_zoom(w))
|
||||
if (!visible && window_pop_zoom(w))
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-select-window.c,v 1.30 2021/08/21 10:22:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-send-keys.c,v 1.81 2026/06/11 19:13:34 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -39,7 +39,8 @@ const struct cmd_entry cmd_send_keys_entry = {
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG|CMD_CLIENT_CANFAIL,
|
||||
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG|CMD_CLIENT_CANFAIL|
|
||||
CMD_READONLY,
|
||||
.exec = cmd_send_keys_exec
|
||||
};
|
||||
|
||||
@@ -69,6 +70,7 @@ cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after,
|
||||
struct key_table *table = NULL;
|
||||
struct key_binding *bd;
|
||||
struct key_event *event;
|
||||
struct cmdq_item *new_after = after;
|
||||
|
||||
if (args_has(args, 'K')) {
|
||||
if (tc == NULL)
|
||||
@@ -76,10 +78,16 @@ cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after,
|
||||
event = xcalloc(1, sizeof *event);
|
||||
event->key = key|KEYC_SENT;
|
||||
memset(&event->m, 0, sizeof event->m);
|
||||
if (server_client_handle_key(tc, event) == 0) {
|
||||
if (after == NULL) {
|
||||
if (server_client_handle_key(tc, event) != 0)
|
||||
return (item);
|
||||
} else {
|
||||
if (server_client_handle_key_after(tc, event, after,
|
||||
&new_after) != 0)
|
||||
return (new_after);
|
||||
}
|
||||
free(event->buf);
|
||||
free(event);
|
||||
}
|
||||
return (item);
|
||||
}
|
||||
|
||||
@@ -167,6 +175,11 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
u_int count = args_count(args);
|
||||
char *cause = NULL;
|
||||
|
||||
if (tc != NULL && tc->flags & CLIENT_READONLY && !args_has(args, 'X')) {
|
||||
cmdq_error(item, "client is read-only");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (args_has(args, 'N')) {
|
||||
np = args_strtonum_and_expand(args, 'N', 1, UINT_MAX, item,
|
||||
&cause);
|
||||
@@ -223,8 +236,10 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (count == 0) {
|
||||
if (args_has(args, 'N') || args_has(args, 'R'))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
after = args_has(args, 'K') ? item : NULL;
|
||||
for (; np != 0; np--)
|
||||
cmd_send_keys_inject_key(item, NULL, args, event->key);
|
||||
after = cmd_send_keys_inject_key(item, after, args,
|
||||
event->key);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-server-access.c,v 1.6 2026/06/09 12:58:40 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021 Dallas Lyons <dallasdlyons@gmail.com>
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -37,66 +38,71 @@ const struct cmd_entry cmd_server_access_entry = {
|
||||
.name = "server-access",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "adlrw", 0, 1, NULL },
|
||||
.usage = "[-adlrw] " CMD_TARGET_PANE_USAGE " [user]",
|
||||
.args = { "adglrw", 0, 1, NULL },
|
||||
.usage = "[-adglrw] " CMD_TARGET_PANE_USAGE " [user|group]",
|
||||
|
||||
.flags = CMD_CLIENT_CANFAIL,
|
||||
.exec = cmd_server_access_exec
|
||||
};
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_server_access_deny(struct cmdq_item *item, struct passwd *pw)
|
||||
cmd_server_access_deny(struct cmdq_item *item, id_t id, int flags,
|
||||
const char *type, const char *name)
|
||||
{
|
||||
struct client *loop;
|
||||
struct server_acl_user *user;
|
||||
uid_t uid;
|
||||
|
||||
if ((user = server_acl_user_find(pw->pw_uid)) == NULL) {
|
||||
cmdq_error(item, "user %s not found", pw->pw_name);
|
||||
if (!server_acl_find(id, flags)) {
|
||||
cmdq_error(item, "%s %s not found", type, name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
TAILQ_FOREACH(loop, &clients, entry) {
|
||||
uid = proc_get_peer_uid(loop->peer);
|
||||
if (uid == server_acl_get_uid(user)) {
|
||||
loop->exit_message = xstrdup("access not allowed");
|
||||
loop->flags |= CLIENT_EXIT;
|
||||
}
|
||||
}
|
||||
server_acl_user_deny(pw->pw_uid);
|
||||
|
||||
server_acl_deny(id, flags);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_server_access_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct client *c = cmdq_get_target_client(item);
|
||||
char *name;
|
||||
struct passwd *pw = NULL;
|
||||
char *arg;
|
||||
const char *name = NULL, *type;
|
||||
struct passwd *pw;
|
||||
struct group *gr;
|
||||
id_t id;
|
||||
int flags = 0;
|
||||
|
||||
if (args_has(args, 'l')) {
|
||||
server_acl_display(item);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
if (args_count(args) == 0) {
|
||||
cmdq_error(item, "missing user argument");
|
||||
cmdq_error(item, "missing user or group argument");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
name = format_single(item, args_string(args, 0), c, NULL, NULL, NULL);
|
||||
if (*name != '\0')
|
||||
pw = getpwnam(name);
|
||||
if (pw == NULL) {
|
||||
cmdq_error(item, "unknown user: %s", name);
|
||||
arg = format_single(item, args_string(args, 0), c, NULL, NULL, NULL);
|
||||
if (args_has(args, 'g')) {
|
||||
type = "group";
|
||||
if ((gr = getgrnam(arg)) != NULL) {
|
||||
id = gr->gr_gid;
|
||||
name = gr->gr_name;
|
||||
flags |= SERVER_ACL_IS_GROUP;
|
||||
}
|
||||
} else {
|
||||
type = "user";
|
||||
if ((pw = getpwnam(arg)) != NULL) {
|
||||
id = pw->pw_uid;
|
||||
name = pw->pw_name;
|
||||
}
|
||||
}
|
||||
if (name == NULL) {
|
||||
cmdq_error(item, "unknown %s: %s", type, arg);
|
||||
free(arg);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
free(name);
|
||||
free(arg);
|
||||
|
||||
if (pw->pw_uid == 0 || pw->pw_uid == getuid()) {
|
||||
if ((~flags & SERVER_ACL_IS_GROUP) && (id == 0 || id == getuid())) {
|
||||
cmdq_error(item, "%s owns the server, can't change access",
|
||||
pw->pw_name);
|
||||
name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
@@ -110,36 +116,35 @@ cmd_server_access_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
|
||||
if (args_has(args, 'd'))
|
||||
return (cmd_server_access_deny(item, pw));
|
||||
return (cmd_server_access_deny(item, id, flags, type, name));
|
||||
if (args_has(args, 'a')) {
|
||||
if (server_acl_user_find(pw->pw_uid) != NULL) {
|
||||
cmdq_error(item, "user %s is already added",
|
||||
pw->pw_name);
|
||||
if (server_acl_find(id, flags)) {
|
||||
cmdq_error(item, "%s %s is already added", type, name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
server_acl_user_allow(pw->pw_uid);
|
||||
server_acl_allow(id, flags);
|
||||
/* Do not return - allow -r or -w with -a. */
|
||||
} else if (args_has(args, 'r') || args_has(args, 'w')) {
|
||||
/* -r or -w implies -a if user does not exist. */
|
||||
if (server_acl_user_find(pw->pw_uid) == NULL)
|
||||
server_acl_user_allow(pw->pw_uid);
|
||||
/* -r or -w implies -a if the entry does not exist. */
|
||||
if (!server_acl_find(id, flags))
|
||||
server_acl_allow(id, flags);
|
||||
}
|
||||
|
||||
if (args_has(args, 'w')) {
|
||||
if (server_acl_user_find(pw->pw_uid) == NULL) {
|
||||
cmdq_error(item, "user %s not found", pw->pw_name);
|
||||
if (!server_acl_find(id, flags)) {
|
||||
cmdq_error(item, "%s %s not found", type, name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
server_acl_user_allow_write(pw->pw_uid);
|
||||
server_acl_allow_write(id, flags);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (args_has(args, 'r')) {
|
||||
if (server_acl_user_find(pw->pw_uid) == NULL) {
|
||||
cmdq_error(item, "user %s not found", pw->pw_name);
|
||||
if (!server_acl_find(id, flags)) {
|
||||
cmdq_error(item, "%s %s not found", type, name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
server_acl_user_deny_write(pw->pw_uid);
|
||||
server_acl_deny_write(id, flags);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-set-buffer.c,v 1.38 2026/08/24 07:05:23 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -57,30 +57,30 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct paste_buffer *pb;
|
||||
char *bufdata, *cause;
|
||||
const char *bufname, *olddata;
|
||||
size_t bufsize, newsize;
|
||||
struct paste_buffer *pb = NULL;
|
||||
char *bufname = NULL, *bufdata = NULL, *cause = NULL;
|
||||
const char *olddata;
|
||||
size_t bufsize = 0, newsize;
|
||||
|
||||
bufname = args_get(args, 'b');
|
||||
if (bufname == NULL)
|
||||
pb = NULL;
|
||||
else
|
||||
if (args_get(args, 'b') != NULL) {
|
||||
bufname = xstrdup(args_get(args, 'b'));
|
||||
pb = paste_get_name(bufname);
|
||||
}
|
||||
|
||||
if (cmd_get_entry(self) == &cmd_delete_buffer_entry) {
|
||||
if (pb == NULL) {
|
||||
if (bufname != NULL) {
|
||||
cmdq_error(item, "unknown buffer: %s", bufname);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
pb = paste_get_top(&bufname);
|
||||
}
|
||||
if (pb == NULL) {
|
||||
cmdq_error(item, "no buffer");
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
paste_free(pb);
|
||||
free(bufname);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -88,31 +88,30 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (pb == NULL) {
|
||||
if (bufname != NULL) {
|
||||
cmdq_error(item, "unknown buffer: %s", bufname);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
pb = paste_get_top(&bufname);
|
||||
}
|
||||
if (pb == NULL) {
|
||||
cmdq_error(item, "no buffer");
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
free(bufname);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (args_count(args) != 1) {
|
||||
cmdq_error(item, "no data specified");
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
if ((newsize = strlen(args_string(args, 0))) == 0)
|
||||
if ((newsize = strlen(args_string(args, 0))) == 0) {
|
||||
free(bufname);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
bufsize = 0;
|
||||
bufdata = NULL;
|
||||
}
|
||||
|
||||
if (args_has(args, 'a') && pb != NULL) {
|
||||
olddata = paste_buffer_data(pb, &bufsize);
|
||||
@@ -126,12 +125,17 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
if (paste_set(bufdata, bufsize, bufname, &cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(bufdata);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
if (args_has(args, 'w') && tc != NULL)
|
||||
tty_set_selection(&tc->tty, "", bufdata, bufsize);
|
||||
|
||||
free(bufname);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
free(bufdata);
|
||||
free(bufname);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-set-environment.c,v 1.29 2025/04/09 06:27:43 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
196
cmd-set-option.c
196
cmd-set-option.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-set-option.c,v 1.146 2026/07/10 15:20:06 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -31,6 +31,10 @@ static enum args_parse_type cmd_set_option_args_parse(struct args *,
|
||||
u_int, char **);
|
||||
static enum cmd_retval cmd_set_option_exec(struct cmd *,
|
||||
struct cmdq_item *);
|
||||
static enum cmd_retval cmd_set_hook_event_exec(struct cmd *,
|
||||
struct cmdq_item *);
|
||||
static enum cmd_retval cmd_set_hook_monitor_exec(struct cmdq_item *,
|
||||
struct args *, int);
|
||||
|
||||
const struct cmd_entry cmd_set_option_entry = {
|
||||
.name = "set-option",
|
||||
@@ -62,8 +66,9 @@ const struct cmd_entry cmd_set_hook_entry = {
|
||||
.name = "set-hook",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "agpRt:uw", 1, 2, cmd_set_option_args_parse },
|
||||
.usage = "[-agpRuw] " CMD_TARGET_PANE_USAGE " hook [command]",
|
||||
.args = { "agpERTt:uB:w", 0, 2, cmd_set_option_args_parse },
|
||||
.usage = "[-agpERTuw] [-B name:what:format] " CMD_TARGET_PANE_USAGE " "
|
||||
"[hook] [command]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||
|
||||
@@ -72,14 +77,152 @@ const struct cmd_entry cmd_set_hook_entry = {
|
||||
};
|
||||
|
||||
static enum args_parse_type
|
||||
cmd_set_option_args_parse(__unused struct args *args, u_int idx,
|
||||
cmd_set_option_args_parse(struct args *args, u_int idx,
|
||||
__unused char **cause)
|
||||
{
|
||||
if (args_has(args, 'B'))
|
||||
return (ARGS_PARSE_COMMANDS_OR_STRING);
|
||||
if (idx == 1)
|
||||
return (ARGS_PARSE_COMMANDS_OR_STRING);
|
||||
return (ARGS_PARSE_STRING);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_set_hook_event_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct event_payload *ep;
|
||||
struct client *c;
|
||||
char *argument;
|
||||
|
||||
if (args_count(args) == 0) {
|
||||
cmdq_error(item, "missing argument");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (args_count(args) != 1) {
|
||||
cmdq_error(item, "too many arguments");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
argument = format_single_from_target(item, args_string(args, 0));
|
||||
if (*argument != '@') {
|
||||
cmdq_error(item, "event name must start with @");
|
||||
free(argument);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
ep = event_payload_create();
|
||||
event_payload_set_target(ep, target);
|
||||
c = cmdq_get_client(item);
|
||||
if (c != NULL)
|
||||
event_payload_set_client(ep, "client", c);
|
||||
if (target->s != NULL)
|
||||
event_payload_set_session(ep, "session", target->s);
|
||||
if (target->w != NULL)
|
||||
event_payload_set_window(ep, "window", target->w);
|
||||
if (target->wl != NULL)
|
||||
event_payload_set_int(ep, "window_index", target->wl->idx);
|
||||
else if (target->idx != -1)
|
||||
event_payload_set_int(ep, "window_index", target->idx);
|
||||
if (target->wp != NULL)
|
||||
event_payload_set_pane(ep, "pane", target->wp);
|
||||
events_fire(argument, ep);
|
||||
free(argument);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_set_hook_monitor_exec(struct cmdq_item *item, struct args *args, int window)
|
||||
{
|
||||
struct cmd_find_state *target = cmdq_get_target(item), fs;
|
||||
struct options *oo;
|
||||
struct options_entry *o;
|
||||
struct session *s = NULL;
|
||||
char *cause = NULL, *name = NULL, *format = NULL;
|
||||
char *expanded = NULL, *newvalue = NULL;
|
||||
const char *value, *old;
|
||||
enum monitor_type type;
|
||||
int id, scope, flags = 0;
|
||||
|
||||
if (args_count(args) > 1) {
|
||||
cmdq_error(item, "too many arguments");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
value = args_get(args, 'B');
|
||||
if (args_has(args, 'u')) {
|
||||
if (monitor_parse(value, &name, &type, &id, &format) != 0)
|
||||
name = xstrdup(value);
|
||||
free(format);
|
||||
format = NULL;
|
||||
} else {
|
||||
if (monitor_parse(value, &name, &type, &id, &format) != 0) {
|
||||
cmdq_error(item, "invalid subscription: %s", value);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
if (*name != '@') {
|
||||
cmdq_error(item, "monitor hook name must start with @");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
scope = options_scope_from_name(args, window, name, target, &oo,
|
||||
&cause);
|
||||
if (scope == OPTIONS_TABLE_NONE) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
goto fail;
|
||||
}
|
||||
cmd_find_copy_state(&fs, target);
|
||||
|
||||
if (args_has(args, 'u')) {
|
||||
hooks_monitor_remove(oo, name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (args_count(args) != 0) {
|
||||
value = args_string(args, 0);
|
||||
if (args_has(args, 'F')) {
|
||||
expanded = format_single_from_target(item, value);
|
||||
value = expanded;
|
||||
}
|
||||
o = options_get_only(oo, name);
|
||||
if (!args_has(args, 'o') || o == NULL) {
|
||||
if (args_has(args, 'a') && o != NULL) {
|
||||
old = options_get_string(oo, name);
|
||||
xasprintf(&newvalue, "%s%s", old, value);
|
||||
value = newvalue;
|
||||
}
|
||||
options_set_string(oo, name, 0, "%s", value);
|
||||
options_push_changes(name);
|
||||
}
|
||||
}
|
||||
|
||||
if (oo != global_options &&
|
||||
oo != global_s_options &&
|
||||
oo != global_w_options)
|
||||
s = target->s;
|
||||
if (args_has(args, 'T'))
|
||||
flags |= MONITOR_NOTIFY_TRUE;
|
||||
hooks_monitor_add(item, oo, name, type, id, format, flags, &fs, s);
|
||||
|
||||
out:
|
||||
free(newvalue);
|
||||
free(expanded);
|
||||
free(name);
|
||||
free(format);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
free(newvalue);
|
||||
free(expanded);
|
||||
free(name);
|
||||
free(format);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
@@ -89,26 +232,34 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct window_pane *loop;
|
||||
struct options *oo;
|
||||
struct options_entry *parent, *o, *po;
|
||||
char *name, *argument, *expanded = NULL;
|
||||
char *cause;
|
||||
char *name, *argument, *cause;
|
||||
char *expanded = NULL, *array_key = NULL;
|
||||
const char *value;
|
||||
int window, idx, already, error, ambiguous;
|
||||
int window, already, error, ambiguous;
|
||||
int scope;
|
||||
|
||||
window = (cmd_get_entry(self) == &cmd_set_window_option_entry);
|
||||
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'E'))
|
||||
return (cmd_set_hook_event_exec(self, item));
|
||||
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'B'))
|
||||
return (cmd_set_hook_monitor_exec(item, args, window));
|
||||
if (args_count(args) == 0) {
|
||||
cmdq_error(item, "missing argument");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
/* Expand argument. */
|
||||
argument = format_single_from_target(item, args_string(args, 0));
|
||||
|
||||
/* If set-hook -R, fire the hook straight away. */
|
||||
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'R')) {
|
||||
notify_hook(item, argument);
|
||||
hooks_run(item, argument);
|
||||
free(argument);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
/* Parse option name and index. */
|
||||
name = options_match(argument, &idx, &ambiguous);
|
||||
/* Parse option name and array key. */
|
||||
name = options_match(argument, &array_key, &ambiguous);
|
||||
if (name == NULL) {
|
||||
if (args_has(args, 'q'))
|
||||
goto out;
|
||||
@@ -140,21 +291,23 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
o = options_get_only(oo, name);
|
||||
parent = options_get(oo, name);
|
||||
|
||||
/* Check that array options and indexes match up. */
|
||||
if (idx != -1 && (*name == '@' || !options_is_array(parent))) {
|
||||
/* Check that array options and keys match up. */
|
||||
if (array_key != NULL && (*name == '@' || !options_is_array(parent))) {
|
||||
cmdq_error(item, "not an array: %s", argument);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* With -o, check this option is not already set. */
|
||||
if (!args_has(args, 'u') && args_has(args, 'o')) {
|
||||
if (idx == -1)
|
||||
if (array_key == NULL)
|
||||
already = (o != NULL);
|
||||
else {
|
||||
if (o == NULL)
|
||||
already = 0;
|
||||
else if (options_array_get(o, array_key) != NULL)
|
||||
already = 1;
|
||||
else
|
||||
already = (options_array_get(o, idx) != NULL);
|
||||
already = 0;
|
||||
}
|
||||
if (already) {
|
||||
if (args_has(args, 'q'))
|
||||
@@ -170,7 +323,8 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
po = options_get_only(loop->options, name);
|
||||
if (po == NULL)
|
||||
continue;
|
||||
if (options_remove_or_default(po, idx, &cause) != 0) {
|
||||
if (options_remove_or_default(po, array_key,
|
||||
&cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
goto fail;
|
||||
@@ -180,7 +334,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'u') || args_has(args, 'U')) {
|
||||
if (o == NULL)
|
||||
goto out;
|
||||
if (options_remove_or_default(o, idx, &cause) != 0) {
|
||||
if (options_remove_or_default(o, array_key, &cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
goto fail;
|
||||
@@ -191,7 +345,9 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
goto fail;
|
||||
}
|
||||
options_set_string(oo, name, append, "%s", value);
|
||||
} else if (idx == -1 && !options_is_array(parent)) {
|
||||
if (cmd_get_entry(self) == &cmd_set_hook_entry)
|
||||
hooks_add_event(name);
|
||||
} else if (array_key == NULL && !options_is_array(parent)) {
|
||||
error = options_from_string(oo, options_table_entry(parent),
|
||||
options_table_entry(parent)->name, value,
|
||||
args_has(args, 'a'), &cause);
|
||||
@@ -207,7 +363,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
if (o == NULL)
|
||||
o = options_empty(oo, options_table_entry(parent));
|
||||
if (idx == -1) {
|
||||
if (array_key == NULL) {
|
||||
if (!append)
|
||||
options_array_clear(o);
|
||||
if (options_array_assign(o, value, &cause) != 0) {
|
||||
@@ -215,7 +371,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
free(cause);
|
||||
goto fail;
|
||||
}
|
||||
} else if (options_array_set(o, idx, value, append,
|
||||
} else if (options_array_set(o, array_key, value, append,
|
||||
&cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
@@ -229,11 +385,13 @@ out:
|
||||
free(argument);
|
||||
free(expanded);
|
||||
free(name);
|
||||
free(array_key);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
free(argument);
|
||||
free(expanded);
|
||||
free(name);
|
||||
free(array_key);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-show-environment.c,v 1.29 2025/04/09 06:27:43 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-show-messages.c,v 1.37 2025/11/18 08:37:54 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-show-options.c,v 1.76 2026/07/27 19:15:58 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -27,10 +27,23 @@
|
||||
* Show options.
|
||||
*/
|
||||
|
||||
#define SHOW_OPTIONS_TEMPLATE \
|
||||
"#{?option_value_only," \
|
||||
"#{option_value}," \
|
||||
"#{option_name}#{?option_has_array_key," \
|
||||
"[#{option_array_key}],}" \
|
||||
"#{?option_is_parent,*,}" \
|
||||
"#{?option_has_value, " \
|
||||
"#{?option_is_string,#{q/a:option_value},#{option_value}},}}"
|
||||
#define SHOW_HOOKS_MONITOR_TEMPLATE \
|
||||
"#{option_name}:#{hook_monitor_target}:#{hook_monitor_format}"
|
||||
|
||||
static enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmdq_item *);
|
||||
|
||||
static void cmd_show_options_print(struct cmd *, struct cmdq_item *,
|
||||
struct options_entry *, int, int);
|
||||
struct options_entry *, const char *, int);
|
||||
static void cmd_show_hooks_print_monitor(struct cmd *,
|
||||
struct cmdq_item *, struct options_entry *);
|
||||
static enum cmd_retval cmd_show_options_all(struct cmd *, struct cmdq_item *,
|
||||
int, struct options *);
|
||||
|
||||
@@ -38,8 +51,8 @@ const struct cmd_entry cmd_show_options_entry = {
|
||||
.name = "show-options",
|
||||
.alias = "show",
|
||||
|
||||
.args = { "AgHpqst:vw", 0, 1, NULL },
|
||||
.usage = "[-AgHpqsvw] " CMD_TARGET_PANE_USAGE " [option]",
|
||||
.args = { "AgF:Hpqst:vw", 0, 1, NULL },
|
||||
.usage = "[-AgHpqsvw] [-F format] " CMD_TARGET_PANE_USAGE " [option]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||
|
||||
@@ -51,8 +64,8 @@ const struct cmd_entry cmd_show_window_options_entry = {
|
||||
.name = "show-window-options",
|
||||
.alias = "showw",
|
||||
|
||||
.args = { "gvt:", 0, 1, NULL },
|
||||
.usage = "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]",
|
||||
.args = { "F:gvt:", 0, 1, NULL },
|
||||
.usage = "[-gv] [-F format] " CMD_TARGET_WINDOW_USAGE " [option]",
|
||||
|
||||
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
|
||||
|
||||
@@ -64,8 +77,8 @@ const struct cmd_entry cmd_show_hooks_entry = {
|
||||
.name = "show-hooks",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "gpt:w", 0, 1, NULL },
|
||||
.usage = "[-gpw] " CMD_TARGET_PANE_USAGE " [hook]",
|
||||
.args = { "BF:gpt:w", 0, 1, NULL },
|
||||
.usage = "[-Bgpw] [-F format] " CMD_TARGET_PANE_USAGE " [hook]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||
|
||||
@@ -80,7 +93,8 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct options *oo;
|
||||
char *argument, *name = NULL, *cause;
|
||||
int window, idx, ambiguous, parent, scope;
|
||||
char *array_key = NULL;
|
||||
int window, ambiguous, parent, print_parent, scope;
|
||||
struct options_entry *o;
|
||||
|
||||
window = (cmd_get_entry(self) == &cmd_show_window_options_entry);
|
||||
@@ -95,11 +109,20 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (cmd_get_entry(self) == &cmd_show_hooks_entry &&
|
||||
args_has(args, 'B')) {
|
||||
o = options_first(oo);
|
||||
while (o != NULL) {
|
||||
cmd_show_hooks_print_monitor(self, item, o);
|
||||
o = options_next(o);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
return (cmd_show_options_all(self, item, scope, oo));
|
||||
}
|
||||
argument = format_single_from_target(item, args_string(args, 0));
|
||||
|
||||
name = options_match(argument, &idx, &ambiguous);
|
||||
name = options_match(argument, &array_key, &ambiguous);
|
||||
if (name == NULL) {
|
||||
if (args_has(args, 'q'))
|
||||
goto out;
|
||||
@@ -124,9 +147,20 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
|
||||
parent = 1;
|
||||
} else
|
||||
parent = 0;
|
||||
if (o != NULL)
|
||||
cmd_show_options_print(self, item, o, idx, parent);
|
||||
else if (*name == '@') {
|
||||
if (o != NULL) {
|
||||
if (cmd_get_entry(self) == &cmd_show_hooks_entry &&
|
||||
args_has(args, 'B'))
|
||||
cmd_show_hooks_print_monitor(self, item, o);
|
||||
else {
|
||||
print_parent = parent;
|
||||
if (array_key == NULL && options_is_array(o) &&
|
||||
options_array_first(o) == NULL) {
|
||||
print_parent = 0;
|
||||
}
|
||||
cmd_show_options_print(self, item, o, array_key,
|
||||
print_parent);
|
||||
}
|
||||
} else if (*name == '@') {
|
||||
if (args_has(args, 'q'))
|
||||
goto out;
|
||||
cmdq_error(item, "invalid option: %s", argument);
|
||||
@@ -135,64 +169,171 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
out:
|
||||
free(name);
|
||||
free(array_key);
|
||||
free(argument);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
free(name);
|
||||
free(array_key);
|
||||
free(argument);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
|
||||
struct options_entry *o, int idx, int parent)
|
||||
struct options_entry *o, const char *array_key, int parent)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct options_array_item *a;
|
||||
struct format_tree *ft;
|
||||
const char *name = options_name(o);
|
||||
char *value, *tmp = NULL, *escaped;
|
||||
const char *template = args_get(args, 'F');
|
||||
char *value, *line;
|
||||
struct timeval tv = { 0 };
|
||||
u_int fire_count;
|
||||
time_t fire_time;
|
||||
int is_hook = 0, is_user = 0;
|
||||
int has_value = 1;
|
||||
const struct options_table_entry *oe = options_table_entry(o);
|
||||
|
||||
if (idx != -1) {
|
||||
xasprintf(&tmp, "%s[%d]", name, idx);
|
||||
name = tmp;
|
||||
} else {
|
||||
if (options_is_array(o)) {
|
||||
if (array_key != NULL)
|
||||
value = options_to_string(o, array_key, 0);
|
||||
else if (options_is_array(o)) {
|
||||
a = options_array_first(o);
|
||||
if (a == NULL) {
|
||||
if (!args_has(args, 'v'))
|
||||
cmdq_print(item, "%s", name);
|
||||
return;
|
||||
}
|
||||
if (a != NULL) {
|
||||
while (a != NULL) {
|
||||
idx = options_array_item_index(a);
|
||||
cmd_show_options_print(self, item, o, idx,
|
||||
array_key = options_array_item_key(a);
|
||||
cmd_show_options_print(self, item, o, array_key,
|
||||
parent);
|
||||
a = options_array_next(a);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (template == NULL && args_has(args, 'v'))
|
||||
return;
|
||||
value = xstrdup("");
|
||||
has_value = 0;
|
||||
} else
|
||||
value = options_to_string(o, NULL, 0);
|
||||
|
||||
value = options_to_string(o, idx, 0);
|
||||
if (args_has(args, 'v'))
|
||||
cmdq_print(item, "%s", value);
|
||||
else if (options_is_string(o)) {
|
||||
escaped = args_escape(value);
|
||||
if (parent)
|
||||
cmdq_print(item, "%s* %s", name, escaped);
|
||||
else
|
||||
cmdq_print(item, "%s %s", name, escaped);
|
||||
free(escaped);
|
||||
if (template == NULL)
|
||||
template = SHOW_OPTIONS_TEMPLATE;
|
||||
|
||||
if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_HOOK))
|
||||
is_hook = 1;
|
||||
else if (oe == NULL)
|
||||
is_user = 1;
|
||||
|
||||
ft = format_create_from_target(item);
|
||||
format_add(ft, "option_name", "%s", name);
|
||||
format_add(ft, "option_value", "%s", value);
|
||||
format_add(ft, "option_value_only", "%d", args_has(args, 'v'));
|
||||
format_add(ft, "option_is_parent", "%d", parent);
|
||||
format_add(ft, "option_is_array", "%d", options_is_array(o));
|
||||
format_add(ft, "option_is_string", "%d", options_is_string(o));
|
||||
format_add(ft, "option_is_hook", "%d", is_hook);
|
||||
format_add(ft, "option_is_user", "%d", is_user);
|
||||
format_add(ft, "option_has_value", "%d", has_value);
|
||||
if (cmd_get_entry(self) == &cmd_show_hooks_entry) {
|
||||
fire_count = options_get_fire_count(o);
|
||||
format_add(ft, "hook_fire_count", "%u", fire_count);
|
||||
|
||||
fire_time = options_get_fire_time(o);
|
||||
if (fire_time != 0) {
|
||||
tv.tv_sec = fire_time;
|
||||
format_add_tv(ft, "hook_fire_time", &tv);
|
||||
}
|
||||
}
|
||||
if (array_key != NULL) {
|
||||
format_add(ft, "option_array_key", "%s", array_key);
|
||||
format_add(ft, "option_has_array_key", "1");
|
||||
} else {
|
||||
if (parent)
|
||||
cmdq_print(item, "%s* %s", name, value);
|
||||
else
|
||||
cmdq_print(item, "%s %s", name, value);
|
||||
format_add(ft, "option_array_key", "%s", "");
|
||||
format_add(ft, "option_has_array_key", "0");
|
||||
}
|
||||
free(value);
|
||||
line = format_expand(ft, template);
|
||||
format_free(ft);
|
||||
|
||||
free(tmp);
|
||||
cmdq_print(item, "%s", line);
|
||||
free(line);
|
||||
free(value);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_show_hooks_print_monitor(struct cmd *self, struct cmdq_item *item,
|
||||
struct options_entry *o)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct format_tree *ft;
|
||||
enum monitor_type type;
|
||||
const char *template = args_get(args, 'F'), *format;
|
||||
char *value, *target, *line;
|
||||
struct timeval tv = { 0 };
|
||||
u_int fire_count;
|
||||
time_t fire_time;
|
||||
int id;
|
||||
|
||||
value = hooks_monitor_to_string(o);
|
||||
if (value == NULL)
|
||||
return;
|
||||
if (!hooks_monitor_get(o, &type, &id, &format)) {
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
if (template == NULL)
|
||||
template = SHOW_HOOKS_MONITOR_TEMPLATE;
|
||||
|
||||
switch (type) {
|
||||
case MONITOR_SESSION:
|
||||
target = xstrdup("");
|
||||
break;
|
||||
case MONITOR_PANE:
|
||||
xasprintf(&target, "%%%d", id);
|
||||
break;
|
||||
case MONITOR_ALL_PANES:
|
||||
target = xstrdup("%*");
|
||||
break;
|
||||
case MONITOR_WINDOW:
|
||||
xasprintf(&target, "@%d", id);
|
||||
break;
|
||||
case MONITOR_ALL_WINDOWS:
|
||||
target = xstrdup("@*");
|
||||
break;
|
||||
}
|
||||
|
||||
ft = format_create_from_target(item);
|
||||
format_add(ft, "option_name", "%s", options_name(o));
|
||||
format_add(ft, "option_value", "%s", value);
|
||||
format_add(ft, "option_value_only", "%d", 0);
|
||||
format_add(ft, "option_is_parent", "%d", 0);
|
||||
format_add(ft, "option_is_array", "%d", 0);
|
||||
format_add(ft, "option_is_string", "%d", 1);
|
||||
format_add(ft, "option_is_hook", "%d", 1);
|
||||
format_add(ft, "option_is_user", "%d", 1);
|
||||
format_add(ft, "option_has_value", "%d", 1);
|
||||
format_add(ft, "option_array_key", "%s", "");
|
||||
format_add(ft, "option_has_array_key", "0");
|
||||
|
||||
format_add(ft, "hook_monitor_target", "%s", target);
|
||||
format_add(ft, "hook_monitor_format", "%s", format);
|
||||
|
||||
fire_count = hooks_monitor_get_fire_count(o);
|
||||
format_add(ft, "hook_fire_count", "%u", fire_count);
|
||||
|
||||
fire_time = hooks_monitor_get_fire_time(o);
|
||||
if (fire_time != 0) {
|
||||
tv.tv_sec = fire_time;
|
||||
format_add_tv(ft, "hook_fire_time", &tv);
|
||||
}
|
||||
|
||||
line = format_expand(ft, template);
|
||||
format_free(ft);
|
||||
|
||||
cmdq_print(item, "%s", line);
|
||||
free(line);
|
||||
free(target);
|
||||
free(value);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
@@ -202,19 +343,30 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
|
||||
struct args *args = cmd_get_args(self);
|
||||
const struct options_table_entry *oe;
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
const char *name;
|
||||
u_int idx;
|
||||
int parent;
|
||||
int parent, is_user_hook;
|
||||
|
||||
if (cmd_get_entry(self) != &cmd_show_hooks_entry) {
|
||||
o = options_first(oo);
|
||||
while (o != NULL) {
|
||||
if (options_table_entry(o) == NULL)
|
||||
cmd_show_options_print(self, item, o, -1, 0);
|
||||
o = options_next(o);
|
||||
if (options_table_entry(o) == NULL) {
|
||||
name = options_name(o);
|
||||
is_user_hook = 0;
|
||||
if (*name == '@') {
|
||||
if (hooks_is_event(name) ||
|
||||
options_get_monitor_data(o) != NULL) {
|
||||
is_user_hook = 1;
|
||||
}
|
||||
}
|
||||
if (cmd_get_entry(self) != &cmd_show_hooks_entry) {
|
||||
if (!is_user_hook || args_has(args, 'H')) {
|
||||
cmd_show_options_print(self, item, o,
|
||||
NULL, 0);
|
||||
}
|
||||
} else if (is_user_hook)
|
||||
cmd_show_options_print(self, item, o, NULL, 0);
|
||||
}
|
||||
o = options_next(o);
|
||||
}
|
||||
for (oe = options_table; oe->name != NULL; oe++) {
|
||||
if (~oe->scope & scope)
|
||||
continue;
|
||||
@@ -237,24 +389,7 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
|
||||
} else
|
||||
parent = 0;
|
||||
|
||||
if (!options_is_array(o))
|
||||
cmd_show_options_print(self, item, o, -1, parent);
|
||||
else if ((a = options_array_first(o)) == NULL) {
|
||||
if (!args_has(args, 'v')) {
|
||||
name = options_name(o);
|
||||
if (parent)
|
||||
cmdq_print(item, "%s*", name);
|
||||
else
|
||||
cmdq_print(item, "%s", name);
|
||||
}
|
||||
} else {
|
||||
while (a != NULL) {
|
||||
idx = options_array_item_index(a);
|
||||
cmd_show_options_print(self, item, o, idx,
|
||||
parent);
|
||||
a = options_array_next(a);
|
||||
}
|
||||
}
|
||||
cmd_show_options_print(self, item, o, NULL, parent);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-show-prompt-history.c,v 1.5 2026/06/25 11:39:11 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021 Anindya Mukherjee <anindya49@hotmail.com>
|
||||
@@ -55,51 +55,44 @@ cmd_show_prompt_history_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct args *args = cmd_get_args(self);
|
||||
const char *typestr = args_get(args, 'T');
|
||||
enum prompt_type type;
|
||||
u_int tidx, hidx;
|
||||
u_int t, h;
|
||||
const char *v;
|
||||
|
||||
if (cmd_get_entry(self) == &cmd_clear_prompt_history_entry) {
|
||||
if (typestr == NULL) {
|
||||
for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
|
||||
free(status_prompt_hlist[tidx]);
|
||||
status_prompt_hlist[tidx] = NULL;
|
||||
status_prompt_hsize[tidx] = 0;
|
||||
}
|
||||
for (t = 0; t < PROMPT_NTYPES; t++)
|
||||
prompt_history_clear(t);
|
||||
} else {
|
||||
type = status_prompt_type(typestr);
|
||||
type = prompt_type(typestr);
|
||||
if (type == PROMPT_TYPE_INVALID) {
|
||||
cmdq_error(item, "invalid type: %s", typestr);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
free(status_prompt_hlist[type]);
|
||||
status_prompt_hlist[type] = NULL;
|
||||
status_prompt_hsize[type] = 0;
|
||||
prompt_history_clear(type);
|
||||
}
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (typestr == NULL) {
|
||||
for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
|
||||
cmdq_print(item, "History for %s:\n",
|
||||
status_prompt_type_string(tidx));
|
||||
for (hidx = 0; hidx < status_prompt_hsize[tidx];
|
||||
hidx++) {
|
||||
cmdq_print(item, "%d: %s", hidx + 1,
|
||||
status_prompt_hlist[tidx][hidx]);
|
||||
for (t = 0; t < PROMPT_NTYPES; t++) {
|
||||
typestr = prompt_type_string(t);
|
||||
cmdq_print(item, "History for %s:\n", typestr);
|
||||
for (h = 0; h < prompt_history_size(t); h++) {
|
||||
v = prompt_history_get(t, h);
|
||||
cmdq_print(item, "%d: %s", h + 1, v);
|
||||
}
|
||||
cmdq_print(item, "%s", "");
|
||||
}
|
||||
} else {
|
||||
type = status_prompt_type(typestr);
|
||||
type = prompt_type(typestr);
|
||||
if (type == PROMPT_TYPE_INVALID) {
|
||||
cmdq_error(item, "invalid type: %s", typestr);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
cmdq_print(item, "History for %s:\n",
|
||||
status_prompt_type_string(type));
|
||||
for (hidx = 0; hidx < status_prompt_hsize[type]; hidx++) {
|
||||
cmdq_print(item, "%d: %s", hidx + 1,
|
||||
status_prompt_hlist[type][hidx]);
|
||||
cmdq_print(item, "History for %s:\n", prompt_type_string(type));
|
||||
for (h = 0; h < prompt_history_size(type); h++) {
|
||||
v = prompt_history_get(type, h);
|
||||
cmdq_print(item, "%d: %s", h + 1, v);
|
||||
}
|
||||
cmdq_print(item, "%s", "");
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-source-file.c,v 1.63 2026/08/18 08:05:05 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Tiago Cunha <me@tiagocunha.org>
|
||||
@@ -50,6 +50,7 @@ const struct cmd_entry cmd_source_file_entry = {
|
||||
|
||||
struct cmd_source_file_data {
|
||||
struct cmdq_item *item;
|
||||
struct client *client;
|
||||
int flags;
|
||||
|
||||
struct cmdq_item *after;
|
||||
@@ -60,10 +61,24 @@ struct cmd_source_file_data {
|
||||
u_int nfiles;
|
||||
};
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_source_file_complete_cb(struct cmdq_item *item, __unused void *data)
|
||||
static void
|
||||
cmd_source_file_free_data(struct cmd_source_file_data *cdata)
|
||||
{
|
||||
struct client *c = cmdq_get_client(item);
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < cdata->nfiles; i++)
|
||||
free(cdata->files[i]);
|
||||
free(cdata->files);
|
||||
if (cdata->client != NULL)
|
||||
server_client_unref(cdata->client);
|
||||
free(cdata);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_source_file_complete_cb(struct cmdq_item *item, void *data)
|
||||
{
|
||||
struct cmd_source_file_data *cdata = data;
|
||||
struct client *c = cdata->client;
|
||||
|
||||
if (c == NULL) {
|
||||
cmd_source_file_depth--;
|
||||
@@ -74,36 +89,36 @@ cmd_source_file_complete_cb(struct cmdq_item *item, __unused void *data)
|
||||
}
|
||||
|
||||
cfg_print_causes(item);
|
||||
cmd_source_file_free_data(cdata);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_source_file_complete(struct client *c, struct cmd_source_file_data *cdata)
|
||||
cmd_source_file_complete(struct cmd_source_file_data *cdata)
|
||||
{
|
||||
struct client *c = cdata->client;
|
||||
struct cmdq_item *new_item;
|
||||
u_int i;
|
||||
|
||||
if (cfg_finished) {
|
||||
if (!cfg_finished) {
|
||||
cmd_source_file_free_data(cdata);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cdata->retval == CMD_RETURN_ERROR &&
|
||||
c != NULL &&
|
||||
c->session == NULL)
|
||||
c->retval = 1;
|
||||
new_item = cmdq_get_callback(cmd_source_file_complete_cb, NULL);
|
||||
new_item = cmdq_get_callback(cmd_source_file_complete_cb, cdata);
|
||||
cmdq_insert_after(cdata->after, new_item);
|
||||
}
|
||||
|
||||
for (i = 0; i < cdata->nfiles; i++)
|
||||
free(cdata->files[i]);
|
||||
free(cdata->files);
|
||||
free(cdata);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_source_file_done(struct client *c, const char *path, int error,
|
||||
int closed, struct evbuffer *buffer, void *data)
|
||||
cmd_source_file_done(__unused struct client *oc, const char *path,
|
||||
int error, int closed, struct evbuffer *buffer, void *data)
|
||||
{
|
||||
struct cmd_source_file_data *cdata = data;
|
||||
struct cmdq_item *item = cdata->item;
|
||||
struct client *c = cdata->client;
|
||||
void *bdata = EVBUFFER_DATA(buffer);
|
||||
size_t bsize = EVBUFFER_LENGTH(buffer);
|
||||
u_int n;
|
||||
@@ -116,7 +131,7 @@ cmd_source_file_done(struct client *c, const char *path, int error,
|
||||
if (error != 0)
|
||||
cmdq_error(item, "%s: %s", strerror(error), path);
|
||||
else if (bsize != 0) {
|
||||
if (load_cfg_from_buffer(bdata, bsize, path, c, cdata->after,
|
||||
if (load_cfg_from_buffer(bdata, bsize, path, cdata->after,
|
||||
target, cdata->flags, &new_item) < 0)
|
||||
cdata->retval = CMD_RETURN_ERROR;
|
||||
else if (new_item != NULL)
|
||||
@@ -127,7 +142,7 @@ cmd_source_file_done(struct client *c, const char *path, int error,
|
||||
if (n < cdata->nfiles)
|
||||
file_read(c, cdata->files[n], cmd_source_file_done, cdata);
|
||||
else {
|
||||
cmd_source_file_complete(c, cdata);
|
||||
cmd_source_file_complete(cdata);
|
||||
cmdq_continue(item);
|
||||
}
|
||||
}
|
||||
@@ -187,6 +202,9 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
cdata = xcalloc(1, sizeof *cdata);
|
||||
cdata->item = item;
|
||||
cdata->client = c;
|
||||
if (c != NULL)
|
||||
c->references++;
|
||||
|
||||
if (args_has(args, 'q'))
|
||||
cdata->flags |= CMD_PARSE_QUIET;
|
||||
@@ -249,7 +267,7 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
|
||||
file_read(c, cdata->files[0], cmd_source_file_done, cdata);
|
||||
retval = CMD_RETURN_WAIT;
|
||||
} else
|
||||
cmd_source_file_complete(c, cdata);
|
||||
cmd_source_file_complete(cdata);
|
||||
|
||||
free(cwd);
|
||||
return (retval);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-split-window.c,v 1.150 2026/08/20 09:19:24 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -27,22 +27,44 @@
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* Split a window (add a new pane).
|
||||
* Create a new pane.
|
||||
*/
|
||||
|
||||
#define SPLIT_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
|
||||
|
||||
static enum cmd_retval cmd_split_window_exec(struct cmd *,
|
||||
struct cmdq_item *);
|
||||
static enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmdq_item *);
|
||||
static void cmd_split_window_mouse_resize(struct client *,
|
||||
struct mouse_event *);
|
||||
|
||||
const struct cmd_entry cmd_new_pane_entry = {
|
||||
.name = "new-pane",
|
||||
.alias = "newp",
|
||||
|
||||
.args = { "AbB:Cc:de:EfF:hIkl:KLMm:Op:PR:s:S:t:T:vWx:X:y:Y:Z", 0, -1, NULL },
|
||||
.usage = "[-AbCdefhIkKLMOPvWZ] [-B border-lines] "
|
||||
"[-c start-directory] [-e environment] "
|
||||
"[-F format] [-l size] [-m message] [-p percentage] "
|
||||
"[-s style] [-S active-border-style] "
|
||||
"[-R inactive-border-style] [-T title] [-x width] [-y height] "
|
||||
"[-X x-position] [-Y y-position] " CMD_TARGET_PANE_USAGE " "
|
||||
"[shell-command [argument ...]]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
.flags = 0,
|
||||
.exec = cmd_split_window_exec
|
||||
};
|
||||
|
||||
const struct cmd_entry cmd_split_window_entry = {
|
||||
.name = "split-window",
|
||||
.alias = "splitw",
|
||||
|
||||
.args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL },
|
||||
.usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] "
|
||||
"[-F format] [-l size] " CMD_TARGET_PANE_USAGE
|
||||
" [shell-command [argument ...]]",
|
||||
.args = { "bB:c:de:EfF:hIkl:m:p:PR:s:S:t:T:vWZ", 0, -1, NULL },
|
||||
.usage = "[-bdefhIklPvWZ] [-B border-lines] [-c start-directory] "
|
||||
"[-e environment] [-F format] [-l size] [-m message] "
|
||||
"[-p percentage] [-s style] [-S active-border-style] "
|
||||
"[-R inactive-border-style] [-T title] "
|
||||
CMD_TARGET_PANE_USAGE " [shell-command [argument ...]]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
@@ -61,65 +83,105 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct session *s = target->s;
|
||||
struct winlink *wl = target->wl;
|
||||
struct window *w = wl->window;
|
||||
struct window_pane *wp = target->wp, *new_wp;
|
||||
enum layout_type type;
|
||||
struct layout_cell *lc;
|
||||
struct window_pane *wp = target->wp, *new_wp = NULL;
|
||||
struct layout_cell *lc = NULL;
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
int size, flags, input;
|
||||
const char *template;
|
||||
char *cause = NULL, *cp;
|
||||
struct key_event *event = cmdq_get_event(item);
|
||||
int input, empty, is_floating, flags = 0;
|
||||
int restore_zoom = 0;
|
||||
const char *template, *style, *value;
|
||||
char *cause = NULL, *cp, *title;
|
||||
const struct options_table_entry *oe;
|
||||
struct args_value *av;
|
||||
u_int count = args_count(args), curval = 0;
|
||||
enum pane_lines lines;
|
||||
u_int count = args_count(args);
|
||||
|
||||
type = LAYOUT_TOPBOTTOM;
|
||||
if (args_has(args, 'h'))
|
||||
type = LAYOUT_LEFTRIGHT;
|
||||
if (window_active_pane_is_over_zoom(w))
|
||||
restore_zoom = 1;
|
||||
|
||||
/* If the 'p' flag is dropped then this bit can be moved into 'l'. */
|
||||
if (args_has(args, 'l') || args_has(args, 'p')) {
|
||||
if (args_has(args, 'f')) {
|
||||
if (type == LAYOUT_TOPBOTTOM)
|
||||
curval = w->sy;
|
||||
else
|
||||
curval = w->sx;
|
||||
} else {
|
||||
if (type == LAYOUT_TOPBOTTOM)
|
||||
curval = wp->sy;
|
||||
else
|
||||
curval = wp->sx;
|
||||
}
|
||||
if (cmd_get_entry(self) == &cmd_new_pane_entry)
|
||||
is_floating = !args_has(args, 'L');
|
||||
else {
|
||||
if (!window_pane_is_visible(wp))
|
||||
restore_zoom = 0;
|
||||
if (!restore_zoom)
|
||||
window_unzoom(w, 1);
|
||||
is_floating = window_pane_is_floating(wp);
|
||||
flags |= SPAWN_SPLIT;
|
||||
}
|
||||
|
||||
size = -1;
|
||||
if (args_has(args, 'l')) {
|
||||
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
|
||||
item, &cause);
|
||||
} else if (args_has(args, 'p')) {
|
||||
size = args_strtonum_and_expand(args, 'p', 0, 100, item,
|
||||
&cause);
|
||||
if (cause == NULL)
|
||||
size = curval * size / 100;
|
||||
}
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "size %s", cause);
|
||||
free(cause);
|
||||
if (args_has(args, 'O')) {
|
||||
if (!is_floating) {
|
||||
cmdq_error(item, "modal pane must be floating");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (w->modal != NULL) {
|
||||
cmdq_error(item, "window already has a modal pane");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
window_push_zoom(wp->window, 1, args_has(args, 'Z'));
|
||||
input = (args_has(args, 'I') && count == 0);
|
||||
if (args_has(args, 'M') && is_floating) {
|
||||
if (event == NULL || !event->m.valid || tc == NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
if (is_floating)
|
||||
flags |= SPAWN_FLOATING;
|
||||
if (args_has(args, 'h'))
|
||||
flags |= SPAWN_HORIZONTAL;
|
||||
if (args_has(args, 'b'))
|
||||
flags |= SPAWN_BEFORE;
|
||||
if (args_has(args, 'f'))
|
||||
flags |= SPAWN_FULLSIZE;
|
||||
if (args_has(args, 'd'))
|
||||
flags |= SPAWN_DETACHED;
|
||||
if (args_has(args, 'Z'))
|
||||
flags |= SPAWN_ZOOM;
|
||||
if (args_has(args, 'O'))
|
||||
flags |= SPAWN_MODAL|SPAWN_FLOATOVERZOOM;
|
||||
if (is_floating && args_has(args, 'A'))
|
||||
flags |= SPAWN_FLOATOVERZOOM;
|
||||
if ((w->flags & WINDOW_ZOOMED) && (flags & SPAWN_FLOATOVERZOOM))
|
||||
restore_zoom = 1;
|
||||
|
||||
input = args_has(args, 'I');
|
||||
if (input || (count == 1 && *args_string(args, 0) == '\0'))
|
||||
empty = 1;
|
||||
else
|
||||
empty = args_has(args, 'E');
|
||||
if (empty &&
|
||||
count != 0 &&
|
||||
(count != 1 || *args_string(args, 0) != '\0')) {
|
||||
cmdq_error(item, "command cannot be given for empty pane");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (empty)
|
||||
flags |= SPAWN_EMPTY;
|
||||
|
||||
lc = layout_split_pane(wp, type, size, flags);
|
||||
if (lc == NULL) {
|
||||
cmdq_error(item, "no space for new pane");
|
||||
if ((value = args_get(args, 'B')) == NULL)
|
||||
lines = window_get_pane_lines(w);
|
||||
else {
|
||||
oe = options_search("pane-border-lines");
|
||||
lines = options_find_choice(oe, value, &cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "pane-border-lines %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & SPAWN_FLOATING) {
|
||||
lc = layout_get_floating_cell(item, args, lines, w, wp, flags,
|
||||
&cause);
|
||||
} else
|
||||
lc = layout_get_tiled_cell(item, args, w, wp, flags, &cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
if (restore_zoom)
|
||||
window_pop_zoom(w);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
@@ -141,43 +203,103 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
sc.idx = -1;
|
||||
sc.cwd = args_get(args, 'c');
|
||||
|
||||
sc.flags = flags;
|
||||
if (args_has(args, 'd'))
|
||||
sc.flags |= SPAWN_DETACHED;
|
||||
if (args_has(args, 'Z'))
|
||||
sc.flags |= SPAWN_ZOOM;
|
||||
|
||||
if ((new_wp = spawn_pane(&sc, &cause)) == NULL) {
|
||||
cmdq_error(item, "create pane failed: %s", cause);
|
||||
free(cause);
|
||||
if (sc.argv != NULL)
|
||||
cmd_free_argv(sc.argc, sc.argv);
|
||||
environ_free(sc.environ);
|
||||
return (CMD_RETURN_ERROR);
|
||||
/*
|
||||
* spawn_pane has already torn the half-built pane down (its
|
||||
* fork-failure path removes the pane and destroys the layout
|
||||
* cell), so new_wp is NULL and there is nothing for fail to do.
|
||||
*/
|
||||
goto fail;
|
||||
}
|
||||
if (args_has(args, 'K') && args_has(args, 'O'))
|
||||
new_wp->flags |= PANE_CAPTUREALLKEYS;
|
||||
if (args_has(args, 'C') && args_has(args, 'O'))
|
||||
new_wp->flags |= PANE_CLOSEONCLICK;
|
||||
|
||||
style = args_get(args, 's');
|
||||
if (style != NULL) {
|
||||
if (options_set_string(new_wp->options, "window-style", 0,
|
||||
"%s", style) == NULL) {
|
||||
cmdq_error(item, "bad style: %s", style);
|
||||
goto fail;
|
||||
}
|
||||
options_set_string(new_wp->options, "window-active-style", 0,
|
||||
"%s", style);
|
||||
new_wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
|
||||
PANE_THEMECHANGED);
|
||||
}
|
||||
style = args_get(args, 'S');
|
||||
if (style != NULL) {
|
||||
if (options_set_string(new_wp->options,
|
||||
"pane-active-border-style", 0, "%s", style) == NULL) {
|
||||
cmdq_error(item, "bad active border style: %s", style);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
style = args_get(args, 'R');
|
||||
if (style != NULL) {
|
||||
if (options_set_string(new_wp->options, "pane-border-style", 0,
|
||||
"%s", style) == NULL) {
|
||||
cmdq_error(item, "bad inactive border style: %s",
|
||||
style);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
if (args_has(args, 'B'))
|
||||
options_set_number(new_wp->options, "pane-border-lines", lines);
|
||||
if (args_has(args, 'k') || args_has(args, 'm')) {
|
||||
options_set_number(new_wp->options, "remain-on-exit", 3);
|
||||
if (args_has(args, 'm')) {
|
||||
options_set_string(new_wp->options,
|
||||
"remain-on-exit-format", 0, "%s",
|
||||
args_get(args, 'm'));
|
||||
}
|
||||
}
|
||||
if (args_has(args, 'T')) {
|
||||
title = format_single_from_target(item, args_get(args, 'T'));
|
||||
screen_set_title(&new_wp->base, title, 0);
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_pane(&fs, new_wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_pane(ep, "pane", new_wp);
|
||||
event_payload_set_window(ep, "window", new_wp->window);
|
||||
event_payload_set_string(ep, "new_title", "%s", title);
|
||||
events_fire("pane-title-changed", ep);
|
||||
free(title);
|
||||
}
|
||||
|
||||
if (input) {
|
||||
switch (window_pane_start_input(new_wp, item, &cause)) {
|
||||
case -1:
|
||||
server_client_remove_pane(new_wp);
|
||||
layout_close_pane(new_wp);
|
||||
window_remove_pane(wp->window, new_wp);
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
if (sc.argv != NULL)
|
||||
cmd_free_argv(sc.argc, sc.argv);
|
||||
environ_free(sc.environ);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
case 1:
|
||||
input = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!args_has(args, 'd'))
|
||||
if (~flags & SPAWN_DETACHED)
|
||||
cmd_find_from_winlink_pane(current, wl, new_wp, 0);
|
||||
|
||||
if (restore_zoom) {
|
||||
window_pop_zoom(wp->window);
|
||||
server_redraw_window(wp->window);
|
||||
server_status_session(s);
|
||||
} else if ((~flags & SPAWN_FLOATING) && !args_has(args, 'O')) {
|
||||
window_pop_zoom(wp->window);
|
||||
server_redraw_window(wp->window);
|
||||
}
|
||||
server_redraw_session(s);
|
||||
|
||||
if (args_has(args, 'M') && is_floating) {
|
||||
tc->tty.mouse_last_pane = new_wp->id;
|
||||
tc->tty.mouse_drag_update = cmd_split_window_mouse_resize;
|
||||
cmd_split_window_mouse_resize(tc, &event->m);
|
||||
}
|
||||
|
||||
if (args_has(args, 'P')) {
|
||||
if ((template = args_get(args, 'F')) == NULL)
|
||||
@@ -195,5 +317,106 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
environ_free(sc.environ);
|
||||
if (input)
|
||||
return (CMD_RETURN_WAIT);
|
||||
|
||||
if (args_has(args, 'W')) {
|
||||
/*
|
||||
* With -W, block this command queue item until the pane's
|
||||
* command exits; window_pane_wait_finish will be called to
|
||||
* continue it.
|
||||
*/
|
||||
new_wp->wait_item = item;
|
||||
return (CMD_RETURN_WAIT);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
/*
|
||||
* If the pane was spawned before we failed, tear it down here; this
|
||||
* also destroys its layout cell. spawn_pane's own failure path has
|
||||
* already done this, so new_wp is NULL in that case.
|
||||
*/
|
||||
if (new_wp != NULL) {
|
||||
server_client_remove_pane(new_wp);
|
||||
if (!is_floating)
|
||||
layout_close_pane(new_wp);
|
||||
window_remove_pane(wp->window, new_wp);
|
||||
}
|
||||
if (restore_zoom || (~flags & SPAWN_FLOATING))
|
||||
window_pop_zoom(wp->window);
|
||||
if (sc.argv != NULL)
|
||||
cmd_free_argv(sc.argc, sc.argv);
|
||||
environ_free(sc.environ);
|
||||
|
||||
return (CMD_RETURN_ERROR);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_split_window_mouse_resize(struct client *c, struct mouse_event *m)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
struct window *w;
|
||||
struct layout_cell *lc;
|
||||
enum pane_lines lines;
|
||||
u_int sx, sy;
|
||||
int x, y, xoff, yoff, border;
|
||||
|
||||
if (c->tty.mouse_last_pane == -1)
|
||||
return;
|
||||
wp = window_pane_find_by_id(c->tty.mouse_last_pane);
|
||||
if (wp == NULL || !window_pane_is_floating(wp)) {
|
||||
c->tty.mouse_drag_update = NULL;
|
||||
return;
|
||||
}
|
||||
w = wp->window;
|
||||
lc = wp->layout_cell;
|
||||
|
||||
x = m->x + m->ox;
|
||||
y = m->y + m->oy;
|
||||
if (m->statusat == 0 && y >= (int)m->statuslines)
|
||||
y -= m->statuslines;
|
||||
else if (m->statusat > 0 && y >= m->statusat)
|
||||
y = m->statusat - 1;
|
||||
|
||||
lines = window_pane_get_pane_lines(wp);
|
||||
border = (lines != PANE_LINES_NONE);
|
||||
|
||||
if (x >= (int)c->tty.mouse_drag_x) {
|
||||
xoff = c->tty.mouse_drag_x + border;
|
||||
sx = x - c->tty.mouse_drag_x + 1;
|
||||
} else {
|
||||
sx = c->tty.mouse_drag_x - x + 1;
|
||||
xoff = c->tty.mouse_drag_x - sx + 1;
|
||||
if (border)
|
||||
xoff++;
|
||||
}
|
||||
if (y >= (int)c->tty.mouse_drag_y) {
|
||||
yoff = c->tty.mouse_drag_y + border;
|
||||
sy = y - c->tty.mouse_drag_y + 1;
|
||||
} else {
|
||||
sy = c->tty.mouse_drag_y - y + 1;
|
||||
yoff = c->tty.mouse_drag_y - sy + 1;
|
||||
if (border)
|
||||
yoff++;
|
||||
}
|
||||
|
||||
if (border) {
|
||||
if (sx <= 2)
|
||||
sx = PANE_MINIMUM;
|
||||
else
|
||||
sx -= 2;
|
||||
if (sy <= 2)
|
||||
sy = PANE_MINIMUM;
|
||||
else
|
||||
sy -= 2;
|
||||
}
|
||||
if (sx < PANE_MINIMUM)
|
||||
sx = PANE_MINIMUM;
|
||||
if (sy < PANE_MINIMUM)
|
||||
sy = PANE_MINIMUM;
|
||||
|
||||
layout_set_size(lc, sx, sy, xoff, yoff);
|
||||
layout_fix_panes(w, NULL);
|
||||
server_redraw_window(w);
|
||||
server_redraw_window_borders(w);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-swap-pane.c,v 1.55 2026/07/15 13:02:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -42,6 +42,22 @@ const struct cmd_entry cmd_swap_pane_entry = {
|
||||
.exec = cmd_swap_pane_exec
|
||||
};
|
||||
|
||||
static struct window_pane *
|
||||
cmd_swap_pane_next_tiled_pane(struct window_pane *wp)
|
||||
{
|
||||
while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell))
|
||||
wp = TAILQ_NEXT(wp, entry);
|
||||
return (wp);
|
||||
}
|
||||
|
||||
static struct window_pane *
|
||||
cmd_swap_pane_prev_tiled_pane(struct window_pane *wp)
|
||||
{
|
||||
while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell))
|
||||
wp = TAILQ_PREV(wp, window_panes, entry);
|
||||
return (wp);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
@@ -52,25 +68,47 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct window_pane *tmp_wp, *src_wp, *dst_wp;
|
||||
struct layout_cell *src_lc, *dst_lc;
|
||||
u_int sx, sy, xoff, yoff;
|
||||
int src_idx, dst_idx;
|
||||
|
||||
dst_w = target->wl->window;
|
||||
dst_wp = target->wp;
|
||||
dst_idx = target->wl->idx;
|
||||
src_w = source->wl->window;
|
||||
src_wp = source->wp;
|
||||
src_idx = source->wl->idx;
|
||||
|
||||
if (src_wp == src_w->modal || dst_wp == dst_w->modal) {
|
||||
cmdq_error(item, "pane is modal");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (window_push_zoom(dst_w, 0, args_has(args, 'Z')))
|
||||
server_redraw_window(dst_w);
|
||||
|
||||
if (args_has(args, 'D')) {
|
||||
if (window_pane_is_floating(dst_wp)) {
|
||||
cmdq_error(item, "cannot swap down on floating pane");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
src_w = dst_w;
|
||||
src_wp = TAILQ_NEXT(dst_wp, entry);
|
||||
if (src_wp == NULL)
|
||||
src_wp = cmd_swap_pane_next_tiled_pane(src_wp);
|
||||
if (src_wp == NULL) {
|
||||
src_wp = TAILQ_FIRST(&dst_w->panes);
|
||||
src_wp = cmd_swap_pane_next_tiled_pane(src_wp);
|
||||
}
|
||||
} else if (args_has(args, 'U')) {
|
||||
if (window_pane_is_floating(dst_wp)) {
|
||||
cmdq_error(item, "cannot swap up on floating pane");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
src_w = dst_w;
|
||||
src_wp = TAILQ_PREV(dst_wp, window_panes, entry);
|
||||
if (src_wp == NULL)
|
||||
src_wp = cmd_swap_pane_prev_tiled_pane(src_wp);
|
||||
if (src_wp == NULL) {
|
||||
src_wp = TAILQ_LAST(&dst_w->panes, window_panes);
|
||||
src_wp = cmd_swap_pane_prev_tiled_pane(src_wp);
|
||||
}
|
||||
}
|
||||
|
||||
if (src_w != dst_w && window_push_zoom(src_w, 0, args_has(args, 'Z')))
|
||||
@@ -92,6 +130,16 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
else
|
||||
TAILQ_INSERT_AFTER(&dst_w->panes, tmp_wp, src_wp, entry);
|
||||
|
||||
tmp_wp = TAILQ_PREV(dst_wp, window_panes, zentry);
|
||||
TAILQ_REMOVE(&dst_w->z_index, dst_wp, zentry);
|
||||
TAILQ_REPLACE(&src_w->z_index, src_wp, dst_wp, zentry);
|
||||
if (tmp_wp == src_wp)
|
||||
tmp_wp = dst_wp;
|
||||
if (tmp_wp == NULL)
|
||||
TAILQ_INSERT_HEAD(&dst_w->z_index, src_wp, zentry);
|
||||
else
|
||||
TAILQ_INSERT_AFTER(&dst_w->z_index, tmp_wp, src_wp, zentry);
|
||||
|
||||
src_lc = src_wp->layout_cell;
|
||||
dst_lc = dst_wp->layout_cell;
|
||||
src_lc->wp = dst_wp;
|
||||
@@ -133,14 +181,20 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
colour_palette_from_option(&src_wp->palette, src_wp->options);
|
||||
colour_palette_from_option(&dst_wp->palette, dst_wp->options);
|
||||
layout_fix_panes(src_w, NULL);
|
||||
redraw_invalidate_scene(src_w);
|
||||
server_redraw_window(src_w);
|
||||
}
|
||||
layout_fix_panes(dst_w, NULL);
|
||||
redraw_invalidate_scene(dst_w);
|
||||
server_redraw_window(dst_w);
|
||||
|
||||
notify_window("window-layout-changed", src_w);
|
||||
if (src_w != dst_w) {
|
||||
window_fire_pane_moved(src_wp, src_w, src_idx, dst_w, dst_idx);
|
||||
window_fire_pane_moved(dst_wp, dst_w, dst_idx, src_w, src_idx);
|
||||
}
|
||||
events_fire_window("window-layout-changed", src_w);
|
||||
if (src_w != dst_w)
|
||||
notify_window("window-layout-changed", dst_w);
|
||||
events_fire_window("window-layout-changed", dst_w);
|
||||
|
||||
out:
|
||||
if (window_pop_zoom(src_w))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-swap-window.c,v 1.30 2026/07/27 08:03:01 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -38,7 +38,7 @@ const struct cmd_entry cmd_swap_window_entry = {
|
||||
.source = { 's', CMD_FIND_WINDOW, CMD_FIND_DEFAULT_MARKED },
|
||||
.target = { 't', CMD_FIND_WINDOW, 0 },
|
||||
|
||||
.flags = 0,
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.exec = cmd_swap_window_exec
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-switch-client.c,v 1.75 2026/08/20 09:19:24 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
@@ -34,9 +35,9 @@ const struct cmd_entry cmd_switch_client_entry = {
|
||||
.name = "switch-client",
|
||||
.alias = "switchc",
|
||||
|
||||
.args = { "lc:EFnpt:rT:Z", 0, 0, NULL },
|
||||
.args = { "c:EFlnO:pt:rT:Z", 0, 0, NULL },
|
||||
.usage = "[-ElnprZ] [-c target-client] [-t target-session] "
|
||||
"[-T key-table]",
|
||||
"[-T key-table] [-O order]",
|
||||
|
||||
/* -t is special */
|
||||
|
||||
@@ -52,7 +53,8 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_find_state target;
|
||||
const char *tflag = args_get(args, 't');
|
||||
enum cmd_find_type type;
|
||||
int flags;
|
||||
int flags, visible, Zflag = args_has(args, 'Z');
|
||||
struct client *c = cmdq_get_client(item);
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct session *s;
|
||||
struct winlink *wl;
|
||||
@@ -60,6 +62,8 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct window_pane *wp;
|
||||
const char *tablename;
|
||||
struct key_table *table;
|
||||
struct sort_criteria sort_crit;
|
||||
uid_t uid;
|
||||
|
||||
if (tflag != NULL &&
|
||||
(tflag[strcspn(tflag, ":.%")] != '\0' || strcmp(tflag, "=") == 0)) {
|
||||
@@ -76,6 +80,13 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
wp = target.wp;
|
||||
|
||||
if (args_has(args, 'r')) {
|
||||
if (tc->flags & CLIENT_READONLY) {
|
||||
uid = proc_get_peer_uid(c->peer);
|
||||
if (uid != getuid()) {
|
||||
cmdq_error(item, "client is read-only");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
if (tc->flags & CLIENT_READONLY)
|
||||
tc->flags &= ~(CLIENT_READONLY|CLIENT_IGNORESIZE);
|
||||
else
|
||||
@@ -95,13 +106,22 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
sort_crit.order = sort_order_from_string(args_get(args, 'O'));
|
||||
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
|
||||
cmdq_error(item, "invalid sort order");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
sort_crit.reversed = args_has(args, 'r');
|
||||
|
||||
if (args_has(args, 'n')) {
|
||||
if ((s = session_next_session(tc->session)) == NULL) {
|
||||
s = session_next_session(tc->session, &sort_crit);
|
||||
if (s == NULL) {
|
||||
cmdq_error(item, "can't find next session");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
} else if (args_has(args, 'p')) {
|
||||
if ((s = session_previous_session(tc->session)) == NULL) {
|
||||
s = session_previous_session(tc->session, &sort_crit);
|
||||
if (s == NULL) {
|
||||
cmdq_error(item, "can't find previous session");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
@@ -119,11 +139,15 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (wl != NULL && wp != NULL && wp != wl->window->active) {
|
||||
w = wl->window;
|
||||
if (window_push_zoom(w, 0, args_has(args, 'Z')))
|
||||
if (w->modal != NULL && wp != w->modal)
|
||||
visible = 1;
|
||||
else
|
||||
visible = window_pane_is_visible(wp);
|
||||
if (!visible && window_push_zoom(w, 0, Zflag))
|
||||
server_redraw_window(w);
|
||||
window_redraw_active_switch(w, wp);
|
||||
window_set_active_pane(w, wp, 1);
|
||||
if (window_pop_zoom(w))
|
||||
if (!visible && window_pop_zoom(w))
|
||||
server_redraw_window(w);
|
||||
}
|
||||
if (wl != NULL) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-unbind-key.c,v 1.34 2021/08/21 10:22:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
259
cmd-wait-for.c
259
cmd-wait-for.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-wait-for.c,v 1.23 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -34,8 +34,8 @@ const struct cmd_entry cmd_wait_for_entry = {
|
||||
.name = "wait-for",
|
||||
.alias = "wait",
|
||||
|
||||
.args = { "LSU", 1, 1, NULL },
|
||||
.usage = "[-L|-S|-U] channel",
|
||||
.args = { "EF:LSUlvw:", 1, 1, NULL },
|
||||
.usage = "[-ELSUlv] [-F format] [-w waiter] name",
|
||||
|
||||
.flags = 0,
|
||||
.exec = cmd_wait_for_exec
|
||||
@@ -46,6 +46,17 @@ struct wait_item {
|
||||
TAILQ_ENTRY(wait_item) entry;
|
||||
};
|
||||
|
||||
struct wait_event_item {
|
||||
struct cmdq_item *item;
|
||||
struct events_sink *sink;
|
||||
char *name;
|
||||
char *filter;
|
||||
int verbose;
|
||||
TAILQ_ENTRY(wait_event_item) entry;
|
||||
};
|
||||
static TAILQ_HEAD(, wait_event_item) wait_event_items =
|
||||
TAILQ_HEAD_INITIALIZER(wait_event_items);
|
||||
|
||||
struct wait_channel {
|
||||
const char *name;
|
||||
int locked;
|
||||
@@ -76,9 +87,28 @@ static enum cmd_retval cmd_wait_for_lock(struct cmdq_item *, const char *,
|
||||
struct wait_channel *);
|
||||
static enum cmd_retval cmd_wait_for_unlock(struct cmdq_item *, const char *,
|
||||
struct wait_channel *);
|
||||
static enum cmd_retval cmd_wait_for_event(struct cmdq_item *, const char *,
|
||||
struct args *);
|
||||
static void cmd_wait_for_event_cb(const char *,
|
||||
struct event_payload *, void *);
|
||||
static void cmd_wait_for_event_free(struct wait_event_item *);
|
||||
static enum cmd_retval cmd_wait_for_event_list(struct cmdq_item *,
|
||||
const char *);
|
||||
static enum cmd_retval cmd_wait_for_event_wake(struct cmdq_item *,
|
||||
const char *, struct args *);
|
||||
static enum cmd_retval cmd_wait_for_list(struct cmdq_item *,
|
||||
struct wait_channel *);
|
||||
static enum cmd_retval cmd_wait_for_wake(struct cmdq_item *, const char *,
|
||||
struct args *, struct wait_channel *);
|
||||
|
||||
static struct wait_channel *cmd_wait_for_add(const char *);
|
||||
static void cmd_wait_for_remove(struct wait_channel *);
|
||||
static void cmd_wait_for_remove_empty(
|
||||
struct wait_channel *);
|
||||
static const char *cmd_wait_for_item_client_name(
|
||||
struct cmdq_item *);
|
||||
static const char *cmd_wait_for_client_name(
|
||||
struct wait_event_item *);
|
||||
|
||||
static struct wait_channel *
|
||||
cmd_wait_for_add(const char *name)
|
||||
@@ -117,16 +147,53 @@ cmd_wait_for_remove(struct wait_channel *wc)
|
||||
free(wc);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_wait_for_remove_empty(struct wait_channel *wc)
|
||||
{
|
||||
if (wc->locked || wc->woken)
|
||||
return;
|
||||
if (!TAILQ_EMPTY(&wc->waiters) || !TAILQ_EMPTY(&wc->lockers))
|
||||
return;
|
||||
|
||||
log_debug("remove empty wait channel %s", wc->name);
|
||||
|
||||
RB_REMOVE(wait_channels, &wait_channels, wc);
|
||||
|
||||
free((void *)wc->name);
|
||||
free(wc);
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_wait_for_item_client_name(struct cmdq_item *item)
|
||||
{
|
||||
struct client *c = cmdq_get_client(item);
|
||||
|
||||
if (c == NULL || c->name == NULL)
|
||||
return ("");
|
||||
return (c->name);
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_wait_for_client_name(struct wait_event_item *wei)
|
||||
{
|
||||
return (cmd_wait_for_item_client_name(wei->item));
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
const char *name = args_string(args, 0);
|
||||
struct wait_channel *wc, find;
|
||||
struct wait_channel *wc, find = { .name = name };
|
||||
|
||||
if (args_has(args, 'E'))
|
||||
return (cmd_wait_for_event(item, name, args));
|
||||
|
||||
find.name = name;
|
||||
wc = RB_FIND(wait_channels, &wait_channels, &find);
|
||||
|
||||
if (args_has(args, 'l'))
|
||||
return (cmd_wait_for_list(item, wc));
|
||||
if (args_has(args, 'w'))
|
||||
return (cmd_wait_for_wake(item, name, args, wc));
|
||||
if (args_has(args, 'S'))
|
||||
return (cmd_wait_for_signal(item, name, wc));
|
||||
if (args_has(args, 'L'))
|
||||
@@ -136,6 +203,179 @@ cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (cmd_wait_for_wait(item, name, wc));
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_wait_for_event_print(struct wait_event_item *wei, struct event_payload *ep)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
const char *key;
|
||||
char *value;
|
||||
|
||||
epi = event_payload_first(ep);
|
||||
while (epi != NULL) {
|
||||
key = event_payload_item_name(epi);
|
||||
if (*key != '_') {
|
||||
value = event_payload_item_print(epi);
|
||||
cmdq_print(wei->item, "%s=%s", key, value);
|
||||
free(value);
|
||||
}
|
||||
epi = event_payload_next(epi);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_wait_for_event_cb(__unused const char *name, struct event_payload *ep,
|
||||
void *item_data)
|
||||
{
|
||||
struct wait_event_item *wei = item_data;
|
||||
struct format_tree *ft;
|
||||
char *expanded;
|
||||
int flag;
|
||||
|
||||
if (wei->verbose)
|
||||
cmd_wait_for_event_print(wei, ep);
|
||||
|
||||
if (wei->filter != NULL) {
|
||||
ft = format_create(cmdq_get_client(wei->item), wei->item,
|
||||
FORMAT_NONE, FORMAT_NOJOBS);
|
||||
event_payload_add_formats(ep, ft, NULL);
|
||||
expanded = format_expand(ft, wei->filter);
|
||||
flag = format_true(expanded);
|
||||
free(expanded);
|
||||
format_free(ft);
|
||||
|
||||
if (!flag)
|
||||
return;
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&wait_event_items, wei, entry);
|
||||
cmdq_continue(wei->item);
|
||||
cmd_wait_for_event_free(wei);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_wait_for_event_free(struct wait_event_item *wei)
|
||||
{
|
||||
events_remove_sink(wei->sink);
|
||||
free(wei->name);
|
||||
free(wei->filter);
|
||||
free(wei);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_event(struct cmdq_item *item, const char *name, struct args *args)
|
||||
{
|
||||
struct wait_event_item *wei;
|
||||
const char *filter = args_get(args, 'F');
|
||||
|
||||
if (!hooks_valid_event_name(name)) {
|
||||
cmdq_error(item, "invalid event: %s", name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (args_has(args, 'l'))
|
||||
return (cmd_wait_for_event_list(item, name));
|
||||
if (args_has(args, 'w'))
|
||||
return (cmd_wait_for_event_wake(item, name, args));
|
||||
|
||||
if (cmdq_get_client(item) == NULL) {
|
||||
cmdq_error(item, "not able to wait");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
wei = xcalloc(1, sizeof *wei);
|
||||
wei->item = item;
|
||||
wei->name = xstrdup(name);
|
||||
wei->filter = (filter != NULL ? xstrdup(filter) : NULL);
|
||||
wei->verbose = args_has(args, 'v');
|
||||
wei->sink = events_add_sink(name, cmd_wait_for_event_cb, wei);
|
||||
TAILQ_INSERT_TAIL(&wait_event_items, wei, entry);
|
||||
|
||||
return (CMD_RETURN_WAIT);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_event_list(struct cmdq_item *item, const char *name)
|
||||
{
|
||||
struct wait_event_item *wei;
|
||||
|
||||
TAILQ_FOREACH(wei, &wait_event_items, entry) {
|
||||
if (strcmp(wei->name, name) == 0)
|
||||
cmdq_print(item, "%s", cmd_wait_for_client_name(wei));
|
||||
}
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_event_wake(struct cmdq_item *item, const char *name,
|
||||
struct args *args)
|
||||
{
|
||||
struct wait_event_item *wei, *wei1;
|
||||
const char *client_name = args_get(args, 'w');
|
||||
|
||||
TAILQ_FOREACH_SAFE(wei, &wait_event_items, entry, wei1) {
|
||||
if (strcmp(wei->name, name) != 0)
|
||||
continue;
|
||||
if (strcmp(cmd_wait_for_client_name(wei), client_name) != 0)
|
||||
continue;
|
||||
|
||||
TAILQ_REMOVE(&wait_event_items, wei, entry);
|
||||
cmdq_continue(wei->item);
|
||||
cmd_wait_for_event_free(wei);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
cmdq_error(item, "waiter %s not found", client_name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_list(struct cmdq_item *item, struct wait_channel *wc)
|
||||
{
|
||||
struct wait_item *wi;
|
||||
|
||||
if (wc == NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
TAILQ_FOREACH(wi, &wc->waiters, entry)
|
||||
cmdq_print(item, "%s", cmd_wait_for_item_client_name(wi->item));
|
||||
TAILQ_FOREACH(wi, &wc->lockers, entry)
|
||||
cmdq_print(item, "%s", cmd_wait_for_item_client_name(wi->item));
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_wake(__unused struct cmdq_item *item, const char *name,
|
||||
struct args *args, struct wait_channel *wc)
|
||||
{
|
||||
struct wait_item *wi, *wi1;
|
||||
const char *client_name = args_get(args, 'w');
|
||||
|
||||
if (wc != NULL) {
|
||||
TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
|
||||
name = cmd_wait_for_item_client_name(wi->item);
|
||||
if (strcmp(name, client_name) != 0)
|
||||
continue;
|
||||
cmdq_continue(wi->item);
|
||||
TAILQ_REMOVE(&wc->waiters, wi, entry);
|
||||
free(wi);
|
||||
cmd_wait_for_remove_empty(wc);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
TAILQ_FOREACH_SAFE(wi, &wc->lockers, entry, wi1) {
|
||||
name = cmd_wait_for_item_client_name(wi->item);
|
||||
if (strcmp(name, client_name) != 0)
|
||||
continue;
|
||||
cmdq_continue(wi->item);
|
||||
TAILQ_REMOVE(&wc->lockers, wi, entry);
|
||||
free(wi);
|
||||
cmd_wait_for_remove_empty(wc);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_signal(__unused struct cmdq_item *item, const char *name,
|
||||
struct wait_channel *wc)
|
||||
@@ -245,6 +485,13 @@ cmd_wait_for_flush(void)
|
||||
{
|
||||
struct wait_channel *wc, *wc1;
|
||||
struct wait_item *wi, *wi1;
|
||||
struct wait_event_item *wei, *wei1;
|
||||
|
||||
TAILQ_FOREACH_SAFE(wei, &wait_event_items, entry, wei1) {
|
||||
TAILQ_REMOVE(&wait_event_items, wei, entry);
|
||||
cmdq_continue(wei->item);
|
||||
cmd_wait_for_event_free(wei);
|
||||
}
|
||||
|
||||
RB_FOREACH_SAFE(wc, wait_channels, &wait_channels, wc1) {
|
||||
TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
|
||||
|
||||
265
cmd.c
265
cmd.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd.c,v 1.189 2026/07/17 08:29:34 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -71,6 +71,7 @@ extern const struct cmd_entry cmd_lock_server_entry;
|
||||
extern const struct cmd_entry cmd_lock_session_entry;
|
||||
extern const struct cmd_entry cmd_move_pane_entry;
|
||||
extern const struct cmd_entry cmd_move_window_entry;
|
||||
extern const struct cmd_entry cmd_new_pane_entry;
|
||||
extern const struct cmd_entry cmd_new_session_entry;
|
||||
extern const struct cmd_entry cmd_new_window_entry;
|
||||
extern const struct cmd_entry cmd_next_layout_entry;
|
||||
@@ -114,6 +115,7 @@ extern const struct cmd_entry cmd_suspend_client_entry;
|
||||
extern const struct cmd_entry cmd_swap_pane_entry;
|
||||
extern const struct cmd_entry cmd_swap_window_entry;
|
||||
extern const struct cmd_entry cmd_switch_client_entry;
|
||||
extern const struct cmd_entry cmd_switch_mode_entry;
|
||||
extern const struct cmd_entry cmd_unbind_key_entry;
|
||||
extern const struct cmd_entry cmd_unlink_window_entry;
|
||||
extern const struct cmd_entry cmd_wait_for_entry;
|
||||
@@ -163,6 +165,7 @@ const struct cmd_entry *cmd_table[] = {
|
||||
&cmd_lock_session_entry,
|
||||
&cmd_move_pane_entry,
|
||||
&cmd_move_window_entry,
|
||||
&cmd_new_pane_entry,
|
||||
&cmd_new_session_entry,
|
||||
&cmd_new_window_entry,
|
||||
&cmd_next_layout_entry,
|
||||
@@ -206,6 +209,7 @@ const struct cmd_entry *cmd_table[] = {
|
||||
&cmd_swap_pane_entry,
|
||||
&cmd_swap_window_entry,
|
||||
&cmd_switch_client_entry,
|
||||
&cmd_switch_mode_entry,
|
||||
&cmd_unbind_key_entry,
|
||||
&cmd_unlink_window_entry,
|
||||
&cmd_wait_for_entry,
|
||||
@@ -216,18 +220,11 @@ const struct cmd_entry *cmd_table[] = {
|
||||
struct cmd {
|
||||
const struct cmd_entry *entry;
|
||||
struct args *args;
|
||||
u_int group;
|
||||
|
||||
char *file;
|
||||
u_int line;
|
||||
int parse_flags;
|
||||
|
||||
TAILQ_ENTRY(cmd) qentry;
|
||||
};
|
||||
TAILQ_HEAD(cmds, cmd);
|
||||
|
||||
/* Next group number for new command list. */
|
||||
static u_int cmd_list_next_group = 1;
|
||||
|
||||
/* Log an argument vector. */
|
||||
void printflike(3, 4)
|
||||
@@ -303,6 +300,8 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
|
||||
|
||||
if (argc == 0)
|
||||
return (0);
|
||||
if (argc < 0 || argc > 1000)
|
||||
return (-1);
|
||||
*argv = xcalloc(argc, sizeof **argv);
|
||||
|
||||
buf[len - 1] = '\0';
|
||||
@@ -396,13 +395,6 @@ cmd_get_args(struct cmd *cmd)
|
||||
return (cmd->args);
|
||||
}
|
||||
|
||||
/* Get group for command. */
|
||||
u_int
|
||||
cmd_get_group(struct cmd *cmd)
|
||||
{
|
||||
return (cmd->group);
|
||||
}
|
||||
|
||||
/* Get file and line for command. */
|
||||
void
|
||||
cmd_get_source(struct cmd *cmd, const char **file, u_int *line)
|
||||
@@ -552,23 +544,6 @@ cmd_free(struct cmd *cmd)
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
/* Copy a command. */
|
||||
struct cmd *
|
||||
cmd_copy(struct cmd *cmd, int argc, char **argv)
|
||||
{
|
||||
struct cmd *new_cmd;
|
||||
|
||||
new_cmd = xcalloc(1, sizeof *new_cmd);
|
||||
new_cmd->entry = cmd->entry;
|
||||
new_cmd->args = args_copy(cmd->args, argc, argv);
|
||||
|
||||
if (cmd->file != NULL)
|
||||
new_cmd->file = xstrdup(cmd->file);
|
||||
new_cmd->line = cmd->line;
|
||||
|
||||
return (new_cmd);
|
||||
}
|
||||
|
||||
/* Get a command as a string. */
|
||||
char *
|
||||
cmd_print(struct cmd *cmd)
|
||||
@@ -585,175 +560,6 @@ cmd_print(struct cmd *cmd)
|
||||
return (out);
|
||||
}
|
||||
|
||||
/* Create a new command list. */
|
||||
struct cmd_list *
|
||||
cmd_list_new(void)
|
||||
{
|
||||
struct cmd_list *cmdlist;
|
||||
|
||||
cmdlist = xcalloc(1, sizeof *cmdlist);
|
||||
cmdlist->references = 1;
|
||||
cmdlist->group = cmd_list_next_group++;
|
||||
cmdlist->list = xcalloc(1, sizeof *cmdlist->list);
|
||||
TAILQ_INIT(cmdlist->list);
|
||||
return (cmdlist);
|
||||
}
|
||||
|
||||
/* Append a command to a command list. */
|
||||
void
|
||||
cmd_list_append(struct cmd_list *cmdlist, struct cmd *cmd)
|
||||
{
|
||||
cmd->group = cmdlist->group;
|
||||
TAILQ_INSERT_TAIL(cmdlist->list, cmd, qentry);
|
||||
}
|
||||
|
||||
/* Append all commands from one list to another. */
|
||||
void
|
||||
cmd_list_append_all(struct cmd_list *cmdlist, struct cmd_list *from)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
|
||||
TAILQ_FOREACH(cmd, from->list, qentry)
|
||||
cmd->group = cmdlist->group;
|
||||
TAILQ_CONCAT(cmdlist->list, from->list, qentry);
|
||||
}
|
||||
|
||||
/* Move all commands from one command list to another. */
|
||||
void
|
||||
cmd_list_move(struct cmd_list *cmdlist, struct cmd_list *from)
|
||||
{
|
||||
TAILQ_CONCAT(cmdlist->list, from->list, qentry);
|
||||
cmdlist->group = cmd_list_next_group++;
|
||||
}
|
||||
|
||||
/* Free a command list. */
|
||||
void
|
||||
cmd_list_free(struct cmd_list *cmdlist)
|
||||
{
|
||||
struct cmd *cmd, *cmd1;
|
||||
|
||||
if (--cmdlist->references != 0)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH_SAFE(cmd, cmdlist->list, qentry, cmd1) {
|
||||
TAILQ_REMOVE(cmdlist->list, cmd, qentry);
|
||||
cmd_free(cmd);
|
||||
}
|
||||
free(cmdlist->list);
|
||||
free(cmdlist);
|
||||
}
|
||||
|
||||
/* Copy a command list, expanding %s in arguments. */
|
||||
struct cmd_list *
|
||||
cmd_list_copy(const struct cmd_list *cmdlist, int argc, char **argv)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
struct cmd_list *new_cmdlist;
|
||||
struct cmd *new_cmd;
|
||||
u_int group = cmdlist->group;
|
||||
char *s;
|
||||
|
||||
s = cmd_list_print(cmdlist, 0);
|
||||
log_debug("%s: %s", __func__, s);
|
||||
free(s);
|
||||
|
||||
new_cmdlist = cmd_list_new();
|
||||
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
|
||||
if (cmd->group != group) {
|
||||
new_cmdlist->group = cmd_list_next_group++;
|
||||
group = cmd->group;
|
||||
}
|
||||
new_cmd = cmd_copy(cmd, argc, argv);
|
||||
cmd_list_append(new_cmdlist, new_cmd);
|
||||
}
|
||||
|
||||
s = cmd_list_print(new_cmdlist, 0);
|
||||
log_debug("%s: %s", __func__, s);
|
||||
free(s);
|
||||
|
||||
return (new_cmdlist);
|
||||
}
|
||||
|
||||
/* Get a command list as a string. */
|
||||
char *
|
||||
cmd_list_print(const struct cmd_list *cmdlist, int escaped)
|
||||
{
|
||||
struct cmd *cmd, *next;
|
||||
char *buf, *this;
|
||||
size_t len;
|
||||
|
||||
len = 1;
|
||||
buf = xcalloc(1, len);
|
||||
|
||||
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
|
||||
this = cmd_print(cmd);
|
||||
|
||||
len += strlen(this) + 6;
|
||||
buf = xrealloc(buf, len);
|
||||
|
||||
strlcat(buf, this, len);
|
||||
|
||||
next = TAILQ_NEXT(cmd, qentry);
|
||||
if (next != NULL) {
|
||||
if (cmd->group != next->group) {
|
||||
if (escaped)
|
||||
strlcat(buf, " \\;\\; ", len);
|
||||
else
|
||||
strlcat(buf, " ;; ", len);
|
||||
} else {
|
||||
if (escaped)
|
||||
strlcat(buf, " \\; ", len);
|
||||
else
|
||||
strlcat(buf, " ; ", len);
|
||||
}
|
||||
}
|
||||
|
||||
free(this);
|
||||
}
|
||||
|
||||
return (buf);
|
||||
}
|
||||
|
||||
/* Get first command in list. */
|
||||
struct cmd *
|
||||
cmd_list_first(struct cmd_list *cmdlist)
|
||||
{
|
||||
return (TAILQ_FIRST(cmdlist->list));
|
||||
}
|
||||
|
||||
/* Get next command in list. */
|
||||
struct cmd *
|
||||
cmd_list_next(struct cmd *cmd)
|
||||
{
|
||||
return (TAILQ_NEXT(cmd, qentry));
|
||||
}
|
||||
|
||||
/* Do all of the commands in this command list have this flag? */
|
||||
int
|
||||
cmd_list_all_have(struct cmd_list *cmdlist, int flag)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
|
||||
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
|
||||
if (~cmd->entry->flags & flag)
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Do any of the commands in this command list have this flag? */
|
||||
int
|
||||
cmd_list_any_have(struct cmd_list *cmdlist, int flag)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
|
||||
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
|
||||
if (cmd->entry->flags & flag)
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Adjust current mouse position for a pane. */
|
||||
int
|
||||
cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
|
||||
@@ -773,9 +579,9 @@ cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
|
||||
if (m->statusat == 0 && y >= m->statuslines)
|
||||
y -= m->statuslines;
|
||||
|
||||
if (x < wp->xoff || x >= wp->xoff + wp->sx)
|
||||
if ((int)x < wp->xoff || (int)x >= wp->xoff + (int)wp->sx)
|
||||
return (-1);
|
||||
if (y < wp->yoff || y >= wp->yoff + wp->sy)
|
||||
if ((int)y < wp->yoff || (int)y >= wp->yoff + (int)wp->sy)
|
||||
return (-1);
|
||||
|
||||
if (xp != NULL)
|
||||
@@ -827,20 +633,27 @@ cmd_mouse_pane(struct mouse_event *m, struct session **sp,
|
||||
if (!window_has_pane(wl->window, wp))
|
||||
return (NULL);
|
||||
}
|
||||
if (wl->window->modal != NULL && wp != wl->window->modal)
|
||||
return (NULL);
|
||||
|
||||
if (wlp != NULL)
|
||||
*wlp = wl;
|
||||
return (wp);
|
||||
}
|
||||
|
||||
/* Replace the first %% or %idx in template by s. */
|
||||
/*
|
||||
* Replace the first %% or any %idx in template by s. %% is intended for use in
|
||||
* single quotes, so ' is escaped. %%% and %idx% are for double quotes, so a
|
||||
* list of special characters is escaped. %idx is left unescaped.
|
||||
*/
|
||||
char *
|
||||
cmd_template_replace(const char *template, const char *s, int idx)
|
||||
{
|
||||
char ch, *buf;
|
||||
const char *ptr, *cp, quote[] = "\"\\$;~";
|
||||
int replaced, quoted;
|
||||
size_t len;
|
||||
const char *ptr, *cp, dquote[] = "\"\\$;~";
|
||||
int replaced;
|
||||
size_t len, slen;
|
||||
enum { NQ, SQ, DQ } quote;
|
||||
|
||||
if (strchr(template, '%') == NULL)
|
||||
return (xstrdup(template));
|
||||
@@ -854,30 +667,52 @@ cmd_template_replace(const char *template, const char *s, int idx)
|
||||
while (*ptr != '\0') {
|
||||
switch (ch = *ptr++) {
|
||||
case '%':
|
||||
if (*ptr < '1' || *ptr > '9' || *ptr - '0' != idx) {
|
||||
if (*ptr >= '1' && *ptr <= '9' && *ptr - '0' == idx) {
|
||||
ptr++;
|
||||
quote = NQ;
|
||||
if (*ptr == '%') {
|
||||
quote = DQ;
|
||||
ptr++;
|
||||
}
|
||||
} else {
|
||||
if (*ptr != '%' || replaced)
|
||||
break;
|
||||
replaced = 1;
|
||||
ptr++;
|
||||
quote = SQ;
|
||||
if (*ptr == '%') {
|
||||
quote = DQ;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
ptr++;
|
||||
|
||||
quoted = (*ptr == '%');
|
||||
if (quoted)
|
||||
ptr++;
|
||||
|
||||
buf = xrealloc(buf, len + (strlen(s) * 3) + 1);
|
||||
slen = strlen(s);
|
||||
if (slen >= SIZE_MAX / 4 ||
|
||||
len > SIZE_MAX - (slen * 4) - 1)
|
||||
fatalx("argument too long");
|
||||
buf = xrealloc(buf, len + (slen * 4) + 1);
|
||||
for (cp = s; *cp != '\0'; cp++) {
|
||||
if (quoted && strchr(quote, *cp) != NULL)
|
||||
if (quote == SQ && *cp == '\'') {
|
||||
buf[len++] = '\'';
|
||||
buf[len++] = '\\';
|
||||
buf[len++] = '\'';
|
||||
buf[len++] = '\'';
|
||||
continue;
|
||||
}
|
||||
if (quote == DQ && strchr(dquote, *cp) != NULL)
|
||||
buf[len++] = '\\';
|
||||
buf[len++] = *cp;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
continue;
|
||||
}
|
||||
if (len > SIZE_MAX - 2)
|
||||
fatalx("argument too long");
|
||||
buf = xrealloc(buf, len + 2);
|
||||
buf[len++] = ch;
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
||||
log_debug("%s: %s -> %s", __func__, template, buf);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
207
colour.c
207
colour.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: colour.c,v 1.35 2026/07/06 14:29:10 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -26,6 +26,85 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Theme colour slots and their server options. */
|
||||
static const struct {
|
||||
const char *name;
|
||||
const char *dark_option;
|
||||
const char *light_option;
|
||||
int terminal_colour;
|
||||
} colour_theme_table[] = {
|
||||
{ "themeblack",
|
||||
"dark-theme-black",
|
||||
"light-theme-black",
|
||||
0
|
||||
},
|
||||
{ "themewhite",
|
||||
"dark-theme-white",
|
||||
"light-theme-white",
|
||||
7
|
||||
},
|
||||
{ "themelightgrey",
|
||||
"dark-theme-light-grey",
|
||||
"light-theme-light-grey",
|
||||
7
|
||||
},
|
||||
{ "themedarkgrey",
|
||||
"dark-theme-dark-grey",
|
||||
"light-theme-dark-grey",
|
||||
0
|
||||
},
|
||||
{ "themegreen",
|
||||
"dark-theme-green",
|
||||
"light-theme-green",
|
||||
2
|
||||
},
|
||||
{ "themeyellow",
|
||||
"dark-theme-yellow",
|
||||
"light-theme-yellow",
|
||||
3
|
||||
},
|
||||
{ "themered",
|
||||
"dark-theme-red",
|
||||
"light-theme-red",
|
||||
1
|
||||
},
|
||||
{ "themeblue",
|
||||
"dark-theme-blue",
|
||||
"light-theme-blue",
|
||||
4
|
||||
},
|
||||
{ "themecyan",
|
||||
"dark-theme-cyan",
|
||||
"light-theme-cyan",
|
||||
6
|
||||
},
|
||||
{ "thememagenta",
|
||||
"dark-theme-magenta",
|
||||
"light-theme-magenta",
|
||||
5
|
||||
}
|
||||
};
|
||||
|
||||
/* Get theme colour option. */
|
||||
const char *
|
||||
colour_theme_option(u_int n, enum client_theme theme)
|
||||
{
|
||||
if (n >= nitems(colour_theme_table))
|
||||
return (NULL);
|
||||
if (theme == THEME_LIGHT)
|
||||
return (colour_theme_table[n].light_option);
|
||||
return (colour_theme_table[n].dark_option);
|
||||
}
|
||||
|
||||
/* Get theme terminal colour. */
|
||||
int
|
||||
colour_theme_terminal_colour(u_int n)
|
||||
{
|
||||
if (n >= nitems(colour_theme_table))
|
||||
return (8);
|
||||
return (colour_theme_table[n].terminal_colour);
|
||||
}
|
||||
|
||||
static int
|
||||
colour_dist_sq(int R, int G, int B, int r, int g, int b)
|
||||
{
|
||||
@@ -120,6 +199,28 @@ colour_force_rgb(int c)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Dim colour by a percentage. */
|
||||
int
|
||||
colour_dim(int c, u_int dim)
|
||||
{
|
||||
u_char r, g, b;
|
||||
|
||||
if (dim == 0 || COLOUR_DEFAULT(c) || (c & COLOUR_FLAG_THEME))
|
||||
return (c);
|
||||
if (dim >= 100)
|
||||
return (colour_join_rgb(0, 0, 0));
|
||||
|
||||
c = colour_force_rgb(c);
|
||||
if (c == -1)
|
||||
return (-1);
|
||||
colour_split_rgb(c, &r, &g, &b);
|
||||
|
||||
r = (r * (100 - dim)) / 100;
|
||||
g = (g * (100 - dim)) / 100;
|
||||
b = (b * (100 - dim)) / 100;
|
||||
return (colour_join_rgb(r, g, b));
|
||||
}
|
||||
|
||||
/* Convert colour to a string. */
|
||||
const char *
|
||||
colour_tostring(int c)
|
||||
@@ -130,6 +231,13 @@ colour_tostring(int c)
|
||||
if (c == -1)
|
||||
return ("none");
|
||||
|
||||
if (c & COLOUR_FLAG_THEME) {
|
||||
c &= 0xff;
|
||||
if (c >= 0 && (u_int)c < nitems(colour_theme_table))
|
||||
return (colour_theme_table[c].name);
|
||||
return ("invalid");
|
||||
}
|
||||
|
||||
if (c & COLOUR_FLAG_RGB) {
|
||||
colour_split_rgb(c, &r, &g, &b);
|
||||
xsnprintf(s, sizeof s, "#%02x%02x%02x", r, g, b);
|
||||
@@ -182,6 +290,58 @@ colour_tostring(int c)
|
||||
return ("invalid");
|
||||
}
|
||||
|
||||
/* Convert colour to an SGR escape sequence. */
|
||||
const char *
|
||||
colour_toescape(struct client *c, int colour, int bg)
|
||||
{
|
||||
static char s[32];
|
||||
u_char r, g, b;
|
||||
int n, flags = (TERM_256COLOURS|TERM_RGBCOLOURS);
|
||||
u_int o = (bg ? 40 : 30);
|
||||
|
||||
if (c != NULL && (c->tty.flags & TTY_OPENED) && c->tty.term != NULL)
|
||||
flags = c->tty.term->flags;
|
||||
|
||||
if (colour & COLOUR_FLAG_THEME) {
|
||||
n = colour & 0xff;
|
||||
if (c != NULL && (u_int)n < COLOUR_THEME_COUNT)
|
||||
colour = c->theme_colours[n];
|
||||
else
|
||||
colour = colour_theme_terminal_colour(n);
|
||||
}
|
||||
|
||||
if (colour == 8 || colour == 9) {
|
||||
xsnprintf(s, sizeof s, "\033[%dm", o + 9);
|
||||
return (s);
|
||||
}
|
||||
|
||||
if ((~flags & TERM_RGBCOLOURS) & (colour & COLOUR_FLAG_RGB)) {
|
||||
colour_split_rgb(colour, &r, &g, &b);
|
||||
colour = colour_find_rgb(r, g, b);
|
||||
}
|
||||
if ((~flags & TERM_256COLOURS) & (colour & COLOUR_FLAG_256))
|
||||
colour = colour_256to16(colour);
|
||||
|
||||
if (colour & COLOUR_FLAG_RGB) {
|
||||
colour_split_rgb(colour, &r, &g, &b);
|
||||
xsnprintf(s, sizeof s, "\033[%d;2;%u;%u;%um", o + 8, r, g, b);
|
||||
return (s);
|
||||
}
|
||||
if (colour & COLOUR_FLAG_256) {
|
||||
xsnprintf(s, sizeof s, "\033[%d;5;%um", o + 8, colour & 0xff);
|
||||
return (s);
|
||||
}
|
||||
if (colour >= 0 && colour <= 7) {
|
||||
xsnprintf(s, sizeof s, "\033[%dm", colour + o);
|
||||
return (s);
|
||||
}
|
||||
if (colour >= 90 && colour <= 97) {
|
||||
xsnprintf(s, sizeof s, "\033[%dm", colour + o - 30);
|
||||
return (s);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Convert background colour to theme. */
|
||||
enum client_theme
|
||||
colour_totheme(int c)
|
||||
@@ -230,6 +390,7 @@ colour_fromstring(const char *s)
|
||||
const char *cp;
|
||||
int n;
|
||||
u_char r, g, b;
|
||||
u_int i;
|
||||
|
||||
if (*s == '#' && strlen(s) == 7) {
|
||||
for (cp = s + 1; isxdigit((u_char) *cp); cp++)
|
||||
@@ -260,6 +421,11 @@ colour_fromstring(const char *s)
|
||||
if (strcasecmp(s, "terminal") == 0)
|
||||
return (9);
|
||||
|
||||
for (i = 0; i < nitems(colour_theme_table); i++) {
|
||||
if (strcasecmp(s, colour_theme_table[i].name) == 0)
|
||||
return (i|COLOUR_FLAG_THEME);
|
||||
}
|
||||
|
||||
if (strcasecmp(s, "black") == 0 || strcmp(s, "0") == 0)
|
||||
return (0);
|
||||
if (strcasecmp(s, "red") == 0 || strcmp(s, "1") == 0)
|
||||
@@ -1082,22 +1248,22 @@ colour_palette_free(struct colour_palette *p)
|
||||
|
||||
/* Get a colour from a palette. */
|
||||
int
|
||||
colour_palette_get(struct colour_palette *p, int c)
|
||||
colour_palette_get(struct colour_palette *p, int n)
|
||||
{
|
||||
if (p == NULL)
|
||||
return (-1);
|
||||
|
||||
if (c >= 90 && c <= 97)
|
||||
c = 8 + c - 90;
|
||||
else if (c & COLOUR_FLAG_256)
|
||||
c &= ~COLOUR_FLAG_256;
|
||||
else if (c >= 8)
|
||||
if (n >= 90 && n <= 97)
|
||||
n = 8 + n - 90;
|
||||
else if (n & COLOUR_FLAG_256)
|
||||
n &= ~COLOUR_FLAG_256;
|
||||
else if (n >= 8)
|
||||
return (-1);
|
||||
|
||||
if (p->palette != NULL && p->palette[c] != -1)
|
||||
return (p->palette[c]);
|
||||
if (p->default_palette != NULL && p->default_palette[c] != -1)
|
||||
return (p->default_palette[c]);
|
||||
if (p->palette != NULL && p->palette[n] != -1)
|
||||
return (p->palette[n]);
|
||||
if (p->default_palette != NULL && p->default_palette[n] != -1)
|
||||
return (p->default_palette[n]);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@@ -1107,14 +1273,13 @@ colour_palette_set(struct colour_palette *p, int n, int c)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
if (p == NULL || n > 255)
|
||||
if (p == NULL || n < 0 || n > 255)
|
||||
return (0);
|
||||
|
||||
if (c == -1 && p->palette == NULL)
|
||||
return (0);
|
||||
|
||||
if (c != -1 && p->palette == NULL) {
|
||||
if (p->palette == NULL)
|
||||
if (p->palette == NULL) {
|
||||
p->palette = xcalloc(256, sizeof *p->palette);
|
||||
for (i = 0; i < 256; i++)
|
||||
p->palette[i] = -1;
|
||||
@@ -1129,7 +1294,8 @@ colour_palette_from_option(struct colour_palette *p, struct options *oo)
|
||||
{
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
u_int i, n;
|
||||
union options_value *ov;
|
||||
u_int i;
|
||||
int c;
|
||||
|
||||
if (p == NULL)
|
||||
@@ -1147,12 +1313,11 @@ colour_palette_from_option(struct colour_palette *p, struct options *oo)
|
||||
p->default_palette = xcalloc(256, sizeof *p->default_palette);
|
||||
for (i = 0; i < 256; i++)
|
||||
p->default_palette[i] = -1;
|
||||
while (a != NULL) {
|
||||
n = options_array_item_index(a);
|
||||
if (n < 256) {
|
||||
c = options_array_item_value(a)->number;
|
||||
p->default_palette[n] = c;
|
||||
for (i = 0; i < 256; i++) {
|
||||
ov = options_array_getv(o, "%u", i);
|
||||
if (ov != NULL) {
|
||||
c = ov->number;
|
||||
p->default_palette[i] = c;
|
||||
}
|
||||
a = options_array_next(a);
|
||||
}
|
||||
}
|
||||
|
||||
10
compat.h
10
compat.h
@@ -388,7 +388,7 @@ int clock_gettime(int, struct timespec *);
|
||||
/* base64.c */
|
||||
#undef b64_ntop
|
||||
#undef b64_pton
|
||||
int b64_ntop(const char *, size_t, char *, size_t);
|
||||
int b64_ntop(const u_char *, size_t, char *, size_t);
|
||||
int b64_pton(const char *, u_char *, size_t);
|
||||
#endif
|
||||
|
||||
@@ -410,11 +410,6 @@ int asprintf(char **, const char *, ...);
|
||||
int vasprintf(char **, const char *, va_list);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FGETLN
|
||||
/* fgetln.c */
|
||||
char *fgetln(FILE *, size_t *);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETLINE
|
||||
/* getline.c */
|
||||
ssize_t getline(char **, size_t *, FILE *);
|
||||
@@ -463,6 +458,9 @@ int utf8proc_wctomb(char *, wchar_t);
|
||||
#ifdef NEED_FUZZING
|
||||
/* tmux.c */
|
||||
#define main __weak main
|
||||
#define regcomp(preg, pattern, cflags) (0)
|
||||
#define regexec(preg, string, nmatch, pmatch, eflags) (REG_NOMATCH)
|
||||
#define regfree(preg) ((void)0)
|
||||
#endif
|
||||
|
||||
/* getopt.c */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: base64.c,v 1.8 2015/01/16 16:48:51 deraadt Exp $ */
|
||||
/* $OpenBSD: base64.c,v 1.15 2021/10/25 14:41:09 jca Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996 by Internet Software Consortium.
|
||||
@@ -46,15 +46,15 @@
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <arpa/nameser.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <resolv.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
static const char Base64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char Pad64 = '=';
|
||||
@@ -123,15 +123,12 @@ static const char Pad64 = '=';
|
||||
*/
|
||||
|
||||
int
|
||||
b64_ntop(src, srclength, target, targsize)
|
||||
u_char const *src;
|
||||
size_t srclength;
|
||||
char *target;
|
||||
size_t targsize;
|
||||
b64_ntop(unsigned char const *src, size_t srclength, char *target,
|
||||
size_t targsize)
|
||||
{
|
||||
size_t datalength = 0;
|
||||
u_char input[3];
|
||||
u_char output[4];
|
||||
unsigned char input[3];
|
||||
unsigned char output[4];
|
||||
int i;
|
||||
|
||||
while (2 < srclength) {
|
||||
@@ -187,13 +184,10 @@ b64_ntop(src, srclength, target, targsize)
|
||||
*/
|
||||
|
||||
int
|
||||
b64_pton(src, target, targsize)
|
||||
char const *src;
|
||||
u_char *target;
|
||||
size_t targsize;
|
||||
b64_pton(char const *src, unsigned char *target, size_t targsize)
|
||||
{
|
||||
int tarindex, state, ch;
|
||||
u_char nextbyte;
|
||||
unsigned char nextbyte;
|
||||
char *pos;
|
||||
|
||||
state = 0;
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Joerg Jung <jung@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* portable fgetln() version, NOT reentrant
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
char *
|
||||
fgetln(FILE *fp, size_t *len)
|
||||
{
|
||||
static char *buf = NULL;
|
||||
static size_t bufsz = 0;
|
||||
size_t r = 0;
|
||||
char *p;
|
||||
int c, e;
|
||||
|
||||
if (!fp || !len) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (!buf) {
|
||||
if (!(buf = calloc(1, BUFSIZ)))
|
||||
return NULL;
|
||||
bufsz = BUFSIZ;
|
||||
}
|
||||
while ((c = getc(fp)) != EOF) {
|
||||
buf[r++] = c;
|
||||
if (r == bufsz) {
|
||||
if (!(p = reallocarray(buf, 2, bufsz))) {
|
||||
e = errno;
|
||||
free(buf);
|
||||
errno = e;
|
||||
buf = NULL, bufsz = 0;
|
||||
return NULL;
|
||||
}
|
||||
buf = p, bufsz = 2 * bufsz;
|
||||
}
|
||||
if (c == '\n')
|
||||
break;
|
||||
}
|
||||
return (*len = r) ? buf : NULL;
|
||||
}
|
||||
@@ -74,8 +74,14 @@ getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp)
|
||||
}
|
||||
if (ptr + 2 >= eptr) {
|
||||
char *nbuf;
|
||||
size_t nbufsiz = *bufsiz * 2;
|
||||
size_t nbufsiz;
|
||||
ssize_t d = ptr - *buf;
|
||||
|
||||
if (*bufsiz > SIZE_MAX / 2) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
nbufsiz = *bufsiz * 2;
|
||||
if ((nbuf = realloc(*buf, nbufsiz)) == NULL)
|
||||
return -1;
|
||||
*buf = nbuf;
|
||||
|
||||
@@ -339,7 +339,7 @@ static int
|
||||
getopt_internal(int nargc, char * const *nargv, const char *options,
|
||||
const struct option *long_options, int *idx, int flags)
|
||||
{
|
||||
char *oli; /* option letter list index */
|
||||
const char *oli; /* option letter list index */
|
||||
int optchar, short_too;
|
||||
static int posixly_correct = -1;
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ getpeereid(int s, uid_t *uid, gid_t *gid)
|
||||
{
|
||||
#ifdef HAVE_SO_PEERCRED
|
||||
struct ucred uc;
|
||||
int len = sizeof uc;
|
||||
socklen_t len = sizeof uc;
|
||||
|
||||
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &uc, &len) == -1)
|
||||
return (-1);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: imsg-buffer.c,v 1.35 2025/06/04 09:06:56 claudio Exp $ */
|
||||
/* $OpenBSD: imsg-buffer.c,v 1.36 2025/08/25 08:29:49 claudio Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
|
||||
@@ -699,8 +699,6 @@ msgbuf_queuelen(struct msgbuf *msgbuf)
|
||||
void
|
||||
msgbuf_clear(struct msgbuf *msgbuf)
|
||||
{
|
||||
struct ibuf *buf;
|
||||
|
||||
/* write side */
|
||||
ibufq_flush(&msgbuf->bufs);
|
||||
|
||||
|
||||
@@ -81,7 +81,8 @@ struct systemd_job_watch {
|
||||
};
|
||||
|
||||
static int
|
||||
job_removed_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
|
||||
job_removed_handler(sd_bus_message *m, void *userdata,
|
||||
__unused sd_bus_error *ret_error)
|
||||
{
|
||||
struct systemd_job_watch *watch = userdata;
|
||||
const char *path = NULL;
|
||||
@@ -109,7 +110,7 @@ systemd_move_to_new_cgroup(char **cause)
|
||||
sd_bus_message *m = NULL, *reply = NULL;
|
||||
sd_bus *bus = NULL;
|
||||
sd_bus_slot *slot = NULL;
|
||||
char *name, *desc, *slice;
|
||||
char *name, *desc, *slice, *unit;
|
||||
sd_id128_t uuid;
|
||||
int r;
|
||||
uint64_t elapsed_usec;
|
||||
@@ -241,6 +242,26 @@ systemd_move_to_new_cgroup(char **cause)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try locating systemd unit that started the server, and mark pane units
|
||||
* as dependent on it. Use "Before" to make sure systemd will not try to
|
||||
* kill them first.
|
||||
*/
|
||||
if (sd_pid_get_user_unit(parent_pid, &unit) == 0 ||
|
||||
sd_pid_get_unit(parent_pid, &unit) == 0) {
|
||||
r = sd_bus_message_append(m, "(sv)", "Before", "as", 1, unit);
|
||||
if (r >= 0) {
|
||||
r = sd_bus_message_append(m, "(sv)", "PartOf", "as", 1,
|
||||
unit);
|
||||
}
|
||||
free(unit);
|
||||
if (r < 0) {
|
||||
xasprintf(cause, "failed to append to properties: %s",
|
||||
strerror(-r));
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
/* End properties array. */
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0) {
|
||||
|
||||
195
configure.ac
195
configure.ac
@@ -1,6 +1,6 @@
|
||||
# configure.ac
|
||||
|
||||
AC_INIT([tmux], 3.6)
|
||||
AC_INIT([tmux], next-3.8)
|
||||
AC_PREREQ([2.60])
|
||||
|
||||
AC_CONFIG_AUX_DIR(etc)
|
||||
@@ -64,6 +64,22 @@ AC_ARG_ENABLE(
|
||||
)
|
||||
AM_CONDITIONAL(IS_DEBUG, test "x$enable_debug" = xyes)
|
||||
|
||||
# Is this --enable-optimizations?
|
||||
AC_ARG_ENABLE(
|
||||
optimizations,
|
||||
AS_HELP_STRING(--enable-optimizations, enable optimization build flags),
|
||||
,
|
||||
enable_optimizations=yes
|
||||
)
|
||||
AM_CONDITIONAL(IS_OPTIMIZED, test "x$enable_optimizations" = xyes)
|
||||
|
||||
# Is this --enable-asan?
|
||||
AC_ARG_ENABLE(
|
||||
asan,
|
||||
AS_HELP_STRING(--enable-asan, enable ASAN build flags)
|
||||
)
|
||||
AM_CONDITIONAL(IS_ASAN, test "x$enable_asan" = xyes)
|
||||
|
||||
# Is this a static build?
|
||||
AC_ARG_ENABLE(
|
||||
static,
|
||||
@@ -159,7 +175,6 @@ AC_REPLACE_FUNCS([ \
|
||||
clock_gettime \
|
||||
closefrom \
|
||||
explicit_bzero \
|
||||
fgetln \
|
||||
freezero \
|
||||
getdtablecount \
|
||||
getdtablesize \
|
||||
@@ -223,6 +238,7 @@ AC_LIBOBJ(getopt_long)
|
||||
|
||||
# Look for libevent. Try libevent_core or libevent with pkg-config first then
|
||||
# look for the library.
|
||||
libevent_version=off
|
||||
PKG_CHECK_MODULES(
|
||||
LIBEVENT_CORE,
|
||||
[libevent_core >= 2],
|
||||
@@ -231,6 +247,8 @@ PKG_CHECK_MODULES(
|
||||
CPPFLAGS="$AM_CPPFLAGS $SAVED_CPPFLAGS"
|
||||
LIBS="$LIBEVENT_CORE_LIBS $LIBS"
|
||||
found_libevent=yes
|
||||
libevent_version=`$PKG_CONFIG --modversion libevent_core 2>/dev/null`
|
||||
test "x$libevent_version" = x && libevent_version=on
|
||||
],
|
||||
found_libevent=no
|
||||
)
|
||||
@@ -243,6 +261,8 @@ if test x$found_libevent = xno; then
|
||||
CPPFLAGS="$AM_CPPFLAGS $SAVED_CPPFLAGS"
|
||||
LIBS="$LIBEVENT_LIBS $LIBS"
|
||||
found_libevent=yes
|
||||
libevent_version=`$PKG_CONFIG --modversion libevent 2>/dev/null`
|
||||
test "x$libevent_version" = x && libevent_version=on
|
||||
],
|
||||
found_libevent=no
|
||||
)
|
||||
@@ -251,7 +271,8 @@ if test x$found_libevent = xno; then
|
||||
AC_SEARCH_LIBS(
|
||||
event_init,
|
||||
[event_core event event-1.4],
|
||||
found_libevent=yes,
|
||||
[found_libevent=yes
|
||||
libevent_version=on],
|
||||
found_libevent=no
|
||||
)
|
||||
fi
|
||||
@@ -278,7 +299,22 @@ fi
|
||||
|
||||
# Look for ncurses or curses. Try pkg-config first then directly for the
|
||||
# library.
|
||||
ncurses_version=off
|
||||
PKG_CHECK_MODULES(
|
||||
LIBTINFOW,
|
||||
tinfow,
|
||||
[
|
||||
AM_CPPFLAGS="$LIBTINFOW_CFLAGS $AM_CPPFLAGS"
|
||||
CPPFLAGS="$LIBTINFOW_CFLAGS $SAVED_CPPFLAGS"
|
||||
LIBS="$LIBTINFOW_LIBS $LIBS"
|
||||
found_ncurses=yes
|
||||
ncurses_version=`$PKG_CONFIG --modversion tinfow 2>/dev/null`
|
||||
test "x$ncurses_version" = x && ncurses_version=on
|
||||
],
|
||||
found_ncurses=no
|
||||
)
|
||||
if test "x$found_ncurses" = xno; then
|
||||
PKG_CHECK_MODULES(
|
||||
LIBTINFO,
|
||||
tinfo,
|
||||
[
|
||||
@@ -286,18 +322,8 @@ PKG_CHECK_MODULES(
|
||||
CPPFLAGS="$LIBTINFO_CFLAGS $SAVED_CPPFLAGS"
|
||||
LIBS="$LIBTINFO_LIBS $LIBS"
|
||||
found_ncurses=yes
|
||||
],
|
||||
found_ncurses=no
|
||||
)
|
||||
if test "x$found_ncurses" = xno; then
|
||||
PKG_CHECK_MODULES(
|
||||
LIBNCURSES,
|
||||
ncurses,
|
||||
[
|
||||
AM_CPPFLAGS="$LIBNCURSES_CFLAGS $AM_CPPFLAGS"
|
||||
CPPFLAGS="$LIBNCURSES_CFLAGS $SAVED_CPPFLAGS"
|
||||
LIBS="$LIBNCURSES_LIBS $LIBS"
|
||||
found_ncurses=yes
|
||||
ncurses_version=`$PKG_CONFIG --modversion tinfo 2>/dev/null`
|
||||
test "x$ncurses_version" = x && ncurses_version=on
|
||||
],
|
||||
found_ncurses=no
|
||||
)
|
||||
@@ -311,6 +337,23 @@ if test "x$found_ncurses" = xno; then
|
||||
CPPFLAGS="$LIBNCURSESW_CFLAGS $SAVED_CPPFLAGS"
|
||||
LIBS="$LIBNCURSESW_LIBS $LIBS"
|
||||
found_ncurses=yes
|
||||
ncurses_version=`$PKG_CONFIG --modversion ncursesw 2>/dev/null`
|
||||
test "x$ncurses_version" = x && ncurses_version=on
|
||||
],
|
||||
found_ncurses=no
|
||||
)
|
||||
fi
|
||||
if test "x$found_ncurses" = xno; then
|
||||
PKG_CHECK_MODULES(
|
||||
LIBNCURSES,
|
||||
ncurses,
|
||||
[
|
||||
AM_CPPFLAGS="$LIBNCURSES_CFLAGS $AM_CPPFLAGS"
|
||||
CPPFLAGS="$LIBNCURSES_CFLAGS $SAVED_CPPFLAGS"
|
||||
LIBS="$LIBNCURSES_LIBS $LIBS"
|
||||
found_ncurses=yes
|
||||
ncurses_version=`$PKG_CONFIG --modversion ncurses 2>/dev/null`
|
||||
test "x$ncurses_version" = x && ncurses_version=on
|
||||
],
|
||||
found_ncurses=no
|
||||
)
|
||||
@@ -318,8 +361,9 @@ fi
|
||||
if test "x$found_ncurses" = xno; then
|
||||
AC_SEARCH_LIBS(
|
||||
setupterm,
|
||||
[tinfo terminfo ncurses ncursesw],
|
||||
found_ncurses=yes,
|
||||
[tinfow tinfo terminfo ncursesw ncurses],
|
||||
[found_ncurses=yes
|
||||
ncurses_version=on],
|
||||
found_ncurses=no
|
||||
)
|
||||
if test "x$found_ncurses" = xyes; then
|
||||
@@ -349,6 +393,7 @@ else
|
||||
LIBS="$LIBS -lcurses"
|
||||
CPPFLAGS="$CPPFLAGS -DHAVE_CURSES_H"
|
||||
AC_DEFINE(HAVE_CURSES_H)
|
||||
ncurses_version=on
|
||||
else
|
||||
AC_MSG_ERROR("curses not found")
|
||||
fi
|
||||
@@ -359,6 +404,7 @@ AC_CHECK_FUNCS([ \
|
||||
])
|
||||
|
||||
# Look for utempter.
|
||||
utempter_version=off
|
||||
AC_ARG_ENABLE(
|
||||
utempter,
|
||||
AS_HELP_STRING(--enable-utempter, use utempter if it is installed)
|
||||
@@ -375,17 +421,34 @@ if test "x$enable_utempter" = xyes; then
|
||||
fi
|
||||
if test "x$enable_utempter" = xyes; then
|
||||
AC_DEFINE(HAVE_UTEMPTER)
|
||||
utempter_version=on
|
||||
else
|
||||
AC_MSG_ERROR("utempter not found")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Look for utf8proc.
|
||||
utf8proc_version=off
|
||||
AC_ARG_ENABLE(
|
||||
utf8proc,
|
||||
AS_HELP_STRING(--enable-utf8proc, use utf8proc if it is installed)
|
||||
)
|
||||
try_utf8proc=no
|
||||
require_utf8proc=no
|
||||
if test "x$enable_utf8proc" = xyes; then
|
||||
try_utf8proc=yes
|
||||
elif test "x$enable_utf8proc" = x; then
|
||||
case "$host_os" in
|
||||
*darwin*)
|
||||
try_utf8proc=yes
|
||||
require_utf8proc=yes
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if test "x$try_utf8proc" = xyes; then
|
||||
SAVED_AM_CPPFLAGS="$AM_CPPFLAGS"
|
||||
SAVED_OLD_CPPFLAGS="$CPPFLAGS"
|
||||
SAVED_LIBS="$LIBS"
|
||||
PKG_CHECK_MODULES(
|
||||
LIBUTF8PROC,
|
||||
libutf8proc,
|
||||
@@ -393,7 +456,10 @@ if test "x$enable_utf8proc" = xyes; then
|
||||
AM_CPPFLAGS="$LIBUTF8PROC_CFLAGS $AM_CPPFLAGS"
|
||||
CPPFLAGS="$LIBUTF8PROC_CFLAGS $SAVED_CPPFLAGS"
|
||||
LIBS="$LIBUTF8PROC_LIBS $LIBS"
|
||||
]
|
||||
utf8proc_version=`$PKG_CONFIG --modversion libutf8proc 2>/dev/null`
|
||||
test "x$utf8proc_version" = x && utf8proc_version=on
|
||||
],
|
||||
[:]
|
||||
)
|
||||
AC_CHECK_HEADER(utf8proc.h, enable_utf8proc=yes, enable_utf8proc=no)
|
||||
if test "x$enable_utf8proc" = xyes; then
|
||||
@@ -406,13 +472,23 @@ if test "x$enable_utf8proc" = xyes; then
|
||||
fi
|
||||
if test "x$enable_utf8proc" = xyes; then
|
||||
AC_DEFINE(HAVE_UTF8PROC)
|
||||
test "x$utf8proc_version" = xoff && utf8proc_version=on
|
||||
else
|
||||
AM_CPPFLAGS="$SAVED_AM_CPPFLAGS"
|
||||
CPPFLAGS="$SAVED_OLD_CPPFLAGS"
|
||||
LIBS="$SAVED_LIBS"
|
||||
utf8proc_version=off
|
||||
if test "x$require_utf8proc" = xyes; then
|
||||
enable_utf8proc=
|
||||
else
|
||||
AC_MSG_ERROR("utf8proc not found")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_UTF8PROC, [test "x$enable_utf8proc" = xyes])
|
||||
|
||||
# Check for systemd support.
|
||||
systemd_version=off
|
||||
AC_ARG_ENABLE(
|
||||
systemd,
|
||||
AS_HELP_STRING(--enable-systemd, enable systemd integration)
|
||||
@@ -426,6 +502,8 @@ if test x"$enable_systemd" = xyes; then
|
||||
CPPFLAGS="$AM_CPPFLAGS $SAVED_CPPFLAGS"
|
||||
LIBS="$SYSTEMD_LIBS $LIBS"
|
||||
found_systemd=yes
|
||||
systemd_version=`$PKG_CONFIG --modversion libsystemd 2>/dev/null`
|
||||
test "x$systemd_version" = x && systemd_version=on
|
||||
],
|
||||
found_systemd=no
|
||||
)
|
||||
@@ -550,11 +628,34 @@ if test "x$found_malloc_trim" = xyes; then
|
||||
fi
|
||||
|
||||
# Build against jemalloc if requested.
|
||||
jemalloc_version=off
|
||||
AC_ARG_ENABLE(
|
||||
jemalloc,
|
||||
AS_HELP_STRING(--enable-jemalloc, use jemalloc if it is installed)
|
||||
)
|
||||
try_jemalloc=no
|
||||
require_jemalloc=no
|
||||
if test "x$enable_asan" = xyes && test "x$enable_jemalloc" = xyes; then
|
||||
AC_MSG_ERROR([--enable-asan and --enable-jemalloc cannot be used together])
|
||||
fi
|
||||
if test "x$enable_jemalloc" = xyes; then
|
||||
try_jemalloc=yes
|
||||
elif test "x$enable_jemalloc" = x; then
|
||||
case "$host_os" in
|
||||
*darwin*)
|
||||
if test "x$enable_asan" = xyes; then
|
||||
enable_jemalloc=no
|
||||
else
|
||||
try_jemalloc=yes
|
||||
require_jemalloc=yes
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if test "x$try_jemalloc" = xyes; then
|
||||
SAVED_AM_CPPFLAGS="$AM_CPPFLAGS"
|
||||
SAVED_OLD_CPPFLAGS="$CPPFLAGS"
|
||||
SAVED_LIBS="$LIBS"
|
||||
PKG_CHECK_MODULES(
|
||||
JEMALLOC,
|
||||
jemalloc,
|
||||
@@ -562,9 +663,26 @@ if test "x$enable_jemalloc" = xyes; then
|
||||
AM_CPPFLAGS="$JEMALLOC_CFLAGS $AM_CPPFLAGS"
|
||||
CPPFLAGS="$AM_CPPFLAGS $SAVED_CPPFLAGS"
|
||||
LIBS="$LIBS $JEMALLOC_LIBS"
|
||||
jemalloc_version=`$PKG_CONFIG --modversion jemalloc 2>/dev/null`
|
||||
test "x$jemalloc_version" = x && jemalloc_version=on
|
||||
],
|
||||
AC_MSG_ERROR("jemalloc not found")
|
||||
enable_jemalloc=no
|
||||
)
|
||||
if test "x$enable_jemalloc" = xno; then
|
||||
AM_CPPFLAGS="$SAVED_AM_CPPFLAGS"
|
||||
CPPFLAGS="$SAVED_OLD_CPPFLAGS"
|
||||
LIBS="$SAVED_LIBS"
|
||||
jemalloc_version=off
|
||||
if test "x$require_jemalloc" = xyes; then
|
||||
enable_jemalloc=
|
||||
else
|
||||
AC_MSG_ERROR("jemalloc not found")
|
||||
fi
|
||||
else
|
||||
enable_jemalloc=yes
|
||||
AC_DEFINE(HAVE_JEMALLOC)
|
||||
test "x$jemalloc_version" = xoff && jemalloc_version=on
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check for CMSG_DATA. On some platforms like HP-UX this requires UNIX 95
|
||||
@@ -911,6 +1029,20 @@ case "$host_os" in
|
||||
AC_MSG_NOTICE([])
|
||||
AC_MSG_ERROR([must give --enable-utf8proc or --disable-utf8proc])
|
||||
fi
|
||||
#
|
||||
# macOS calloc(3) does not appear to always zero memory correctly,
|
||||
# so complain and suggest using jemalloc instead.
|
||||
#
|
||||
if test "x$enable_jemalloc" = x; then
|
||||
AC_MSG_NOTICE([])
|
||||
AC_MSG_NOTICE([ macOS calloc(3) appears not to correctly])
|
||||
AC_MSG_NOTICE([ zero allocations in some circumstances;])
|
||||
AC_MSG_NOTICE([ to avoid this, configuring with])
|
||||
AC_MSG_NOTICE([ --enable-jemalloc is recommended. To build])
|
||||
AC_MSG_NOTICE([ without anyway, use --disable-jemalloc])
|
||||
AC_MSG_NOTICE([])
|
||||
AC_MSG_ERROR([must give --enable-jemalloc or --disable-jemalloc])
|
||||
fi
|
||||
;;
|
||||
*dragonfly*)
|
||||
AC_MSG_RESULT(dragonfly)
|
||||
@@ -998,6 +1130,31 @@ AC_MSG_CHECKING(lock-command)
|
||||
AC_MSG_RESULT($DEFAULT_LOCK_CMD)
|
||||
AC_SUBST(DEFAULT_LOCK_CMD)
|
||||
|
||||
# Print a summary.
|
||||
AC_MSG_NOTICE([])
|
||||
if test "x$enable_asan" = xyes; then
|
||||
AC_MSG_NOTICE([ASAN: on])
|
||||
else
|
||||
AC_MSG_NOTICE([ASAN: off])
|
||||
fi
|
||||
if test "x$enable_sixel" = xyes; then
|
||||
AC_MSG_NOTICE([SIXEL: on])
|
||||
else
|
||||
AC_MSG_NOTICE([SIXEL: off])
|
||||
fi
|
||||
if test "x$enable_debug" = xyes; then
|
||||
AC_MSG_NOTICE([debug: on])
|
||||
else
|
||||
AC_MSG_NOTICE([debug: off])
|
||||
fi
|
||||
AC_MSG_NOTICE([jemalloc: $jemalloc_version])
|
||||
AC_MSG_NOTICE([libevent: $libevent_version])
|
||||
AC_MSG_NOTICE([ncurses: $ncurses_version])
|
||||
AC_MSG_NOTICE([systemd: $systemd_version])
|
||||
AC_MSG_NOTICE([utempter: $utempter_version])
|
||||
AC_MSG_NOTICE([utf8proc: $utf8proc_version])
|
||||
AC_MSG_NOTICE([])
|
||||
|
||||
# Save our CFLAGS/CPPFLAGS/LDFLAGS for the Makefile and restore the old user
|
||||
# variables.
|
||||
AC_SUBST(AM_CPPFLAGS)
|
||||
|
||||
282
control-notify.c
282
control-notify.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: control-notify.c,v 1.38 2026/08/03 13:38:42 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -23,137 +23,187 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Should this client be sent events? */
|
||||
#define CONTROL_SHOULD_NOTIFY_CLIENT(c) \
|
||||
((c) != NULL && ((c)->flags & CLIENT_CONTROL))
|
||||
((c) != NULL && \
|
||||
((c)->flags & CLIENT_CONTROL) && \
|
||||
(~(c)->flags & CLIENT_EXIT) && \
|
||||
(c)->control_state != NULL)
|
||||
|
||||
void
|
||||
control_notify_pane_mode_changed(int pane)
|
||||
/* Notify control clients that pane mode changed. */
|
||||
static void
|
||||
control_pane_mode_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
struct client *c;
|
||||
char *value;
|
||||
|
||||
wp = event_payload_get_pane(ep, "pane");
|
||||
if (wp != NULL) {
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
|
||||
control_write(c, "%%pane-mode-changed %%%u", pane);
|
||||
control_notify_write(c, "%%pane-mode-changed %%%u",
|
||||
wp->id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
value = event_payload_print(ep, "pane");
|
||||
if (value == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
control_notify_write(c, "%%pane-mode-changed %s", value);
|
||||
}
|
||||
free(value);
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_window_layout_changed(struct window *w)
|
||||
/* Notify control clients that window layout changed. */
|
||||
static void
|
||||
control_window_layout_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
struct winlink *wl;
|
||||
struct window *w = event_payload_get_window(ep, "window");
|
||||
const char *template;
|
||||
char *cp;
|
||||
|
||||
if (w == NULL)
|
||||
return;
|
||||
|
||||
template = "%layout-change #{window_id} #{window_layout} "
|
||||
"#{window_visible_layout} #{window_raw_flags}";
|
||||
|
||||
/*
|
||||
* When the last pane in a window is closed it won't have a layout root
|
||||
* and we don't need to inform the client about the layout change
|
||||
* because the whole window will go away soon.
|
||||
*/
|
||||
wl = TAILQ_FIRST(&w->winlinks);
|
||||
if (wl == NULL || w->layout_root == NULL)
|
||||
return;
|
||||
cp = format_single(NULL, template, NULL, NULL, wl, NULL);
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
|
||||
continue;
|
||||
s = c->session;
|
||||
|
||||
if (winlink_find_by_window_id(&s->windows, w->id) == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* When the last pane in a window is closed it won't have a
|
||||
* layout root and we don't need to inform the client about the
|
||||
* layout change because the whole window will go away soon.
|
||||
*/
|
||||
if (w->layout_root == NULL)
|
||||
continue;
|
||||
|
||||
wl = winlink_find_by_window(&s->windows, w);
|
||||
if (wl != NULL) {
|
||||
cp = format_single(NULL, template, c, NULL, wl, NULL);
|
||||
control_write(c, "%s", cp);
|
||||
if (winlink_find_by_window_id(&s->windows, w->id) != NULL)
|
||||
control_notify_write(c, "%s", cp);
|
||||
}
|
||||
free(cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_window_pane_changed(struct window *w)
|
||||
/* Notify control clients that window pane changed. */
|
||||
static void
|
||||
control_window_pane_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct window *w = event_payload_get_window(ep, "window");
|
||||
|
||||
if (w == NULL || w->active == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
|
||||
control_write(c, "%%window-pane-changed @%u %%%u", w->id,
|
||||
control_notify_write(c, "%%window-pane-changed @%u %%%u", w->id,
|
||||
w->active->id);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_window_unlinked(__unused struct session *s, struct window *w)
|
||||
/* Notify control clients that a window was unlinked. */
|
||||
static void
|
||||
control_window_unlinked_cb(__unused const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *cs;
|
||||
struct window *w = event_payload_get_window(ep, "window");
|
||||
|
||||
if (w == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
|
||||
continue;
|
||||
cs = c->session;
|
||||
|
||||
if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
|
||||
control_write(c, "%%window-close @%u", w->id);
|
||||
else
|
||||
control_write(c, "%%unlinked-window-close @%u", w->id);
|
||||
control_notify_write(c, "%%window-close @%u", w->id);
|
||||
else {
|
||||
control_notify_write(c, "%%unlinked-window-close @%u",
|
||||
w->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_window_linked(__unused struct session *s, struct window *w)
|
||||
/* Notify control clients that a window was linked. */
|
||||
static void
|
||||
control_window_linked_cb(__unused const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *cs;
|
||||
struct window *w = event_payload_get_window(ep, "window");
|
||||
|
||||
if (w == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
|
||||
continue;
|
||||
cs = c->session;
|
||||
|
||||
if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
|
||||
control_write(c, "%%window-add @%u", w->id);
|
||||
else
|
||||
control_write(c, "%%unlinked-window-add @%u", w->id);
|
||||
control_notify_write(c, "%%window-add @%u", w->id);
|
||||
else {
|
||||
control_notify_write(c, "%%unlinked-window-add @%u",
|
||||
w->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_window_renamed(struct window *w)
|
||||
/* Notify control clients that a window was renamed. */
|
||||
static void
|
||||
control_window_renamed_cb(__unused const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *cs;
|
||||
struct window *w = event_payload_get_window(ep, "window");
|
||||
|
||||
if (w == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
|
||||
continue;
|
||||
cs = c->session;
|
||||
|
||||
if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) {
|
||||
control_write(c, "%%window-renamed @%u %s", w->id,
|
||||
w->name);
|
||||
} else {
|
||||
control_write(c, "%%unlinked-window-renamed @%u %s",
|
||||
control_notify_write(c, "%%window-renamed @%u %s",
|
||||
w->id, w->name);
|
||||
} else {
|
||||
control_notify_write(c,
|
||||
"%%unlinked-window-renamed @%u %s", w->id, w->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_client_session_changed(struct client *cc)
|
||||
/* Notify control clients that a client changed session. */
|
||||
static void
|
||||
control_client_session_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *cc = event_payload_get_client(ep, "client");
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
|
||||
if (cc->session == NULL)
|
||||
if (cc == NULL || cc->session == NULL)
|
||||
return;
|
||||
s = cc->session;
|
||||
|
||||
@@ -162,101 +212,163 @@ control_notify_client_session_changed(struct client *cc)
|
||||
continue;
|
||||
|
||||
if (cc == c) {
|
||||
control_write(c, "%%session-changed $%u %s", s->id,
|
||||
s->name);
|
||||
control_notify_write(c, "%%session-changed $%u %s",
|
||||
s->id, s->name);
|
||||
} else {
|
||||
control_write(c, "%%client-session-changed %s $%u %s",
|
||||
cc->name, s->id, s->name);
|
||||
control_notify_write(c,
|
||||
"%%client-session-changed %s $%u %s", cc->name,
|
||||
s->id, s->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_client_detached(struct client *cc)
|
||||
/* Notify control clients that a client detached. */
|
||||
static void
|
||||
control_client_detached_cb(__unused const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct client *cc = event_payload_get_client(ep, "client");
|
||||
struct client *c;
|
||||
|
||||
if (cc == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
control_write(c, "%%client-detached %s", cc->name);
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
control_notify_write(c, "%%client-detached %s", cc->name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_session_renamed(struct session *s)
|
||||
/* Notify control clients that a session was renamed. */
|
||||
static void
|
||||
control_session_renamed_cb(__unused const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct session *s = event_payload_get_session(ep, "session");
|
||||
struct client *c;
|
||||
|
||||
if (s == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
control_notify_write(c, "%%session-renamed $%u %s", s->id,
|
||||
s->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Notify control clients that sessions changed. */
|
||||
static void
|
||||
control_session_created_cb(__unused const char *name,
|
||||
__unused struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
|
||||
control_write(c, "%%session-renamed $%u %s", s->id, s->name);
|
||||
control_notify_write(c, "%%sessions-changed");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_session_created(__unused struct session *s)
|
||||
/* Notify control clients that sessions changed. */
|
||||
static void
|
||||
control_session_closed_cb(__unused const char *name,
|
||||
__unused struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
|
||||
control_write(c, "%%sessions-changed");
|
||||
control_notify_write(c, "%%sessions-changed");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_session_closed(__unused struct session *s)
|
||||
/* Notify control clients that the current window changed. */
|
||||
static void
|
||||
control_session_window_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct session *s = event_payload_get_session(ep, "session");
|
||||
struct client *c;
|
||||
|
||||
/*
|
||||
* A deferred session-window-changed notification can fire after the
|
||||
* session has been destroyed (which sets curw to NULL) but is kept
|
||||
* alive by the notification's reference. Skip the notification.
|
||||
*/
|
||||
if (s == NULL || s->curw == NULL)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
|
||||
control_write(c, "%%sessions-changed");
|
||||
control_notify_write(c, "%%session-window-changed $%u @%u",
|
||||
s->id, s->curw->window->id);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_session_window_changed(struct session *s)
|
||||
/* Notify control clients that a paste buffer changed. */
|
||||
static void
|
||||
control_paste_buffer_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
const char *pbname = event_payload_get_string(ep, "paste_buffer");
|
||||
struct client *c;
|
||||
|
||||
if (pbname == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
|
||||
control_write(c, "%%session-window-changed $%u @%u", s->id,
|
||||
s->curw->window->id);
|
||||
control_notify_write(c, "%%paste-buffer-changed %s", pbname);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_paste_buffer_changed(const char *name)
|
||||
/* Notify control clients that a paste buffer was deleted. */
|
||||
static void
|
||||
control_paste_buffer_deleted_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
const char *pbname = event_payload_get_string(ep, "paste_buffer");
|
||||
struct client *c;
|
||||
|
||||
if (pbname == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
|
||||
control_write(c, "%%paste-buffer-changed %s", name);
|
||||
control_notify_write(c, "%%paste-buffer-deleted %s", pbname);
|
||||
}
|
||||
}
|
||||
|
||||
/* Build control event sinks. */
|
||||
void
|
||||
control_notify_paste_buffer_deleted(const char *name)
|
||||
control_build_events(void)
|
||||
{
|
||||
struct client *c;
|
||||
/* Control event sink callbacks. */
|
||||
static struct {
|
||||
const char *name;
|
||||
events_cb cb;
|
||||
} events[] = {
|
||||
{ "pane-mode-changed", control_pane_mode_changed_cb },
|
||||
{ "window-layout-changed", control_window_layout_changed_cb },
|
||||
{ "window-pane-changed", control_window_pane_changed_cb },
|
||||
{ "window-unlinked", control_window_unlinked_cb },
|
||||
{ "window-linked", control_window_linked_cb },
|
||||
{ "window-renamed", control_window_renamed_cb },
|
||||
{ "client-session-changed", control_client_session_changed_cb },
|
||||
{ "client-detached", control_client_detached_cb },
|
||||
{ "session-renamed", control_session_renamed_cb },
|
||||
{ "session-created", control_session_created_cb },
|
||||
{ "session-closed", control_session_closed_cb },
|
||||
{ "session-window-changed", control_session_window_changed_cb },
|
||||
{ "paste-buffer-changed", control_paste_buffer_changed_cb },
|
||||
{ "paste-buffer-deleted", control_paste_buffer_deleted_cb }
|
||||
};
|
||||
u_int i;
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
|
||||
control_write(c, "%%paste-buffer-deleted %s", name);
|
||||
}
|
||||
for (i = 0; i < nitems(events); i++)
|
||||
events_add_sink(events[i].name, events[i].cb, NULL);
|
||||
}
|
||||
|
||||
741
control.c
741
control.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: control.c,v 1.66 2026/08/18 07:43:44 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <event.h>
|
||||
#include <poll.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
@@ -50,6 +53,17 @@ struct control_block {
|
||||
TAILQ_ENTRY(control_block) all_entry;
|
||||
};
|
||||
|
||||
/*
|
||||
* A notification line deferred because it was generated while a command's
|
||||
* %begin/%end guard block was open. Notifications must never appear inside a
|
||||
* guard block, so they are held here and flushed once the block closes.
|
||||
*/
|
||||
struct control_line {
|
||||
char *line;
|
||||
|
||||
TAILQ_ENTRY(control_line) entry;
|
||||
};
|
||||
|
||||
/* Control client pane. */
|
||||
struct control_pane {
|
||||
u_int pane;
|
||||
@@ -75,45 +89,20 @@ struct control_pane {
|
||||
};
|
||||
RB_HEAD(control_panes, control_pane);
|
||||
|
||||
/* Subscription pane. */
|
||||
struct control_sub_pane {
|
||||
u_int pane;
|
||||
u_int idx;
|
||||
char *last;
|
||||
|
||||
RB_ENTRY(control_sub_pane) entry;
|
||||
};
|
||||
RB_HEAD(control_sub_panes, control_sub_pane);
|
||||
|
||||
/* Subscription window. */
|
||||
struct control_sub_window {
|
||||
/* Control client window size. */
|
||||
struct control_window {
|
||||
u_int window;
|
||||
u_int idx;
|
||||
char *last;
|
||||
u_int sx;
|
||||
u_int sy;
|
||||
|
||||
RB_ENTRY(control_sub_window) entry;
|
||||
RB_ENTRY(control_window) entry;
|
||||
};
|
||||
RB_HEAD(control_sub_windows, control_sub_window);
|
||||
|
||||
/* Control client subscription. */
|
||||
struct control_sub {
|
||||
char *name;
|
||||
char *format;
|
||||
|
||||
enum control_sub_type type;
|
||||
u_int id;
|
||||
|
||||
char *last;
|
||||
struct control_sub_panes panes;
|
||||
struct control_sub_windows windows;
|
||||
|
||||
RB_ENTRY(control_sub) entry;
|
||||
};
|
||||
RB_HEAD(control_subs, control_sub);
|
||||
RB_HEAD(control_windows, control_window);
|
||||
|
||||
/* Control client state. */
|
||||
struct control_state {
|
||||
struct control_panes panes;
|
||||
struct control_windows windows;
|
||||
|
||||
TAILQ_HEAD(, control_pane) pending_list;
|
||||
u_int pending_count;
|
||||
@@ -123,8 +112,14 @@ struct control_state {
|
||||
struct bufferevent *read_event;
|
||||
struct bufferevent *write_event;
|
||||
|
||||
struct control_subs subs;
|
||||
struct event subs_timer;
|
||||
struct monitor_set *subs;
|
||||
|
||||
/*
|
||||
* Depth of open %begin/%end guard blocks and notifications deferred
|
||||
* until the outermost block closes.
|
||||
*/
|
||||
int guard_depth;
|
||||
TAILQ_HEAD(, control_line) deferred;
|
||||
};
|
||||
|
||||
/* Low and high watermarks. */
|
||||
@@ -154,72 +149,17 @@ control_pane_cmp(struct control_pane *cp1, struct control_pane *cp2)
|
||||
}
|
||||
RB_GENERATE_STATIC(control_panes, control_pane, entry, control_pane_cmp);
|
||||
|
||||
/* Compare client subs. */
|
||||
/* Compare control windows. */
|
||||
static int
|
||||
control_sub_cmp(struct control_sub *csub1, struct control_sub *csub2)
|
||||
control_window_cmp(struct control_window *cw1, struct control_window *cw2)
|
||||
{
|
||||
return (strcmp(csub1->name, csub2->name));
|
||||
}
|
||||
RB_GENERATE_STATIC(control_subs, control_sub, entry, control_sub_cmp);
|
||||
|
||||
/* Compare client subscription panes. */
|
||||
static int
|
||||
control_sub_pane_cmp(struct control_sub_pane *csp1,
|
||||
struct control_sub_pane *csp2)
|
||||
{
|
||||
if (csp1->pane < csp2->pane)
|
||||
if (cw1->window < cw2->window)
|
||||
return (-1);
|
||||
if (csp1->pane > csp2->pane)
|
||||
return (1);
|
||||
if (csp1->idx < csp2->idx)
|
||||
return (-1);
|
||||
if (csp1->idx > csp2->idx)
|
||||
if (cw1->window > cw2->window)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
RB_GENERATE_STATIC(control_sub_panes, control_sub_pane, entry,
|
||||
control_sub_pane_cmp);
|
||||
|
||||
/* Compare client subscription windows. */
|
||||
static int
|
||||
control_sub_window_cmp(struct control_sub_window *csw1,
|
||||
struct control_sub_window *csw2)
|
||||
{
|
||||
if (csw1->window < csw2->window)
|
||||
return (-1);
|
||||
if (csw1->window > csw2->window)
|
||||
return (1);
|
||||
if (csw1->idx < csw2->idx)
|
||||
return (-1);
|
||||
if (csw1->idx > csw2->idx)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
RB_GENERATE_STATIC(control_sub_windows, control_sub_window, entry,
|
||||
control_sub_window_cmp);
|
||||
|
||||
/* Free a subscription. */
|
||||
static void
|
||||
control_free_sub(struct control_state *cs, struct control_sub *csub)
|
||||
{
|
||||
struct control_sub_pane *csp, *csp1;
|
||||
struct control_sub_window *csw, *csw1;
|
||||
|
||||
RB_FOREACH_SAFE(csp, control_sub_panes, &csub->panes, csp1) {
|
||||
RB_REMOVE(control_sub_panes, &csub->panes, csp);
|
||||
free(csp);
|
||||
}
|
||||
RB_FOREACH_SAFE(csw, control_sub_windows, &csub->windows, csw1) {
|
||||
RB_REMOVE(control_sub_windows, &csub->windows, csw);
|
||||
free(csw);
|
||||
}
|
||||
free(csub->last);
|
||||
|
||||
RB_REMOVE(control_subs, &cs->subs, csub);
|
||||
free(csub->name);
|
||||
free(csub->format);
|
||||
free(csub);
|
||||
}
|
||||
RB_GENERATE_STATIC(control_windows, control_window, entry, control_window_cmp);
|
||||
|
||||
/* Free a block. */
|
||||
static void
|
||||
@@ -262,6 +202,66 @@ control_add_pane(struct client *c, struct window_pane *wp)
|
||||
return (cp);
|
||||
}
|
||||
|
||||
/* Get window for this client. */
|
||||
static struct control_window *
|
||||
control_get_window(struct client *c, u_int window)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_window cw = { .window = window };
|
||||
|
||||
if (cs == NULL)
|
||||
return (NULL);
|
||||
return (RB_FIND(control_windows, &cs->windows, &cw));
|
||||
}
|
||||
|
||||
/* Set window size for this client. */
|
||||
void
|
||||
control_set_window_size(struct client *c, u_int window, u_int sx, u_int sy)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_window *cw;
|
||||
|
||||
if (cs == NULL)
|
||||
return;
|
||||
cw = control_get_window(c, window);
|
||||
if (cw == NULL) {
|
||||
cw = xcalloc(1, sizeof *cw);
|
||||
cw->window = window;
|
||||
RB_INSERT(control_windows, &cs->windows, cw);
|
||||
}
|
||||
cw->sx = sx;
|
||||
cw->sy = sy;
|
||||
}
|
||||
|
||||
/* Get window size for this client. */
|
||||
int
|
||||
control_get_window_size(struct client *c, u_int window, u_int *sx, u_int *sy)
|
||||
{
|
||||
struct control_window *cw;
|
||||
|
||||
if ((cw = control_get_window(c, window)) == NULL)
|
||||
return (0);
|
||||
*sx = cw->sx;
|
||||
*sy = cw->sy;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Clear window size for this client. */
|
||||
void
|
||||
control_clear_window_size(struct client *c, u_int window)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_window *cw;
|
||||
|
||||
if (cs == NULL)
|
||||
return;
|
||||
cw = control_get_window(c, window);
|
||||
if (cw != NULL) {
|
||||
RB_REMOVE(control_windows, &cs->windows, cw);
|
||||
free(cw);
|
||||
}
|
||||
}
|
||||
|
||||
/* Discard output for a pane. */
|
||||
static void
|
||||
control_discard_pane(struct client *c, struct control_pane *cp)
|
||||
@@ -298,6 +298,7 @@ control_reset_offsets(struct client *c)
|
||||
struct control_pane *cp, *cp1;
|
||||
|
||||
RB_FOREACH_SAFE(cp, control_panes, &cs->panes, cp1) {
|
||||
control_discard_pane(c, cp);
|
||||
RB_REMOVE(control_panes, &cs->panes, cp);
|
||||
free(cp);
|
||||
}
|
||||
@@ -352,6 +353,9 @@ control_set_pane_off(struct client *c, struct window_pane *wp)
|
||||
struct control_pane *cp;
|
||||
|
||||
cp = control_add_pane(c, wp);
|
||||
control_discard_pane(c, cp);
|
||||
memcpy(&cp->offset, &wp->offset, sizeof cp->offset);
|
||||
memcpy(&cp->queued, &wp->offset, sizeof cp->queued);
|
||||
cp->flags |= CONTROL_PANE_OFF;
|
||||
}
|
||||
|
||||
@@ -366,7 +370,7 @@ control_continue_pane(struct client *c, struct window_pane *wp)
|
||||
cp->flags &= ~CONTROL_PANE_PAUSED;
|
||||
memcpy(&cp->offset, &wp->offset, sizeof cp->offset);
|
||||
memcpy(&cp->queued, &wp->offset, sizeof cp->queued);
|
||||
control_write(c, "%%continue %%%u", wp->id);
|
||||
control_notify_write(c, "%%continue %%%u", wp->id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,52 +384,139 @@ control_pause_pane(struct client *c, struct window_pane *wp)
|
||||
if (~cp->flags & CONTROL_PANE_PAUSED) {
|
||||
cp->flags |= CONTROL_PANE_PAUSED;
|
||||
control_discard_pane(c, cp);
|
||||
control_write(c, "%%pause %%%u", wp->id);
|
||||
control_notify_write(c, "%%pause %%%u", wp->id);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write a line. */
|
||||
static void printflike(2, 0)
|
||||
control_vwrite(struct client *c, const char *fmt, va_list ap)
|
||||
/*
|
||||
* Reset a pane after its buffer has been replaced: drop any output still
|
||||
* queued from the old buffer and start again from the pane's own offset.
|
||||
*/
|
||||
void
|
||||
control_reset_pane(struct client *c, struct window_pane *wp)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
char *s;
|
||||
struct control_pane *cp;
|
||||
|
||||
xvasprintf(&s, fmt, ap);
|
||||
log_debug("%s: %s: writing line: %s", __func__, c->name, s);
|
||||
|
||||
bufferevent_write(cs->write_event, s, strlen(s));
|
||||
bufferevent_write(cs->write_event, "\n", 1);
|
||||
|
||||
bufferevent_enable(cs->write_event, EV_WRITE);
|
||||
free(s);
|
||||
if (c->control_state == NULL)
|
||||
return;
|
||||
cp = control_get_pane(c, wp);
|
||||
if (cp == NULL)
|
||||
return;
|
||||
control_discard_pane(c, cp);
|
||||
memcpy(&cp->offset, &wp->offset, sizeof cp->offset);
|
||||
memcpy(&cp->queued, &wp->offset, sizeof cp->queued);
|
||||
}
|
||||
|
||||
/* Write a line. */
|
||||
void
|
||||
control_write(struct client *c, const char *fmt, ...)
|
||||
/* Write an already-formatted line, queueing it behind %output if needed. */
|
||||
static void
|
||||
control_write_line(struct client *c, char *line)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_block *cb;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
if (TAILQ_EMPTY(&cs->all_blocks)) {
|
||||
control_vwrite(c, fmt, ap);
|
||||
va_end(ap);
|
||||
log_debug("%s: %s: writing line: %s", __func__, c->name, line);
|
||||
bufferevent_write(cs->write_event, line, strlen(line));
|
||||
bufferevent_write(cs->write_event, "\n", 1);
|
||||
bufferevent_enable(cs->write_event, EV_WRITE);
|
||||
free(line);
|
||||
return;
|
||||
}
|
||||
|
||||
cb = xcalloc(1, sizeof *cb);
|
||||
xvasprintf(&cb->line, fmt, ap);
|
||||
cb->line = line;
|
||||
TAILQ_INSERT_TAIL(&cs->all_blocks, cb, all_entry);
|
||||
cb->t = get_timer();
|
||||
|
||||
log_debug("%s: %s: storing line: %s", __func__, c->name, cb->line);
|
||||
bufferevent_enable(cs->write_event, EV_WRITE);
|
||||
}
|
||||
|
||||
/* Flush notifications that were deferred while a guard block was open. */
|
||||
static void
|
||||
control_flush_deferred(struct client *c)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_line *cl, *cl1;
|
||||
|
||||
TAILQ_FOREACH_SAFE(cl, &cs->deferred, entry, cl1) {
|
||||
TAILQ_REMOVE(&cs->deferred, cl, entry);
|
||||
control_write_line(c, cl->line);
|
||||
free(cl);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a line of command output or error text. This is a sink for arbitrary
|
||||
* user-controlled text (command output, capture-pane, error messages), so it
|
||||
* must never try to interpret the content: guard tracking is done only in
|
||||
* control_write_guard.
|
||||
*/
|
||||
void
|
||||
control_write(struct client *c, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *line;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&line, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
control_write_line(c, line);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a %begin, %end or %error guard around a command's output. This is the
|
||||
* only place guard lines are produced, so the block depth is maintained here;
|
||||
* when the outermost block closes any deferred notifications are flushed after
|
||||
* it. "guard" is always one of the fixed strings from cmdq_guard, never user
|
||||
* text.
|
||||
*/
|
||||
void
|
||||
control_write_guard(struct client *c, const char *guard, long t, u_int number,
|
||||
int flags)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
char *line;
|
||||
|
||||
if (strcmp(guard, "begin") == 0)
|
||||
cs->guard_depth++;
|
||||
|
||||
xasprintf(&line, "%%%s %ld %u %d", guard, t, number, flags);
|
||||
control_write_line(c, line);
|
||||
|
||||
if (strcmp(guard, "begin") != 0 && cs->guard_depth > 0 &&
|
||||
--cs->guard_depth == 0)
|
||||
control_flush_deferred(c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a notification line. Notifications must never appear inside a command's
|
||||
* %begin/%end guard block, so if one is open the line is deferred until it
|
||||
* closes.
|
||||
*/
|
||||
void
|
||||
control_notify_write(struct client *c, const char *fmt, ...)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_line *cl;
|
||||
va_list ap;
|
||||
char *line;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&line, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (cs->guard_depth == 0) {
|
||||
control_write_line(c, line);
|
||||
return;
|
||||
}
|
||||
|
||||
log_debug("%s: %s: deferring notification: %s", __func__, c->name,
|
||||
line);
|
||||
cl = xcalloc(1, sizeof *cl);
|
||||
cl->line = line;
|
||||
TAILQ_INSERT_TAIL(&cs->deferred, cl, entry);
|
||||
}
|
||||
|
||||
/* Check age for this pane. */
|
||||
@@ -452,7 +543,7 @@ control_check_age(struct client *c, struct window_pane *wp,
|
||||
return (0);
|
||||
cp->flags |= CONTROL_PANE_PAUSED;
|
||||
control_discard_pane(c, cp);
|
||||
control_write(c, "%%pause %%%u", wp->id);
|
||||
control_notify_write(c, "%%pause %%%u", wp->id);
|
||||
} else {
|
||||
if (age < CONTROL_MAXIMUM_AGE)
|
||||
return (0);
|
||||
@@ -475,7 +566,7 @@ control_write_output(struct client *c, struct window_pane *wp)
|
||||
if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
|
||||
return;
|
||||
|
||||
if (c->flags & CONTROL_IGNORE_FLAGS) {
|
||||
if (c->flags & (CONTROL_IGNORE_FLAGS|CLIENT_EXIT)) {
|
||||
cp = control_get_pane(c, wp);
|
||||
if (cp != NULL)
|
||||
goto ignore;
|
||||
@@ -550,8 +641,9 @@ control_read_callback(__unused struct bufferevent *bufev, void *data)
|
||||
struct control_state *cs = c->control_state;
|
||||
struct evbuffer *buffer = cs->read_event->input;
|
||||
char *line, *error;
|
||||
struct cmd_parse_tree *tree;
|
||||
struct cmdq_item *new_item;
|
||||
struct cmdq_state *state;
|
||||
enum cmd_parse_status status;
|
||||
|
||||
for (;;) {
|
||||
line = evbuffer_readln(buffer, NULL, EVBUFFER_EOL_LF);
|
||||
@@ -565,9 +657,14 @@ control_read_callback(__unused struct bufferevent *bufev, void *data)
|
||||
}
|
||||
|
||||
state = cmdq_new_state(NULL, NULL, CMDQ_STATE_CONTROL);
|
||||
status = cmd_parse_and_append(line, NULL, c, state, &error);
|
||||
if (status == CMD_PARSE_ERROR)
|
||||
tree = cmd_parse_from_string(line, NULL, &error);
|
||||
if (tree == NULL)
|
||||
cmdq_append(c, cmdq_get_callback(control_error, error));
|
||||
else {
|
||||
new_item = cmd_invoke_get(tree, state, NULL);
|
||||
cmdq_append(c, new_item);
|
||||
cmd_parse_free(tree);
|
||||
}
|
||||
cmdq_free_state(state);
|
||||
|
||||
free(line);
|
||||
@@ -585,6 +682,53 @@ control_all_done(struct client *c)
|
||||
return (EVBUFFER_LENGTH(cs->write_event->output) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for the terminal to send an empty line or close, used by a control
|
||||
* client after printing %exit so a wrapping terminal (such as iTerm2) can
|
||||
* finish reading.
|
||||
*/
|
||||
void
|
||||
control_wait_exit(int fd)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
struct evbuffer *evb;
|
||||
char *line;
|
||||
int n;
|
||||
|
||||
evb = evbuffer_new();
|
||||
if (evb == NULL)
|
||||
fatalx("out of memory");
|
||||
|
||||
for (;;) {
|
||||
line = evbuffer_readln(evb, NULL, EVBUFFER_EOL_LF);
|
||||
if (line != NULL) {
|
||||
if (*line == '\0') { /* empty line, stop */
|
||||
free(line);
|
||||
break;
|
||||
}
|
||||
free(line);
|
||||
continue; /* drain buffered lines first */
|
||||
}
|
||||
|
||||
memset(&pfd, 0, sizeof pfd);
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLIN;
|
||||
if (poll(&pfd, 1, INFTIM) == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
n = evbuffer_read(evb, fd, -1);
|
||||
if (n == 0)
|
||||
break;
|
||||
if (n == -1 && errno != EAGAIN && errno != EINTR)
|
||||
break;
|
||||
}
|
||||
|
||||
evbuffer_free(evb);
|
||||
}
|
||||
|
||||
/* Flush all blocks until output. */
|
||||
static void
|
||||
control_flush_all_blocks(struct client *c)
|
||||
@@ -610,7 +754,7 @@ control_append_data(struct client *c, struct control_pane *cp, uint64_t age,
|
||||
struct evbuffer *message, struct window_pane *wp, size_t size)
|
||||
{
|
||||
u_char *new_data;
|
||||
size_t new_size;
|
||||
size_t new_size, start;
|
||||
u_int i;
|
||||
|
||||
if (message == NULL) {
|
||||
@@ -629,10 +773,16 @@ control_append_data(struct client *c, struct control_pane *cp, uint64_t age,
|
||||
if (new_size < size)
|
||||
fatalx("not enough data: %zu < %zu", new_size, size);
|
||||
for (i = 0; i < size; i++) {
|
||||
if (new_data[i] < ' ' || new_data[i] == '\\')
|
||||
if (new_data[i] < ' ' || new_data[i] == '\\') {
|
||||
evbuffer_add_printf(message, "\\%03o", new_data[i]);
|
||||
else
|
||||
evbuffer_add_printf(message, "%c", new_data[i]);
|
||||
} else {
|
||||
start = i;
|
||||
while (i + 1 < size &&
|
||||
new_data[i + 1] >= ' ' &&
|
||||
new_data[i + 1] != '\\')
|
||||
i++;
|
||||
evbuffer_add(message, new_data + start, i - start + 1);
|
||||
}
|
||||
}
|
||||
window_pane_update_used_data(wp, &cp->offset, size);
|
||||
return (message);
|
||||
@@ -754,6 +904,33 @@ control_write_callback(__unused struct bufferevent *bufev, void *data)
|
||||
bufferevent_disable(cs->write_event, EV_WRITE);
|
||||
}
|
||||
|
||||
/* Write a subscription change. */
|
||||
static void
|
||||
control_sub_change(struct monitor_change *change, __unused void *data)
|
||||
{
|
||||
struct client *c = change->c;
|
||||
struct session *s = change->s;
|
||||
struct winlink *wl = change->wl;
|
||||
struct window_pane *wp = change->wp;
|
||||
struct window *w;
|
||||
|
||||
if (wp != NULL) {
|
||||
w = wp->window;
|
||||
control_notify_write(c,
|
||||
"%%subscription-changed %s $%u @%u %u %%%u : %s",
|
||||
change->name, s->id, w->id, wl->idx, wp->id, change->value);
|
||||
} else if (wl != NULL) {
|
||||
w = wl->window;
|
||||
control_notify_write(c,
|
||||
"%%subscription-changed %s $%u @%u %u - : %s",
|
||||
change->name, s->id, w->id, wl->idx, change->value);
|
||||
} else {
|
||||
control_notify_write(c,
|
||||
"%%subscription-changed %s $%u - - - : %s",
|
||||
change->name, s->id, change->value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize for control mode. */
|
||||
void
|
||||
control_start(struct client *c)
|
||||
@@ -769,9 +946,11 @@ control_start(struct client *c)
|
||||
|
||||
cs = c->control_state = xcalloc(1, sizeof *cs);
|
||||
RB_INIT(&cs->panes);
|
||||
RB_INIT(&cs->windows);
|
||||
TAILQ_INIT(&cs->pending_list);
|
||||
TAILQ_INIT(&cs->all_blocks);
|
||||
RB_INIT(&cs->subs);
|
||||
TAILQ_INIT(&cs->deferred);
|
||||
cs->subs = monitor_create_client(c, control_sub_change, NULL);
|
||||
|
||||
cs->read_event = bufferevent_new(c->fd, control_read_callback,
|
||||
control_write_callback, control_error_callback, c);
|
||||
@@ -814,292 +993,63 @@ control_discard(struct client *c)
|
||||
bufferevent_disable(cs->read_event, EV_READ);
|
||||
}
|
||||
|
||||
/* Discard all tmux-owned queued control blocks and stop writing. */
|
||||
void
|
||||
control_discard_all(struct client *c)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_block *cb, *cb1;
|
||||
|
||||
control_discard(c);
|
||||
TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1)
|
||||
control_free_block(cs, cb);
|
||||
bufferevent_disable(cs->write_event, EV_WRITE);
|
||||
}
|
||||
|
||||
/* Stop control mode. */
|
||||
void
|
||||
control_stop(struct client *c)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_block *cb, *cb1;
|
||||
struct control_sub *csub, *csub1;
|
||||
struct control_window *cw, *cw1;
|
||||
struct control_line *cl, *cl1;
|
||||
|
||||
if (cs == NULL)
|
||||
return;
|
||||
|
||||
monitor_destroy(cs->subs);
|
||||
|
||||
TAILQ_FOREACH_SAFE(cl, &cs->deferred, entry, cl1) {
|
||||
TAILQ_REMOVE(&cs->deferred, cl, entry);
|
||||
free(cl->line);
|
||||
free(cl);
|
||||
}
|
||||
|
||||
if (~c->flags & CLIENT_CONTROLCONTROL)
|
||||
bufferevent_free(cs->write_event);
|
||||
bufferevent_free(cs->read_event);
|
||||
|
||||
RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1)
|
||||
control_free_sub(cs, csub);
|
||||
if (evtimer_initialized(&cs->subs_timer))
|
||||
evtimer_del(&cs->subs_timer);
|
||||
|
||||
control_reset_offsets(c);
|
||||
RB_FOREACH_SAFE(cw, control_windows, &cs->windows, cw1) {
|
||||
RB_REMOVE(control_windows, &cs->windows, cw);
|
||||
free(cw);
|
||||
}
|
||||
TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1)
|
||||
control_free_block(cs, cb);
|
||||
control_reset_offsets(c);
|
||||
|
||||
c->control_state = NULL;
|
||||
free(cs);
|
||||
}
|
||||
|
||||
/* Check session subscription. */
|
||||
static void
|
||||
control_check_subs_session(struct client *c, struct control_sub *csub)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct format_tree *ft;
|
||||
char *value;
|
||||
|
||||
ft = format_create_defaults(NULL, c, s, NULL, NULL);
|
||||
value = format_expand(ft, csub->format);
|
||||
format_free(ft);
|
||||
|
||||
if (csub->last != NULL && strcmp(value, csub->last) == 0) {
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
control_write(c,
|
||||
"%%subscription-changed %s $%u - - - : %s",
|
||||
csub->name, s->id, value);
|
||||
free(csub->last);
|
||||
csub->last = value;
|
||||
}
|
||||
|
||||
/* Check pane subscription. */
|
||||
static void
|
||||
control_check_subs_pane(struct client *c, struct control_sub *csub)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct window_pane *wp;
|
||||
struct window *w;
|
||||
struct winlink *wl;
|
||||
struct format_tree *ft;
|
||||
char *value;
|
||||
struct control_sub_pane *csp, find;
|
||||
|
||||
wp = window_pane_find_by_id(csub->id);
|
||||
if (wp == NULL || wp->fd == -1)
|
||||
return;
|
||||
w = wp->window;
|
||||
|
||||
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
|
||||
if (wl->session != s)
|
||||
continue;
|
||||
|
||||
ft = format_create_defaults(NULL, c, s, wl, wp);
|
||||
value = format_expand(ft, csub->format);
|
||||
format_free(ft);
|
||||
|
||||
find.pane = wp->id;
|
||||
find.idx = wl->idx;
|
||||
|
||||
csp = RB_FIND(control_sub_panes, &csub->panes, &find);
|
||||
if (csp == NULL) {
|
||||
csp = xcalloc(1, sizeof *csp);
|
||||
csp->pane = wp->id;
|
||||
csp->idx = wl->idx;
|
||||
RB_INSERT(control_sub_panes, &csub->panes, csp);
|
||||
}
|
||||
|
||||
if (csp->last != NULL && strcmp(value, csp->last) == 0) {
|
||||
free(value);
|
||||
continue;
|
||||
}
|
||||
control_write(c,
|
||||
"%%subscription-changed %s $%u @%u %u %%%u : %s",
|
||||
csub->name, s->id, w->id, wl->idx, wp->id, value);
|
||||
free(csp->last);
|
||||
csp->last = value;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check all panes subscription. */
|
||||
static void
|
||||
control_check_subs_all_panes(struct client *c, struct control_sub *csub)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct window_pane *wp;
|
||||
struct window *w;
|
||||
struct winlink *wl;
|
||||
struct format_tree *ft;
|
||||
char *value;
|
||||
struct control_sub_pane *csp, find;
|
||||
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
w = wl->window;
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
ft = format_create_defaults(NULL, c, s, wl, wp);
|
||||
value = format_expand(ft, csub->format);
|
||||
format_free(ft);
|
||||
|
||||
find.pane = wp->id;
|
||||
find.idx = wl->idx;
|
||||
|
||||
csp = RB_FIND(control_sub_panes, &csub->panes, &find);
|
||||
if (csp == NULL) {
|
||||
csp = xcalloc(1, sizeof *csp);
|
||||
csp->pane = wp->id;
|
||||
csp->idx = wl->idx;
|
||||
RB_INSERT(control_sub_panes, &csub->panes, csp);
|
||||
}
|
||||
|
||||
if (csp->last != NULL &&
|
||||
strcmp(value, csp->last) == 0) {
|
||||
free(value);
|
||||
continue;
|
||||
}
|
||||
control_write(c,
|
||||
"%%subscription-changed %s $%u @%u %u %%%u : %s",
|
||||
csub->name, s->id, w->id, wl->idx, wp->id, value);
|
||||
free(csp->last);
|
||||
csp->last = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check window subscription. */
|
||||
static void
|
||||
control_check_subs_window(struct client *c, struct control_sub *csub)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct window *w;
|
||||
struct winlink *wl;
|
||||
struct format_tree *ft;
|
||||
char *value;
|
||||
struct control_sub_window *csw, find;
|
||||
|
||||
w = window_find_by_id(csub->id);
|
||||
if (w == NULL)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
|
||||
if (wl->session != s)
|
||||
continue;
|
||||
|
||||
ft = format_create_defaults(NULL, c, s, wl, NULL);
|
||||
value = format_expand(ft, csub->format);
|
||||
format_free(ft);
|
||||
|
||||
find.window = w->id;
|
||||
find.idx = wl->idx;
|
||||
|
||||
csw = RB_FIND(control_sub_windows, &csub->windows, &find);
|
||||
if (csw == NULL) {
|
||||
csw = xcalloc(1, sizeof *csw);
|
||||
csw->window = w->id;
|
||||
csw->idx = wl->idx;
|
||||
RB_INSERT(control_sub_windows, &csub->windows, csw);
|
||||
}
|
||||
|
||||
if (csw->last != NULL && strcmp(value, csw->last) == 0) {
|
||||
free(value);
|
||||
continue;
|
||||
}
|
||||
control_write(c,
|
||||
"%%subscription-changed %s $%u @%u %u - : %s",
|
||||
csub->name, s->id, w->id, wl->idx, value);
|
||||
free(csw->last);
|
||||
csw->last = value;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check all windows subscription. */
|
||||
static void
|
||||
control_check_subs_all_windows(struct client *c, struct control_sub *csub)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct window *w;
|
||||
struct winlink *wl;
|
||||
struct format_tree *ft;
|
||||
char *value;
|
||||
struct control_sub_window *csw, find;
|
||||
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
w = wl->window;
|
||||
|
||||
ft = format_create_defaults(NULL, c, s, wl, NULL);
|
||||
value = format_expand(ft, csub->format);
|
||||
format_free(ft);
|
||||
|
||||
find.window = w->id;
|
||||
find.idx = wl->idx;
|
||||
|
||||
csw = RB_FIND(control_sub_windows, &csub->windows, &find);
|
||||
if (csw == NULL) {
|
||||
csw = xcalloc(1, sizeof *csw);
|
||||
csw->window = w->id;
|
||||
csw->idx = wl->idx;
|
||||
RB_INSERT(control_sub_windows, &csub->windows, csw);
|
||||
}
|
||||
|
||||
if (csw->last != NULL && strcmp(value, csw->last) == 0) {
|
||||
free(value);
|
||||
continue;
|
||||
}
|
||||
control_write(c,
|
||||
"%%subscription-changed %s $%u @%u %u - : %s",
|
||||
csub->name, s->id, w->id, wl->idx, value);
|
||||
free(csw->last);
|
||||
csw->last = value;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check subscriptions timer. */
|
||||
static void
|
||||
control_check_subs_timer(__unused int fd, __unused short events, void *data)
|
||||
{
|
||||
struct client *c = data;
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_sub *csub, *csub1;
|
||||
struct timeval tv = { .tv_sec = 1 };
|
||||
|
||||
log_debug("%s: timer fired", __func__);
|
||||
evtimer_add(&cs->subs_timer, &tv);
|
||||
|
||||
RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) {
|
||||
switch (csub->type) {
|
||||
case CONTROL_SUB_SESSION:
|
||||
control_check_subs_session(c, csub);
|
||||
break;
|
||||
case CONTROL_SUB_PANE:
|
||||
control_check_subs_pane(c, csub);
|
||||
break;
|
||||
case CONTROL_SUB_ALL_PANES:
|
||||
control_check_subs_all_panes(c, csub);
|
||||
break;
|
||||
case CONTROL_SUB_WINDOW:
|
||||
control_check_subs_window(c, csub);
|
||||
break;
|
||||
case CONTROL_SUB_ALL_WINDOWS:
|
||||
control_check_subs_all_windows(c, csub);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a subscription. */
|
||||
void
|
||||
control_add_sub(struct client *c, const char *name, enum control_sub_type type,
|
||||
control_add_sub(struct client *c, const char *name, enum monitor_type type,
|
||||
int id, const char *format)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_sub *csub, find;
|
||||
struct timeval tv = { .tv_sec = 1 };
|
||||
|
||||
find.name = (char *)name;
|
||||
if ((csub = RB_FIND(control_subs, &cs->subs, &find)) != NULL)
|
||||
control_free_sub(cs, csub);
|
||||
|
||||
csub = xcalloc(1, sizeof *csub);
|
||||
csub->name = xstrdup(name);
|
||||
csub->type = type;
|
||||
csub->id = id;
|
||||
csub->format = xstrdup(format);
|
||||
RB_INSERT(control_subs, &cs->subs, csub);
|
||||
|
||||
RB_INIT(&csub->panes);
|
||||
RB_INIT(&csub->windows);
|
||||
|
||||
if (!evtimer_initialized(&cs->subs_timer))
|
||||
evtimer_set(&cs->subs_timer, control_check_subs_timer, c);
|
||||
if (!evtimer_pending(&cs->subs_timer, NULL))
|
||||
evtimer_add(&cs->subs_timer, &tv);
|
||||
monitor_add(cs->subs, name, type, id, format, MONITOR_NOTIFY_INITIAL);
|
||||
}
|
||||
|
||||
/* Remove a subscription. */
|
||||
@@ -1107,11 +1057,6 @@ void
|
||||
control_remove_sub(struct client *c, const char *name)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_sub *csub, find;
|
||||
|
||||
find.name = (char *)name;
|
||||
if ((csub = RB_FIND(control_subs, &cs->subs, &find)) != NULL)
|
||||
control_free_sub(cs, csub);
|
||||
if (RB_EMPTY(&cs->subs))
|
||||
evtimer_del(&cs->subs_timer);
|
||||
monitor_remove(cs->subs, name);
|
||||
}
|
||||
|
||||
13
environ.c
13
environ.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: environ.c,v 1.31 2026/06/13 20:07:30 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -57,6 +57,9 @@ environ_free(struct environ *env)
|
||||
{
|
||||
struct environ_entry *envent, *envent1;
|
||||
|
||||
if (env == NULL)
|
||||
return;
|
||||
|
||||
RB_FOREACH_SAFE(envent, environ, env, envent1) {
|
||||
RB_REMOVE(environ, env, envent);
|
||||
free(envent->name);
|
||||
@@ -149,7 +152,8 @@ environ_clear(struct environ *env, const char *name)
|
||||
void
|
||||
environ_put(struct environ *env, const char *var, int flags)
|
||||
{
|
||||
char *name, *value;
|
||||
char *name;
|
||||
const char *value;
|
||||
|
||||
value = strchr(var, '=');
|
||||
if (value == NULL)
|
||||
@@ -263,11 +267,6 @@ environ_for_session(struct session *s, int no_TERM)
|
||||
environ_set(env, "TERM_PROGRAM", 0, "%s", "tmux");
|
||||
environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion());
|
||||
environ_set(env, "COLORTERM", 0, "truecolor");
|
||||
} else {
|
||||
environ_unset(env, "TERM");
|
||||
environ_unset(env, "TERM_PROGRAM");
|
||||
environ_unset(env, "TERM_PROGRAM_VERSION");
|
||||
environ_unset(env, "COLORTERM");
|
||||
}
|
||||
|
||||
#ifdef HAVE_SYSTEMD
|
||||
|
||||
672
events-payload.c
Normal file
672
events-payload.c
Normal file
@@ -0,0 +1,672 @@
|
||||
/* $OpenBSD: events-payload.c,v 1.1 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <event.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Event payload item. */
|
||||
struct event_payload_item {
|
||||
char *name;
|
||||
enum event_payload_type type;
|
||||
|
||||
union {
|
||||
char *string;
|
||||
time_t time;
|
||||
int number;
|
||||
u_int unsigned_number;
|
||||
struct client *client;
|
||||
struct session *session;
|
||||
struct window *window;
|
||||
struct window_pane *pane;
|
||||
struct {
|
||||
void *ptr;
|
||||
event_payload_free_cb free_cb;
|
||||
event_payload_print_cb print_cb;
|
||||
} pointer;
|
||||
};
|
||||
|
||||
RB_ENTRY(event_payload_item) entry;
|
||||
};
|
||||
|
||||
RB_HEAD(event_payload_tree, event_payload_item);
|
||||
|
||||
struct event_payload {
|
||||
struct event_payload_tree items;
|
||||
struct cmd_find_state target;
|
||||
};
|
||||
|
||||
static int
|
||||
event_payload_cmp(struct event_payload_item *epi1,
|
||||
struct event_payload_item *epi2)
|
||||
{
|
||||
return (strcmp(epi1->name, epi2->name));
|
||||
}
|
||||
RB_GENERATE_STATIC(event_payload_tree, event_payload_item, entry,
|
||||
event_payload_cmp);
|
||||
|
||||
/* Find an item. */
|
||||
static struct event_payload_item *
|
||||
event_payload_find(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item find = { .name = (char *)name };
|
||||
|
||||
return (RB_FIND(event_payload_tree, &ep->items, &find));
|
||||
}
|
||||
|
||||
/* Free the target in a payload. */
|
||||
static void
|
||||
event_payload_free_target(struct event_payload *ep)
|
||||
{
|
||||
struct cmd_find_state *target = &ep->target;
|
||||
|
||||
if (target->s != NULL)
|
||||
session_remove_ref(target->s, __func__);
|
||||
if (target->w != NULL)
|
||||
window_remove_ref(target->w, __func__);
|
||||
if (target->wp != NULL)
|
||||
window_pane_remove_ref(target->wp, __func__);
|
||||
|
||||
cmd_find_clear_state(target, 0);
|
||||
}
|
||||
|
||||
/* Free the value in an item. */
|
||||
static void
|
||||
event_payload_free_value(struct event_payload_item *epi)
|
||||
{
|
||||
switch (epi->type) {
|
||||
case EVENT_PAYLOAD_STRING:
|
||||
free(epi->string);
|
||||
break;
|
||||
case EVENT_PAYLOAD_CLIENT:
|
||||
server_client_unref(epi->client);
|
||||
break;
|
||||
case EVENT_PAYLOAD_SESSION:
|
||||
session_remove_ref(epi->session, __func__);
|
||||
break;
|
||||
case EVENT_PAYLOAD_WINDOW:
|
||||
window_remove_ref(epi->window, __func__);
|
||||
break;
|
||||
case EVENT_PAYLOAD_PANE:
|
||||
window_pane_remove_ref(epi->pane, __func__);
|
||||
break;
|
||||
case EVENT_PAYLOAD_POINTER:
|
||||
if (epi->pointer.free_cb != NULL)
|
||||
epi->pointer.free_cb(epi->pointer.ptr);
|
||||
break;
|
||||
case EVENT_PAYLOAD_INT:
|
||||
case EVENT_PAYLOAD_UINT:
|
||||
case EVENT_PAYLOAD_TIME:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set an item. */
|
||||
static void
|
||||
event_payload_set_item(struct event_payload *ep, const char *name,
|
||||
struct event_payload_item *new)
|
||||
{
|
||||
struct event_payload_item *old;
|
||||
|
||||
new->name = xstrdup(name);
|
||||
old = RB_INSERT(event_payload_tree, &ep->items, new);
|
||||
if (old != NULL) {
|
||||
RB_REMOVE(event_payload_tree, &ep->items, old);
|
||||
event_payload_free_value(old);
|
||||
free(old->name);
|
||||
free(old);
|
||||
RB_INSERT(event_payload_tree, &ep->items, new);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create an event payload. */
|
||||
struct event_payload *
|
||||
event_payload_create(void)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
|
||||
ep = xcalloc(1, sizeof *ep);
|
||||
RB_INIT(&ep->items);
|
||||
cmd_find_clear_state(&ep->target, 0);
|
||||
return (ep);
|
||||
}
|
||||
|
||||
/* Free an event payload. */
|
||||
void
|
||||
event_payload_free(struct event_payload *ep)
|
||||
{
|
||||
struct event_payload_item *epi, *epi1;
|
||||
|
||||
if (ep != NULL) {
|
||||
RB_FOREACH_SAFE(epi, event_payload_tree, &ep->items, epi1) {
|
||||
RB_REMOVE(event_payload_tree, &ep->items, epi);
|
||||
event_payload_free_value(epi);
|
||||
free(epi->name);
|
||||
free(epi);
|
||||
}
|
||||
event_payload_free_target(ep);
|
||||
free(ep);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the target. */
|
||||
void
|
||||
event_payload_set_target(struct event_payload *ep, struct cmd_find_state *fs)
|
||||
{
|
||||
struct cmd_find_state *target = &ep->target;
|
||||
|
||||
event_payload_free_target(ep);
|
||||
|
||||
if (fs->s != NULL) {
|
||||
session_add_ref(fs->s, __func__);
|
||||
target->s = fs->s;
|
||||
}
|
||||
if (fs->wl != NULL) {
|
||||
target->idx = fs->wl->idx;
|
||||
if (target->s == NULL) {
|
||||
session_add_ref(fs->wl->session, __func__);
|
||||
target->s = fs->wl->session;
|
||||
}
|
||||
} else
|
||||
target->idx = -1;
|
||||
if (fs->w != NULL) {
|
||||
window_add_ref(fs->w, __func__);
|
||||
target->w = fs->w;
|
||||
} else if (fs->wl != NULL) {
|
||||
window_add_ref(fs->wl->window, __func__);
|
||||
target->w = fs->wl->window;
|
||||
}
|
||||
if (fs->wp != NULL) {
|
||||
window_pane_add_ref(fs->wp, __func__);
|
||||
target->wp = fs->wp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the target. */
|
||||
int
|
||||
event_payload_get_target(struct event_payload *ep, struct cmd_find_state *fs)
|
||||
{
|
||||
struct cmd_find_state *t = &ep->target;
|
||||
struct winlink *wl = NULL;
|
||||
int flags = fs->flags;
|
||||
|
||||
if (t->idx != -1 &&
|
||||
t->s != NULL &&
|
||||
t->w != NULL &&
|
||||
session_alive(t->s)) {
|
||||
wl = winlink_find_by_index(&t->s->windows, t->idx);
|
||||
if (wl != NULL && wl->window != t->w)
|
||||
wl = NULL;
|
||||
}
|
||||
|
||||
cmd_find_clear_state(fs, flags);
|
||||
fs->s = t->s;
|
||||
fs->w = t->w;
|
||||
fs->wp = t->wp;
|
||||
fs->wl = wl;
|
||||
fs->idx = (wl != NULL ? wl->idx : -1);
|
||||
if (cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
|
||||
if (wl != NULL &&
|
||||
t->wp != NULL &&
|
||||
window_has_pane(wl->window, t->wp)) {
|
||||
cmd_find_from_winlink_pane(fs, wl, t->wp, flags);
|
||||
if (cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (t->wp != NULL &&
|
||||
cmd_find_from_pane(fs, t->wp, flags) == 0 &&
|
||||
cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
|
||||
if (wl != NULL) {
|
||||
cmd_find_from_winlink(fs, wl, flags);
|
||||
if (cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (t->s != NULL &&
|
||||
t->w != NULL &&
|
||||
session_alive(t->s) &&
|
||||
cmd_find_from_session_window(fs, t->s, t->w, flags) == 0 &&
|
||||
cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
|
||||
if (t->s != NULL && session_alive(t->s)) {
|
||||
cmd_find_from_session(fs, t->s, flags);
|
||||
if (cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (cmd_find_from_nothing(fs, flags) == 0)
|
||||
return (1);
|
||||
|
||||
cmd_find_clear_state(fs, flags);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Set a string item. */
|
||||
void
|
||||
event_payload_set_string(struct event_payload *ep, const char *name,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_STRING;
|
||||
xvasprintf(&epi->string, fmt, ap);
|
||||
event_payload_set_item(ep, name, epi);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* Set a time item. */
|
||||
void
|
||||
event_payload_set_time(struct event_payload *ep, const char *name,
|
||||
time_t value)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_TIME;
|
||||
epi->time = value;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a number item. */
|
||||
void
|
||||
event_payload_set_int(struct event_payload *ep, const char *name, int value)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_INT;
|
||||
epi->number = value;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set an unsigned number item. */
|
||||
void
|
||||
event_payload_set_uint(struct event_payload *ep, const char *name, u_int value)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_UINT;
|
||||
epi->unsigned_number = value;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a client item. */
|
||||
void
|
||||
event_payload_set_client(struct event_payload *ep, const char *name,
|
||||
struct client *c)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
c->references++;
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_CLIENT;
|
||||
epi->client = c;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a session item. */
|
||||
void
|
||||
event_payload_set_session(struct event_payload *ep, const char *name,
|
||||
struct session *s)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
session_add_ref(s, __func__);
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_SESSION;
|
||||
epi->session = s;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a window item. */
|
||||
void
|
||||
event_payload_set_window(struct event_payload *ep, const char *name,
|
||||
struct window *w)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
window_add_ref(w, __func__);
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_WINDOW;
|
||||
epi->window = w;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a pane item. */
|
||||
void
|
||||
event_payload_set_pane(struct event_payload *ep, const char *name,
|
||||
struct window_pane *wp)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
window_pane_add_ref(wp, __func__);
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_PANE;
|
||||
epi->pane = wp;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a pointer item. */
|
||||
void
|
||||
event_payload_set_pointer(struct event_payload *ep, const char *name,
|
||||
void *ptr, event_payload_free_cb free_cb, event_payload_print_cb print_cb)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_POINTER;
|
||||
epi->pointer.ptr = ptr;
|
||||
epi->pointer.free_cb = free_cb;
|
||||
epi->pointer.print_cb = print_cb;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Get a string item. */
|
||||
const char *
|
||||
event_payload_get_string(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_STRING)
|
||||
return (NULL);
|
||||
return (epi->string);
|
||||
}
|
||||
|
||||
/* Print a payload item. */
|
||||
static void
|
||||
event_payload_add_item(struct event_payload_item *epi, struct evbuffer *evb)
|
||||
{
|
||||
switch (epi->type) {
|
||||
case EVENT_PAYLOAD_STRING:
|
||||
evbuffer_add_printf(evb, "%s", epi->string);
|
||||
break;
|
||||
case EVENT_PAYLOAD_TIME:
|
||||
evbuffer_add_printf(evb, "%lld", (long long)epi->time);
|
||||
break;
|
||||
case EVENT_PAYLOAD_INT:
|
||||
evbuffer_add_printf(evb, "%d", epi->number);
|
||||
break;
|
||||
case EVENT_PAYLOAD_UINT:
|
||||
evbuffer_add_printf(evb, "%u", epi->unsigned_number);
|
||||
break;
|
||||
case EVENT_PAYLOAD_CLIENT:
|
||||
evbuffer_add_printf(evb, "%s", epi->client->name);
|
||||
break;
|
||||
case EVENT_PAYLOAD_SESSION:
|
||||
evbuffer_add_printf(evb, "$%u", epi->session->id);
|
||||
break;
|
||||
case EVENT_PAYLOAD_WINDOW:
|
||||
evbuffer_add_printf(evb, "@%u", epi->window->id);
|
||||
break;
|
||||
case EVENT_PAYLOAD_PANE:
|
||||
evbuffer_add_printf(evb, "%%%u", epi->pane->id);
|
||||
break;
|
||||
case EVENT_PAYLOAD_POINTER:
|
||||
if (epi->pointer.print_cb != NULL)
|
||||
epi->pointer.print_cb(epi->pointer.ptr, evb);
|
||||
else
|
||||
evbuffer_add_printf(evb, "%p", epi->pointer.ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print a payload item. */
|
||||
char *
|
||||
event_payload_item_print(struct event_payload_item *epi)
|
||||
{
|
||||
struct evbuffer *evb;
|
||||
char *value = NULL;
|
||||
size_t size;
|
||||
|
||||
evb = evbuffer_new();
|
||||
if (evb == NULL)
|
||||
fatalx("out of memory");
|
||||
event_payload_add_item(epi, evb);
|
||||
if ((size = EVBUFFER_LENGTH(evb)) != 0)
|
||||
value = xmemdup(EVBUFFER_DATA(evb), size);
|
||||
else
|
||||
value = xstrdup("");
|
||||
evbuffer_free(evb);
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* Print an item value. */
|
||||
char *
|
||||
event_payload_print(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL)
|
||||
return (NULL);
|
||||
return (event_payload_item_print(epi));
|
||||
}
|
||||
|
||||
/* Add payload items as formats. */
|
||||
void
|
||||
event_payload_add_formats(struct event_payload *ep, struct format_tree *ft,
|
||||
const char *prefix)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
char *name, *value;
|
||||
const char *key;
|
||||
|
||||
if (prefix == NULL)
|
||||
prefix = "";
|
||||
|
||||
RB_FOREACH(epi, event_payload_tree, &ep->items) {
|
||||
key = epi->name;
|
||||
if (*key == '_')
|
||||
continue;
|
||||
|
||||
value = event_payload_item_print(epi);
|
||||
xasprintf(&name, "%s%s", prefix, key);
|
||||
format_add(ft, name, "%s", value);
|
||||
free(name);
|
||||
free(value);
|
||||
|
||||
if (epi->type == EVENT_PAYLOAD_SESSION) {
|
||||
xasprintf(&name, "%s%s_name", prefix, key);
|
||||
format_add(ft, name, "%s", epi->session->name);
|
||||
free(name);
|
||||
} else if (epi->type == EVENT_PAYLOAD_WINDOW) {
|
||||
xasprintf(&name, "%s%s_name", prefix, key);
|
||||
format_add(ft, name, "%s", epi->window->name);
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the first payload item. */
|
||||
struct event_payload_item *
|
||||
event_payload_first(struct event_payload *ep)
|
||||
{
|
||||
return (RB_MIN(event_payload_tree, &ep->items));
|
||||
}
|
||||
|
||||
/* Get the next payload item. */
|
||||
struct event_payload_item *
|
||||
event_payload_next(struct event_payload_item *epi)
|
||||
{
|
||||
return (RB_NEXT(event_payload_tree, , epi));
|
||||
}
|
||||
|
||||
/* Get a payload item name. */
|
||||
const char *
|
||||
event_payload_item_name(struct event_payload_item *epi)
|
||||
{
|
||||
return (epi->name);
|
||||
}
|
||||
|
||||
/* Get a payload item type. */
|
||||
enum event_payload_type
|
||||
event_payload_item_type(struct event_payload_item *epi)
|
||||
{
|
||||
return (epi->type);
|
||||
}
|
||||
|
||||
/* Log a payload. */
|
||||
void
|
||||
event_payload_log(struct event_payload *ep, const char *fmt, ...)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
struct evbuffer *evb;
|
||||
va_list ap;
|
||||
char *prefix;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&prefix, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
evb = evbuffer_new();
|
||||
if (evb == NULL)
|
||||
fatalx("out of memory");
|
||||
if (ep != NULL) {
|
||||
RB_FOREACH(epi, event_payload_tree, &ep->items) {
|
||||
if (EVBUFFER_LENGTH(evb) != 0)
|
||||
evbuffer_add_printf(evb, ", ");
|
||||
evbuffer_add_printf(evb, "%s=", epi->name);
|
||||
event_payload_add_item(epi, evb);
|
||||
}
|
||||
}
|
||||
log_debug("%s%.*s", prefix, (int)EVBUFFER_LENGTH(evb),
|
||||
(char *)EVBUFFER_DATA(evb));
|
||||
evbuffer_free(evb);
|
||||
free(prefix);
|
||||
}
|
||||
|
||||
/* Get a time item. */
|
||||
time_t
|
||||
event_payload_get_time(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_TIME)
|
||||
return (0);
|
||||
return (epi->time);
|
||||
}
|
||||
|
||||
/* Get a number item. */
|
||||
int
|
||||
event_payload_get_int(struct event_payload *ep, const char *name, int *value)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_INT)
|
||||
return (-1);
|
||||
*value = epi->number;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Get an unsigned number item. */
|
||||
int
|
||||
event_payload_get_uint(struct event_payload *ep, const char *name, u_int *value)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_UINT)
|
||||
return (-1);
|
||||
*value = epi->unsigned_number;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Get a client item. */
|
||||
struct client *
|
||||
event_payload_get_client(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_CLIENT)
|
||||
return (NULL);
|
||||
return (epi->client);
|
||||
}
|
||||
|
||||
/* Get a session item. */
|
||||
struct session *
|
||||
event_payload_get_session(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_SESSION)
|
||||
return (NULL);
|
||||
return (epi->session);
|
||||
}
|
||||
|
||||
/* Get a window item. */
|
||||
struct window *
|
||||
event_payload_get_window(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_WINDOW)
|
||||
return (NULL);
|
||||
return (epi->window);
|
||||
}
|
||||
|
||||
/* Get a pane item. */
|
||||
struct window_pane *
|
||||
event_payload_get_pane(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_PANE)
|
||||
return (NULL);
|
||||
return (epi->pane);
|
||||
}
|
||||
|
||||
/* Get a pointer item. */
|
||||
void *
|
||||
event_payload_get_pointer(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_POINTER)
|
||||
return (NULL);
|
||||
return (epi->pointer.ptr);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user