140 Commits
2.7 ... 2.8

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

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

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

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

However, it is nice that display-message can be used to show information
about a specific client. So change so that the -c client will be used if
the session matches the target session (-t or default), otherwise the
best client will be chosen.
2018-04-18 14:35:37 +00:00
nicm
2595718dd3 Include source function name in grid_check_y logging. 2018-04-18 14:31:42 +00:00
Thomas Adam
6ebd737590 Merge branch 'obsd-master' 2018-04-18 15:02:25 +01:00
nicm
e64d078a4c Fix || example. 2018-04-18 12:50:11 +00:00
Nicholas Marriott
ae0b7c7d72 Some changes. 2018-04-13 17:59:11 +01:00
Nicholas Marriott
a770ef3e2a Merge branch '2.7-rc' 2018-04-13 17:50:40 +01:00
Nicholas Marriott
b95d1de8fd 2.7. 2018-04-13 17:47:36 +01:00
Thomas Adam
7e5262ae9a Merge branch 'obsd-master' 2018-04-11 13:02:28 +01:00
nicm
14ecb5032e Allow no client for rename-session, from Ryan Freeman. 2018-04-11 09:54:45 +00:00
Thomas Adam
1bd66b65a3 Merge branch 'obsd-master' 2018-04-10 13:02:28 +01:00
nicm
051a29ca03 A couple of fixes to the : form of SGR. Apparently there is an extra
argument that nobody knew about, so skip that if it exists. Also there
are a bunch of useless optional arguments at the end, so ignore those.
2018-04-10 11:20:15 +00:00
nicm
c6975b3bb4 Add x and X to choose-tree (with a confirmation prompt) to kill an
item. Suggested by Matt Zagrabelny.
2018-04-10 10:48:44 +00:00
Nicholas Marriott
68bf7c532b Merge branch '2.7-rc' 2018-04-06 12:53:43 +01:00
Thomas Adam
9b73d76ddd Merge branch 'obsd-master' 2018-04-06 11:02:24 +01:00
nicm
5d616f4c72 Fix link, from Eliran Gonen. 2018-04-06 09:09:38 +00:00
Thomas Adam
b5c0b2cae2 Merge branch 'obsd-master' 2018-03-29 10:28:18 +01:00
nicm
803b8815bd Do not crash on empty window, reported by Jamie Macdonald in GitHub
issue 1299. Patch from Thomas Adam.
2018-03-29 08:03:51 +00:00
Thomas Adam
640d97afd0 Merge branch 'obsd-master' 2018-03-23 20:02:31 +00:00
nicm
194e9f611b Fix a regression: do not warn about no client in rename-window. 2018-03-23 19:17:03 +00:00
Thomas Adam
5512de6a61 Merge branch 'obsd-master' 2018-03-23 10:02:30 +00:00
nicm
26792b9035 Fix size calculation when spreading out panes. 2018-03-23 07:44:44 +00:00
Nicholas Marriott
919f55ac4a Merge branch '2.7-rc' 2018-03-22 11:26:32 +00:00
Nicholas Marriott
80283f99fb Revert "2.7-rc."
This reverts commit ced74bd72c.
2018-03-22 11:18:26 +00:00
55 changed files with 1381 additions and 634 deletions

38
CHANGES
View File

@@ -1,9 +1,45 @@
CHANGES FROM 2.7 to 2.8
* Make display-panes block the client until a pane is chosen or it
times out.
* Clear history on RIS like most other terminals do.
* Add an "Any" key to run a command if a key is pressed that is not
bound in the current key table.
* Expand formats in load-buffer and save-buffer.
* Add a rectangle_toggle format.
* Add set-hook -R to run a hook immediately.
* Add README.ja.
* Add pane focus hooks.
* Allow any punctuation as separator for s/x/y not only /.
* Improve resizing with the mouse (fix resizing the wrong pane in some
layouts, and allow resizing multiple panes at the same time).
* Allow , and } to be escaped in formats as #, and #}.
* Add KRB5CCNAME to update-environment.
* Change meaning of -c to display-message so the client is used if it
matches the session given to -t.
* Fixes to : form of SGR.
* Add x and X to choose-tree to kill sessions, windows or panes.
CHANGES FROM 2.6 TO 2.7 CHANGES FROM 2.6 TO 2.7
* Remove EVENT_* variables from environment on platforms where tmux uses them * Remove EVENT_* variables from environment on platforms where tmux uses them
so they do not pass on to panes. so they do not pass on to panes.
* Fixed for hooks at server exit. * Fixes for hooks at server exit.
* Remove SGR 10 (was equivalent to SGR 0 but no other terminal seems to do * Remove SGR 10 (was equivalent to SGR 0 but no other terminal seems to do
this). this).

View File

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

6
README
View File

@@ -1,8 +1,8 @@
Welcome to tmux! Welcome to tmux!
tmux is a "terminal multiplexer", it enables a number of terminals (or windows) tmux is a terminal multiplexer: it enables a number of terminals to be created,
to be accessed and controlled from a single terminal. tmux is intended to be a accessed, and controlled from a single screen. tmux may be detached from a
simple, modern, BSD-licensed alternative to programs such as GNU screen. screen and continue running in the background, then later reattached.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris. This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.

62
README.ja Normal file
View File

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

View File

@@ -17,11 +17,10 @@
*/ */
#include <sys/types.h> #include <sys/types.h>
#include <sys/file.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h> #include <sys/un.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/file.h>
#include <errno.h> #include <errno.h>
#include <event.h> #include <event.h>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -156,10 +156,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
/* Get the new session working directory. */ /* Get the new session working directory. */
if ((tmp = args_get(args, 'c')) != NULL) if ((tmp = args_get(args, 'c')) != NULL)
cwd = format_single(item, tmp, c, NULL, NULL, NULL); cwd = format_single(item, tmp, c, NULL, NULL, NULL);
else if (c != NULL && c->session == NULL && c->cwd != NULL)
cwd = xstrdup(c->cwd);
else else
cwd = xstrdup("."); cwd = xstrdup(server_client_get_cwd(c, NULL));
/* /*
* If this is a new client, check for nesting and save the termios * If this is a new client, check for nesting and save the termios
@@ -204,17 +202,29 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
sy = 24; sy = 24;
} }
if ((is_control || detached) && args_has(args, 'x')) { if ((is_control || detached) && args_has(args, 'x')) {
sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr); tmp = args_get(args, 'x');
if (errstr != NULL) { if (strcmp(tmp, "-") == 0) {
cmdq_error(item, "width %s", errstr); if (c != NULL)
goto error; sx = c->tty.sx;
} else {
sx = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "width %s", errstr);
goto error;
}
} }
} }
if ((is_control || detached) && args_has(args, 'y')) { if ((is_control || detached) && args_has(args, 'y')) {
sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr); tmp = args_get(args, 'y');
if (errstr != NULL) { if (strcmp(tmp, "-") == 0) {
cmdq_error(item, "height %s", errstr); if (c != NULL)
goto error; sy = c->tty.sy;
} else {
sy = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
goto error;
}
} }
} }
if (sx == 0) if (sx == 0)

View File

@@ -63,7 +63,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
struct environ_entry *envent; struct environ_entry *envent;
struct cmd_find_state fs; struct cmd_find_state fs;
if (args_has(args, 'a')) { if (args_has(args, 'a') && wl != NULL) {
if ((idx = winlink_shuffle_up(s, wl)) == -1) { if ((idx = winlink_shuffle_up(s, wl)) == -1) {
cmdq_error(item, "no free window indexes"); cmdq_error(item, "no free window indexes");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@@ -95,17 +95,14 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
if ((tmp = args_get(args, 'c')) != NULL) if ((tmp = args_get(args, 'c')) != NULL)
cwd = format_single(item, tmp, c, s, NULL, NULL); cwd = format_single(item, tmp, c, s, NULL, NULL);
else if (item->client != NULL && item->client->session == NULL)
cwd = xstrdup(item->client->cwd);
else else
cwd = xstrdup(s->cwd); cwd = xstrdup(server_client_get_cwd(item->client, s));
if ((tmp = args_get(args, 'n')) != NULL) if ((tmp = args_get(args, 'n')) != NULL)
name = format_single(item, tmp, c, s, NULL, NULL); name = format_single(item, tmp, c, s, NULL, NULL);
else else
name = NULL; name = NULL;
wl = NULL;
if (idx != -1) if (idx != -1)
wl = winlink_find_by_index(&s->windows, idx); wl = winlink_find_by_index(&s->windows, idx);
if (wl != NULL && args_has(args, 'k')) { if (wl != NULL && args_has(args, 'k')) {

View File

@@ -47,7 +47,7 @@ static enum cmd_retval
cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item) cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmd_find_client(item, NULL, 0); struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s; struct session *s = item->target.s;
char *newname; char *newname;

View File

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

View File

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

View File

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

View File

@@ -136,6 +136,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
changed: changed:
free(oldlayout); free(oldlayout);
server_redraw_window(w); server_redraw_window(w);
notify_window("window-layout-changed", w);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
error: error:

View File

@@ -69,6 +69,11 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) { if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
lastwp = w->last; lastwp = w->last;
if (lastwp == NULL && window_count_panes(w) == 2) {
lastwp = TAILQ_PREV(w->active, window_panes, entry);
if (lastwp == NULL)
lastwp = TAILQ_NEXT(w->active, entry);
}
if (lastwp == NULL) { if (lastwp == NULL) {
cmdq_error(item, "no last pane"); cmdq_error(item, "no last pane");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@@ -157,6 +162,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
screen_set_title(&wp->base, pane_title); screen_set_title(&wp->base, pane_title);
server_status_window(wp->window); server_status_window(wp->window);
free(pane_title); free(pane_title);
return (CMD_RETURN_NORMAL);
} }
if (wp == w->active) if (wp == w->active)

View File

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

View File

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

View File

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

View File

@@ -87,10 +87,8 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if ((tmp = args_get(args, 'c')) != NULL) if ((tmp = args_get(args, 'c')) != NULL)
cwd = format_single(item, tmp, c, s, NULL, NULL); cwd = format_single(item, tmp, c, s, NULL, NULL);
else if (item->client != NULL && item->client->session == NULL)
cwd = xstrdup(item->client->cwd);
else else
cwd = xstrdup(s->cwd); cwd = xstrdup(server_client_get_cwd(item->client, s));
type = LAYOUT_TOPBOTTOM; type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h')) if (args_has(args, 'h'))

13
cmd.c
View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
# configure.ac # configure.ac
AC_INIT(tmux, 2.7-rc) AC_INIT(tmux, 2.8)
AC_PREREQ([2.60]) AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc) AC_CONFIG_AUX_DIR(etc)
@@ -610,7 +610,16 @@ case "$host_os" in
*solaris*) *solaris*)
AC_MSG_RESULT(sunos) AC_MSG_RESULT(sunos)
PLATFORM=sunos PLATFORM=sunos
MANFORMAT=man case `/usr/bin/nroff --version 2>&1` in
*GNU*)
# Solaris 11.4 and later use GNU groff.
MANFORMAT=mdoc
;;
*)
# Solaris 2.0 to 11.3 use AT&T nroff.
MANFORMAT=man
;;
esac
;; ;;
*hpux*) *hpux*)
AC_MSG_RESULT(hpux) AC_MSG_RESULT(hpux)

View File

@@ -19,6 +19,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <ctype.h>
#include <errno.h> #include <errno.h>
#include <fnmatch.h> #include <fnmatch.h>
#include <libgen.h> #include <libgen.h>
@@ -562,11 +563,11 @@ format_cb_history_bytes(struct format_tree *ft, struct format_entry *fe)
size = 0; size = 0;
for (i = 0; i < gd->hsize; i++) { for (i = 0; i < gd->hsize; i++) {
gl = &gd->linedata[i]; gl = grid_get_line(gd, i);
size += gl->cellsize * sizeof *gl->celldata; size += gl->cellsize * sizeof *gl->celldata;
size += gl->extdsize * sizeof *gl->extddata; size += gl->extdsize * sizeof *gl->extddata;
} }
size += gd->hsize * sizeof *gd->linedata; size += gd->hsize * sizeof *gl;
xasprintf(&fe->value, "%llu", size); xasprintf(&fe->value, "%llu", size);
} }
@@ -853,18 +854,22 @@ found:
return (copy); return (copy);
} }
/* Skip until comma. */ /* Skip until end. */
static char * static const char *
format_skip(char *s) format_skip(const char *s, char end)
{ {
int brackets = 0; int brackets = 0;
for (; *s != '\0'; s++) { for (; *s != '\0'; s++) {
if (*s == '{') if (*s == '#' && s[1] == '{')
brackets++; brackets++;
if (*s == '#' && strchr(",#{}", s[1]) != NULL) {
s++;
continue;
}
if (*s == '}') if (*s == '}')
brackets--; brackets--;
if (*s == ',' && brackets == 0) if (*s == end && brackets == 0)
break; break;
} }
if (*s == '\0') if (*s == '\0')
@@ -878,7 +883,7 @@ format_choose(char *s, char **left, char **right)
{ {
char *cp; char *cp;
cp = format_skip(s); cp = (char *)format_skip(s, ',');
if (cp == NULL) if (cp == NULL)
return (-1); return (-1);
*cp = '\0'; *cp = '\0';
@@ -903,11 +908,12 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
char **buf, size_t *len, size_t *off) char **buf, size_t *len, size_t *off)
{ {
struct window_pane *wp = ft->wp; struct window_pane *wp = ft->wp;
char *copy, *copy0, *endptr, *ptr, *found, *new; char *copy, *copy0, *endptr, *ptr, *found, *new, sep;
char *value, *from = NULL, *to = NULL, *left, *right; char *value, *from = NULL, *to = NULL, *left, *right;
size_t valuelen, newlen, fromlen, tolen, used; size_t valuelen, newlen, fromlen, tolen, used;
long limit = 0; long limit = 0;
int modifiers = 0, compare = 0, search = 0; int modifiers = 0, compare = 0, search = 0;
int literal = 0;
/* Make a copy of the key. */ /* Make a copy of the key. */
copy0 = copy = xmalloc(keylen + 1); copy0 = copy = xmalloc(keylen + 1);
@@ -916,6 +922,12 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
/* Is there a length limit or whatnot? */ /* Is there a length limit or whatnot? */
switch (copy[0]) { switch (copy[0]) {
case 'l':
if (copy[1] != ':')
break;
literal = 1;
copy += 2;
break;
case 'm': case 'm':
if (copy[1] != ':') if (copy[1] != ':')
break; break;
@@ -980,20 +992,21 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
copy += 2; copy += 2;
break; break;
case 's': case 's':
if (copy[1] != '/') sep = copy[1];
if (sep == ':' || !ispunct((u_char)sep))
break; break;
from = copy + 2; from = copy + 2;
for (copy = from; *copy != '\0' && *copy != '/'; copy++) for (copy = from; *copy != '\0' && *copy != sep; copy++)
/* nothing */; /* nothing */;
if (copy[0] != '/' || copy == from) { if (copy[0] != sep || copy == from) {
copy = copy0; copy = copy0;
break; break;
} }
copy[0] = '\0'; copy[0] = '\0';
to = copy + 1; to = copy + 1;
for (copy = to; *copy != '\0' && *copy != '/'; copy++) for (copy = to; *copy != '\0' && *copy != sep; copy++)
/* nothing */; /* nothing */;
if (copy[0] != '/' || copy[1] != ':') { if (copy[0] != sep || copy[1] != ':') {
copy = copy0; copy = copy0;
break; break;
} }
@@ -1004,6 +1017,12 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
break; break;
} }
/* Is this a literal string? */
if (literal) {
value = xstrdup(copy);
goto done;
}
/* Is this a comparison or a conditional? */ /* Is this a comparison or a conditional? */
if (search) { if (search) {
/* Search in pane. */ /* Search in pane. */
@@ -1035,14 +1054,24 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
free(left); free(left);
} else if (*copy == '?') { } else if (*copy == '?') {
/* Conditional: check first and choose second or third. */ /* Conditional: check first and choose second or third. */
ptr = format_skip(copy); ptr = (char *)format_skip(copy, ',');
if (ptr == NULL) if (ptr == NULL)
goto fail; goto fail;
*ptr = '\0'; *ptr = '\0';
found = format_find(ft, copy + 1, modifiers); found = format_find(ft, copy + 1, modifiers);
if (found == NULL) if (found == NULL) {
/*
* If the conditional not found, try to expand it. If
* the expansion doesn't have any effect, then assume
* false.
*/
found = format_expand(ft, copy + 1); found = format_expand(ft, copy + 1);
if (strcmp(found, copy + 1) == 0) {
free(found);
found = xstrdup("");
}
}
if (format_choose(ptr + 1, &left, &right) != 0) if (format_choose(ptr + 1, &left, &right) != 0)
goto fail; goto fail;
@@ -1097,6 +1126,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
value = new; value = new;
} }
done:
/* Expand the buffer and copy in the value. */ /* Expand the buffer and copy in the value. */
valuelen = strlen(value); valuelen = strlen(value);
while (*len - *off < valuelen + 1) { while (*len - *off < valuelen + 1) {
@@ -1195,14 +1225,8 @@ format_expand(struct format_tree *ft, const char *fmt)
fmt += n + 1; fmt += n + 1;
continue; continue;
case '{': case '{':
brackets = 1; ptr = format_skip(fmt - 2, '}');
for (ptr = fmt; *ptr != '\0'; ptr++) { if (ptr == NULL)
if (*ptr == '{')
brackets++;
if (*ptr == '}' && --brackets == 0)
break;
}
if (*ptr != '}' || brackets != 0)
break; break;
n = ptr - fmt; n = ptr - fmt;
@@ -1210,12 +1234,14 @@ format_expand(struct format_tree *ft, const char *fmt)
break; break;
fmt += n + 1; fmt += n + 1;
continue; continue;
case '}':
case '#': case '#':
case ',':
while (len - off < 2) { while (len - off < 2) {
buf = xreallocarray(buf, 2, len); buf = xreallocarray(buf, 2, len);
len *= 2; len *= 2;
} }
buf[off++] = '#'; buf[off++] = ch;
continue; continue;
default: default:
s = NULL; s = NULL;
@@ -1270,6 +1296,9 @@ void
format_defaults(struct format_tree *ft, struct client *c, struct session *s, format_defaults(struct format_tree *ft, struct client *c, struct session *s,
struct winlink *wl, struct window_pane *wp) struct winlink *wl, struct window_pane *wp)
{ {
if (c != NULL && s != NULL && c->session != s)
log_debug("%s: session does not match", __func__);
format_add(ft, "session_format", "%d", s != NULL); format_add(ft, "session_format", "%d", s != NULL);
format_add(ft, "window_format", "%d", wl != NULL); format_add(ft, "window_format", "%d", wl != NULL);
format_add(ft, "pane_format", "%d", wp != NULL); format_add(ft, "pane_format", "%d", wp != NULL);

View File

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

69
grid.c
View File

@@ -145,6 +145,20 @@ grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
return (gcp); return (gcp);
} }
/* Get line data. */
struct grid_line *
grid_get_line(struct grid *gd, u_int line)
{
return (&gd->linedata[line]);
}
/* Adjust number of lines. */
void
grid_adjust_lines(struct grid *gd, u_int lines)
{
gd->linedata = xreallocarray(gd->linedata, lines, sizeof *gd->linedata);
}
/* Copy default into a cell. */ /* Copy default into a cell. */
static void static void
grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg) grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg)
@@ -166,10 +180,10 @@ grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg)
/* Check grid y position. */ /* Check grid y position. */
static int static int
grid_check_y(struct grid *gd, u_int py) grid_check_y(struct grid *gd, const char* from, u_int py)
{ {
if (py >= gd->hsize + gd->sy) { if (py >= gd->hsize + gd->sy) {
log_debug("y out of range: %u", py); log_debug("%s: y out of range: %u", from, py);
return (-1); return (-1);
} }
return (0); return (0);
@@ -272,6 +286,15 @@ grid_compare(struct grid *ga, struct grid *gb)
return (0); return (0);
} }
/* Trim lines from the history. */
static void
grid_trim_history(struct grid *gd, u_int ny)
{
grid_free_lines(gd, 0, ny);
memmove(&gd->linedata[0], &gd->linedata[ny],
(gd->hsize + gd->sy - ny) * (sizeof *gd->linedata));
}
/* /*
* Collect lines from the history if at the limit. Free the top (oldest) 10% * Collect lines from the history if at the limit. Free the top (oldest) 10%
* and shift up. * and shift up.
@@ -294,9 +317,7 @@ grid_collect_history(struct grid *gd)
* Free the lines from 0 to ny then move the remaining lines over * Free the lines from 0 to ny then move the remaining lines over
* them. * them.
*/ */
grid_free_lines(gd, 0, ny); grid_trim_history(gd, ny);
memmove(&gd->linedata[0], &gd->linedata[ny],
(gd->hsize + gd->sy - ny) * (sizeof *gd->linedata));
gd->hsize -= ny; gd->hsize -= ny;
if (gd->hscrolled > gd->hsize) if (gd->hscrolled > gd->hsize)
@@ -326,9 +347,7 @@ grid_scroll_history(struct grid *gd, u_int bg)
void void
grid_clear_history(struct grid *gd) grid_clear_history(struct grid *gd)
{ {
grid_free_lines(gd, 0, gd->hsize); grid_trim_history(gd, gd->hsize);
memmove(&gd->linedata[0], &gd->linedata[gd->hsize],
gd->sy * (sizeof *gd->linedata));
gd->hscrolled = 0; gd->hscrolled = 0;
gd->hsize = 0; gd->hsize = 0;
@@ -407,7 +426,7 @@ grid_empty_line(struct grid *gd, u_int py, u_int bg)
const struct grid_line * const struct grid_line *
grid_peek_line(struct grid *gd, u_int py) grid_peek_line(struct grid *gd, u_int py)
{ {
if (grid_check_y(gd, py) != 0) if (grid_check_y(gd, __func__, py) != 0)
return (NULL); return (NULL);
return (&gd->linedata[py]); return (&gd->linedata[py]);
} }
@@ -441,7 +460,8 @@ grid_get_cell1(struct grid_line *gl, u_int px, struct grid_cell *gc)
void void
grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc) grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc)
{ {
if (grid_check_y(gd, py) != 0 || px >= gd->linedata[py].cellsize) { if (grid_check_y(gd, __func__, py) != 0 ||
px >= gd->linedata[py].cellsize) {
memcpy(gc, &grid_default_cell, sizeof *gc); memcpy(gc, &grid_default_cell, sizeof *gc);
return; return;
} }
@@ -455,7 +475,7 @@ grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
struct grid_line *gl; struct grid_line *gl;
struct grid_cell_entry *gce; struct grid_cell_entry *gce;
if (grid_check_y(gd, py) != 0) if (grid_check_y(gd, __func__, py) != 0)
return; return;
grid_expand_line(gd, py, px + 1, 8); grid_expand_line(gd, py, px + 1, 8);
@@ -481,7 +501,7 @@ grid_set_cells(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc,
struct grid_cell *gcp; struct grid_cell *gcp;
u_int i; u_int i;
if (grid_check_y(gd, py) != 0) if (grid_check_y(gd, __func__, py) != 0)
return; return;
grid_expand_line(gd, py, px + slen, 8); grid_expand_line(gd, py, px + slen, 8);
@@ -514,9 +534,9 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, u_int bg)
return; return;
} }
if (grid_check_y(gd, py) != 0) if (grid_check_y(gd, __func__, py) != 0)
return; return;
if (grid_check_y(gd, py + ny - 1) != 0) if (grid_check_y(gd, __func__, py + ny - 1) != 0)
return; return;
for (yy = py; yy < py + ny; yy++) { for (yy = py; yy < py + ny; yy++) {
@@ -543,9 +563,9 @@ grid_clear_lines(struct grid *gd, u_int py, u_int ny, u_int bg)
if (ny == 0) if (ny == 0)
return; return;
if (grid_check_y(gd, py) != 0) if (grid_check_y(gd, __func__, py) != 0)
return; return;
if (grid_check_y(gd, py + ny - 1) != 0) if (grid_check_y(gd, __func__, py + ny - 1) != 0)
return; return;
for (yy = py; yy < py + ny; yy++) { for (yy = py; yy < py + ny; yy++) {
@@ -563,13 +583,13 @@ grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny, u_int bg)
if (ny == 0 || py == dy) if (ny == 0 || py == dy)
return; return;
if (grid_check_y(gd, py) != 0) if (grid_check_y(gd, __func__, py) != 0)
return; return;
if (grid_check_y(gd, py + ny - 1) != 0) if (grid_check_y(gd, __func__, py + ny - 1) != 0)
return; return;
if (grid_check_y(gd, dy) != 0) if (grid_check_y(gd, __func__, dy) != 0)
return; return;
if (grid_check_y(gd, dy + ny - 1) != 0) if (grid_check_y(gd, __func__, dy + ny - 1) != 0)
return; return;
/* Free any lines which are being replaced. */ /* Free any lines which are being replaced. */
@@ -603,7 +623,7 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx,
if (nx == 0 || px == dx) if (nx == 0 || px == dx)
return; return;
if (grid_check_y(gd, py) != 0) if (grid_check_y(gd, __func__, py) != 0)
return; return;
gl = &gd->linedata[py]; gl = &gd->linedata[py];
@@ -983,9 +1003,9 @@ static void
grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy, grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy,
u_int width, u_int *cy, int already) u_int width, u_int *cy, int already)
{ {
struct grid_line *gl, *from; struct grid_line *gl, *from = NULL;
struct grid_cell gc; struct grid_cell gc;
u_int lines, want, left, i, to, line; u_int lines, left, i, to, line, want = 0;
u_int at; u_int at;
int wrapped = 1; int wrapped = 1;
@@ -1010,7 +1030,7 @@ grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy,
* If this is now the last line, there is nothing more to be * If this is now the last line, there is nothing more to be
* done. * done.
*/ */
if (yy + lines == gd->hsize + gd->sy) if (yy + 1 + lines == gd->hsize + gd->sy)
break; break;
line = yy + 1 + lines; line = yy + 1 + lines;
@@ -1020,6 +1040,7 @@ grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy,
if (gd->linedata[line].cellused == 0) { if (gd->linedata[line].cellused == 0) {
if (!wrapped) if (!wrapped)
break; break;
lines++;
continue; continue;
} }

30
input.c
View File

@@ -30,7 +30,7 @@
/* /*
* Based on the description by Paul Williams at: * Based on the description by Paul Williams at:
* *
* http://vt100.net/emu/dec_ansi_parser * https://vt100.net/emu/dec_ansi_parser
* *
* With the following changes: * With the following changes:
* *
@@ -1188,6 +1188,7 @@ input_esc_dispatch(struct input_ctx *ictx)
window_pane_reset_palette(ictx->wp); window_pane_reset_palette(ictx->wp);
input_reset_cell(ictx); input_reset_cell(ictx);
screen_write_reset(sctx); screen_write_reset(sctx);
screen_write_clearhistory(sctx);
break; break;
case INPUT_ESC_IND: case INPUT_ESC_IND:
screen_write_linefeed(sctx, 0, ictx->cell.cell.bg); screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
@@ -1845,10 +1846,12 @@ input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
ptr = copy = xstrdup(s); ptr = copy = xstrdup(s);
while ((out = strsep(&ptr, ":")) != NULL) { while ((out = strsep(&ptr, ":")) != NULL) {
p[n++] = strtonum(out, 0, INT_MAX, &errstr); if (*out != '\0') {
if (errstr != NULL || n == nitems(p)) { p[n++] = strtonum(out, 0, INT_MAX, &errstr);
free(copy); if (errstr != NULL || n == nitems(p)) {
return; free(copy);
return;
}
} }
log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]); log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]);
} }
@@ -1856,16 +1859,21 @@ input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
if (n == 0 || (p[0] != 38 && p[0] != 48)) if (n == 0 || (p[0] != 38 && p[0] != 48))
return; return;
switch (p[1]) { if (p[1] == -1)
i = 2;
else
i = 1;
switch (p[i]) {
case 2: case 2:
if (n != 5) if (n < i + 4)
break; break;
input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[2], p[3], p[4]); input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[i + 1], p[i + 2],
p[i + 3]);
break; break;
case 5: case 5:
if (n != 3) if (n < i + 2)
break; break;
input_csi_dispatch_sgr_256_do(ictx, p[0], p[2]); input_csi_dispatch_sgr_256_do(ictx, p[0], p[i + 1]);
break; break;
} }
} }
@@ -2227,7 +2235,7 @@ bad:
free(copy); free(copy);
} }
/* Handle the OSC 10 sequence for setting background colour. */ /* Handle the OSC 10 sequence for setting foreground colour. */
static void static void
input_osc_10(struct window_pane *wp, const char *p) input_osc_10(struct window_pane *wp, const char *p)
{ {

View File

@@ -24,17 +24,19 @@
#include "tmux.h" #include "tmux.h"
RB_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp); static int key_bindings_cmp(struct key_binding *, struct key_binding *);
RB_GENERATE(key_tables, key_table, entry, key_table_cmp); RB_GENERATE_STATIC(key_bindings, key_binding, entry, key_bindings_cmp);
struct key_tables key_tables = RB_INITIALIZER(&key_tables); static int key_table_cmp(struct key_table *, struct key_table *);
RB_GENERATE_STATIC(key_tables, key_table, entry, key_table_cmp);
static struct key_tables key_tables = RB_INITIALIZER(&key_tables);
int static int
key_table_cmp(struct key_table *e1, struct key_table *e2) key_table_cmp(struct key_table *table1, struct key_table *table2)
{ {
return (strcmp(e1->name, e2->name)); return (strcmp(table1->name, table2->name));
} }
int static int
key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2) key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2)
{ {
if (bd1->key < bd2->key) if (bd1->key < bd2->key)
@@ -64,6 +66,18 @@ key_bindings_get_table(const char *name, int create)
return (table); return (table);
} }
struct key_table *
key_bindings_first_table(void)
{
return (RB_MIN(key_tables, &key_tables));
}
struct key_table *
key_bindings_next_table(struct key_table *table)
{
return (RB_NEXT(key_tables, &key_tables, table));
}
void void
key_bindings_unref_table(struct key_table *table) key_bindings_unref_table(struct key_table *table)
{ {
@@ -83,6 +97,27 @@ key_bindings_unref_table(struct key_table *table)
free(table); free(table);
} }
struct key_binding *
key_bindings_get(struct key_table *table, key_code key)
{
struct key_binding bd;
bd.key = key;
return (RB_FIND(key_bindings, &table->key_bindings, &bd));
}
struct key_binding *
key_bindings_first(struct key_table *table)
{
return (RB_MIN(key_bindings, &table->key_bindings));
}
struct key_binding *
key_bindings_next(__unused struct key_table *table, struct key_binding *bd)
{
return (RB_NEXT(key_bindings, &table->key_bindings, bd));
}
void void
key_bindings_add(const char *name, key_code key, int repeat, key_bindings_add(const char *name, key_code key, int repeat,
struct cmd_list *cmdlist) struct cmd_list *cmdlist)

View File

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

View File

@@ -127,6 +127,42 @@ layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
} }
} }
struct layout_cell *
layout_search_by_border(struct layout_cell *lc, u_int x, u_int y)
{
struct layout_cell *lcchild, *last = NULL;
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
if (x >= lcchild->xoff && x < lcchild->xoff + lcchild->sx &&
y >= lcchild->yoff && y < lcchild->yoff + lcchild->sy) {
/* Inside the cell - recurse. */
return (layout_search_by_border(lcchild, x, y));
}
if (last == NULL) {
last = lcchild;
continue;
}
switch (lc->type) {
case LAYOUT_LEFTRIGHT:
if (x < lcchild->xoff && x >= last->xoff + last->sx)
return (last);
break;
case LAYOUT_TOPBOTTOM:
if (y < lcchild->yoff && y >= last->yoff + last->sy)
return (last);
break;
case LAYOUT_WINDOWPANE:
break;
}
last = lcchild;
}
return (NULL);
}
void void
layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, u_int xoff, layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, u_int xoff,
u_int yoff) u_int yoff)
@@ -550,29 +586,11 @@ layout_resize_pane_to(struct window_pane *wp, enum layout_type type,
layout_resize_pane(wp, type, change, 1); layout_resize_pane(wp, type, change, 1);
} }
/* Resize a single pane within the layout. */
void void
layout_resize_pane(struct window_pane *wp, enum layout_type type, int change, layout_resize_layout(struct window *w, struct layout_cell *lc,
int opposite) enum layout_type type, int change, int opposite)
{ {
struct window *w = wp->window; int needed, size;
struct layout_cell *lc, *lcparent;
int needed, size;
lc = wp->layout_cell;
/* Find next parent of the same type. */
lcparent = lc->parent;
while (lcparent != NULL && lcparent->type != type) {
lc = lcparent;
lcparent = lc->parent;
}
if (lcparent == NULL)
return;
/* If this is the last cell, move back one. */
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
lc = TAILQ_PREV(lc, layout_cells, entry);
/* Grow or shrink the cell. */ /* Grow or shrink the cell. */
needed = change; needed = change;
@@ -591,9 +609,34 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change,
} }
/* Fix cell offsets. */ /* Fix cell offsets. */
layout_fix_offsets(wp->window->layout_root); layout_fix_offsets(w->layout_root);
layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); layout_fix_panes(w, w->sx, w->sy);
notify_window("window-layout-changed", wp->window); notify_window("window-layout-changed", w);
}
/* Resize a single pane within the layout. */
void
layout_resize_pane(struct window_pane *wp, enum layout_type type, int change,
int opposite)
{
struct layout_cell *lc, *lcparent;
lc = wp->layout_cell;
/* Find next parent of the same type. */
lcparent = lc->parent;
while (lcparent != NULL && lcparent->type != type) {
lc = lcparent;
lcparent = lc->parent;
}
if (lcparent == NULL)
return;
/* If this is the last cell, move back one. */
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
lc = TAILQ_PREV(lc, layout_cells, entry);
layout_resize_layout(wp->window, lc, type, change, opposite);
} }
/* Helper function to grow pane. */ /* Helper function to grow pane. */

View File

@@ -192,7 +192,7 @@ mode_tree_clear_tagged(struct mode_tree_list *mtl)
} }
} }
void static void
mode_tree_up(struct mode_tree_data *mtd, int wrap) mode_tree_up(struct mode_tree_data *mtd, int wrap)
{ {
if (mtd->current == 0) { if (mtd->current == 0) {

View File

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

View File

@@ -513,8 +513,8 @@ const struct options_table_entry options_table[] = {
{ .name = "update-environment", { .name = "update-environment",
.type = OPTIONS_TABLE_ARRAY, .type = OPTIONS_TABLE_ARRAY,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
.default_str = "DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID " .default_str = "DISPLAY KRB5CCNAME SSH_ASKPASS SSH_AUTH_SOCK "
"SSH_CONNECTION WINDOWID XAUTHORITY" "SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY"
}, },
{ .name = "visual-activity", { .name = "visual-activity",

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

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

View File

@@ -23,6 +23,18 @@
#include "tmux.h" #include "tmux.h"
struct screen_redraw_ctx {
struct client *c;
u_int lines;
int top;
int pane_status;
u_int sx;
u_int sy;
};
static int screen_redraw_cell_border1(struct window_pane *, u_int, u_int); static int screen_redraw_cell_border1(struct window_pane *, u_int, u_int);
static int screen_redraw_cell_border(struct client *, u_int, u_int); static int screen_redraw_cell_border(struct client *, u_int, u_int);
static int screen_redraw_check_cell(struct client *, u_int, u_int, int, static int screen_redraw_check_cell(struct client *, u_int, u_int, int,
@@ -34,11 +46,11 @@ static int screen_redraw_make_pane_status(struct client *, struct window *,
struct window_pane *); struct window_pane *);
static void screen_redraw_draw_pane_status(struct client *, int); static void screen_redraw_draw_pane_status(struct client *, int);
static void screen_redraw_draw_borders(struct client *, int, u_int, u_int); static void screen_redraw_draw_borders(struct screen_redraw_ctx *);
static void screen_redraw_draw_panes(struct client *, u_int, u_int); static void screen_redraw_draw_panes(struct screen_redraw_ctx *);
static void screen_redraw_draw_status(struct client *, u_int, u_int); static void screen_redraw_draw_status(struct screen_redraw_ctx *);
static void screen_redraw_draw_number(struct client *, struct window_pane *, static void screen_redraw_draw_number(struct screen_redraw_ctx *,
u_int, u_int); struct window_pane *);
#define CELL_INSIDE 0 #define CELL_INSIDE 0
#define CELL_LEFTRIGHT 1 #define CELL_LEFTRIGHT 1
@@ -375,42 +387,44 @@ void
screen_redraw_screen(struct client *c, int draw_panes, int draw_status, screen_redraw_screen(struct client *c, int draw_panes, int draw_status,
int draw_borders) int draw_borders)
{ {
struct options *oo = c->session->options; struct options *oo = c->session->options;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct options *wo = w->options; struct options *wo = w->options;
u_int top, lines; struct screen_redraw_ctx ctx;
int position, pane_status;
if (c->flags & CLIENT_SUSPENDED) if (c->flags & CLIENT_SUSPENDED)
return; return;
memset(&ctx, 0, sizeof ctx);
ctx.c = c;
if (c->flags & CLIENT_STATUSOFF) if (c->flags & CLIENT_STATUSOFF)
lines = 0; ctx.lines = 0;
else else
lines = status_line_size(c->session); ctx.lines = status_line_size(c->session);
if (c->message_string != NULL || c->prompt_string != NULL) if (c->message_string != NULL || c->prompt_string != NULL)
lines = (lines == 0) ? 1 : lines; ctx.lines = (ctx.lines == 0) ? 1 : ctx.lines;
position = options_get_number(oo, "status-position"); if (ctx.lines != 0 && options_get_number(oo, "status-position") == 0)
if (lines != 0 && position == 0) ctx.top = 1;
top = 1; ctx.pane_status = options_get_number(wo, "pane-border-status");
else
top = 0;
if (lines == 0) ctx.sx = tty->sx;
ctx.sy = tty->sy - ctx.lines;
if (ctx.lines == 0)
draw_status = 0; draw_status = 0;
if (draw_borders) { if (draw_borders) {
pane_status = options_get_number(wo, "pane-border-status"); if (ctx.pane_status != CELL_STATUS_OFF)
screen_redraw_draw_borders(c, pane_status, lines, top); screen_redraw_draw_pane_status(c, ctx.pane_status);
if (pane_status != CELL_STATUS_OFF) screen_redraw_draw_borders(&ctx);
screen_redraw_draw_pane_status(c, pane_status);
} }
if (draw_panes) if (draw_panes)
screen_redraw_draw_panes(c, lines, top); screen_redraw_draw_panes(&ctx);
if (draw_status) if (draw_status)
screen_redraw_draw_status(c, lines, top); screen_redraw_draw_status(&ctx);
tty_reset(tty); tty_reset(tty);
} }
@@ -435,25 +449,65 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
tty_reset(&c->tty); tty_reset(&c->tty);
} }
/* Draw a border cell. */
static void
screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int x, u_int y,
int small, u_int msgx, u_int msgy, struct grid_cell *m_active_gc,
struct grid_cell *active_gc, struct grid_cell *m_other_gc,
struct grid_cell *other_gc)
{
struct client *c = ctx->c;
struct session *s = c->session;
struct window *w = s->curw->window;
struct tty *tty = &c->tty;
struct window_pane *wp;
struct window_pane *active = w->active;
struct window_pane *marked = marked_pane.wp;
u_int type;
int flag, pane_status = ctx->pane_status;
type = screen_redraw_check_cell(c, x, y, pane_status, &wp);
if (type == CELL_INSIDE)
return;
if (type == CELL_OUTSIDE && small && x > msgx && y == msgy)
return;
flag = screen_redraw_check_is(x, y, type, pane_status, w, active, wp);
if (server_is_marked(s, s->curw, marked_pane.wp) &&
screen_redraw_check_is(x, y, type, pane_status, w, marked, wp)) {
if (flag)
tty_attributes(tty, m_active_gc, NULL);
else
tty_attributes(tty, m_other_gc, NULL);
} else if (flag)
tty_attributes(tty, active_gc, NULL);
else
tty_attributes(tty, other_gc, NULL);
if (ctx->top)
tty_cursor(tty, x, ctx->lines + y);
else
tty_cursor(tty, x, y);
tty_putc(tty, CELL_BORDERS[type]);
}
/* Draw the borders. */ /* Draw the borders. */
static void static void
screen_redraw_draw_borders(struct client *c, int pane_status, u_int lines, screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
u_int top)
{ {
struct client *c = ctx->c;
struct session *s = c->session; struct session *s = c->session;
struct window *w = s->curw->window; struct window *w = s->curw->window;
struct options *oo = w->options; struct options *oo = w->options;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct window_pane *wp;
struct grid_cell m_active_gc, active_gc, m_other_gc, other_gc; struct grid_cell m_active_gc, active_gc, m_other_gc, other_gc;
struct grid_cell msg_gc; struct grid_cell msg_gc;
u_int i, j, type, msgx = 0, msgy = 0; u_int i, j, msgx = 0, msgy = 0;
int active, small, flags; int small, flags;
char msg[256]; char msg[256];
const char *tmp; const char *tmp;
size_t msglen = 0; size_t msglen = 0;
small = (tty->sy - lines + top > w->sy) || (tty->sx > w->sx); small = (ctx->sy + ctx->top > w->sy) || (ctx->sx > w->sx);
if (small) { if (small) {
flags = w->flags & (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT); flags = w->flags & (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT);
if (flags == (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT)) if (flags == (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT))
@@ -470,12 +524,12 @@ screen_redraw_draw_borders(struct client *c, int pane_status, u_int lines,
w->sx, w->sy, tmp); w->sx, w->sy, tmp);
msglen = strlen(msg); msglen = strlen(msg);
if (tty->sy - 1 - lines + top > w->sy && tty->sx >= msglen) { if (ctx->sy - 1 + ctx->top > w->sy && ctx->sx >= msglen) {
msgx = tty->sx - msglen; msgx = ctx->sx - msglen;
msgy = tty->sy - 1 - lines + top; msgy = ctx->sy - 1 + ctx->top;
} else if (tty->sx - w->sx > msglen) { } else if (ctx->sx - w->sx > msglen) {
msgx = tty->sx - msglen; msgx = ctx->sx - msglen;
msgy = tty->sy - 1 - lines + top; msgy = ctx->sy - 1 + ctx->top;
} else } else
small = 0; small = 0;
} }
@@ -489,33 +543,11 @@ screen_redraw_draw_borders(struct client *c, int pane_status, u_int lines,
memcpy(&m_active_gc, &active_gc, sizeof m_active_gc); memcpy(&m_active_gc, &active_gc, sizeof m_active_gc);
m_active_gc.attr ^= GRID_ATTR_REVERSE; m_active_gc.attr ^= GRID_ATTR_REVERSE;
for (j = 0; j < tty->sy - lines; j++) { for (j = 0; j < ctx->sy; j++) {
for (i = 0; i < tty->sx; i++) { for (i = 0; i < ctx->sx; i++) {
type = screen_redraw_check_cell(c, i, j, pane_status, screen_redraw_draw_borders_cell(ctx, i, j, small,
&wp); msgx, msgy, &m_active_gc, &active_gc, &m_other_gc,
if (type == CELL_INSIDE) &other_gc);
continue;
if (type == CELL_OUTSIDE && small &&
i > msgx && j == msgy)
continue;
active = screen_redraw_check_is(i, j, type, pane_status,
w, w->active, wp);
if (server_is_marked(s, s->curw, marked_pane.wp) &&
screen_redraw_check_is(i, j, type, pane_status, w,
marked_pane.wp, wp)) {
if (active)
tty_attributes(tty, &m_active_gc, NULL);
else
tty_attributes(tty, &m_other_gc, NULL);
} else if (active)
tty_attributes(tty, &active_gc, NULL);
else
tty_attributes(tty, &other_gc, NULL);
if (top)
tty_cursor(tty, i, lines + j);
else
tty_cursor(tty, i, j);
tty_putc(tty, CELL_BORDERS[type]);
} }
} }
@@ -529,48 +561,49 @@ screen_redraw_draw_borders(struct client *c, int pane_status, u_int lines,
/* Draw the panes. */ /* Draw the panes. */
static void static void
screen_redraw_draw_panes(struct client *c, u_int lines, u_int top) screen_redraw_draw_panes(struct screen_redraw_ctx *ctx)
{ {
struct client *c = ctx->c;
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct window_pane *wp; struct window_pane *wp;
u_int i, y; u_int i, y;
if (top) if (ctx->top)
y = lines; y = ctx->lines;
else else
y = 0; y = 0;
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp)) if (!window_pane_visible(wp))
continue; continue;
for (i = 0; i < wp->sy; i++) for (i = 0; i < wp->sy; i++)
tty_draw_pane(tty, wp, i, wp->xoff, y + wp->yoff); tty_draw_pane(tty, wp, i, wp->xoff, y + wp->yoff);
if (c->flags & CLIENT_IDENTIFY) if (c->flags & CLIENT_IDENTIFY)
screen_redraw_draw_number(c, wp, lines, top); screen_redraw_draw_number(ctx, wp);
} }
} }
/* Draw the status line. */ /* Draw the status line. */
static void static void
screen_redraw_draw_status(struct client *c, u_int lines, u_int top) screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
{ {
struct client *c = ctx->c;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
u_int i, y; u_int i, y;
if (top) if (ctx->top)
y = 0; y = 0;
else else
y = tty->sy - lines; y = ctx->sy;
for (i = 0; i < lines; i++) for (i = 0; i < ctx->lines; i++)
tty_draw_line(tty, NULL, &c->status.status, i, 0, y); tty_draw_line(tty, NULL, &c->status.status, i, 0, y);
} }
/* Draw number on a pane. */ /* Draw number on a pane. */
static void static void
screen_redraw_draw_number(struct client *c, struct window_pane *wp, screen_redraw_draw_number(struct screen_redraw_ctx *ctx, struct window_pane *wp)
u_int lines, u_int top)
{ {
struct client *c = ctx->c;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct session *s = c->session; struct session *s = c->session;
struct options *oo = s->options; struct options *oo = s->options;
@@ -593,8 +626,8 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp,
px = wp->sx / 2; py = wp->sy / 2; px = wp->sx / 2; py = wp->sy / 2;
xoff = wp->xoff; yoff = wp->yoff; xoff = wp->xoff; yoff = wp->yoff;
if (top) if (ctx->top)
yoff += lines; yoff += ctx->lines;
if (wp->sx < len * 6 || wp->sy < 5) { if (wp->sx < len * 6 || wp->sy < 5) {
tty_cursor(tty, xoff + px - len / 2, yoff + py); tty_cursor(tty, xoff + px - len / 2, yoff + py);

View File

@@ -408,7 +408,7 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
break; break;
cx = s->cx; cx = s->cx;
for (xx = px; xx < px + nx; xx++) { for (xx = px; xx < px + nx; xx++) {
if (xx >= gd->linedata[yy].cellsize) if (xx >= grid_get_line(gd, yy)->cellsize)
break; break;
grid_get_cell(gd, xx, yy, &gc); grid_get_cell(gd, xx, yy, &gc);
if (xx + gc.data.width > px + nx) if (xx + gc.data.width > px + nx)
@@ -694,7 +694,7 @@ screen_write_backspace(struct screen_write_ctx *ctx)
if (s->cx == 0) { if (s->cx == 0) {
if (s->cy == 0) if (s->cy == 0)
return; return;
gl = &s->grid->linedata[s->grid->hsize + s->cy - 1]; gl = grid_get_line(s->grid, s->grid->hsize + s->cy - 1);
if (gl->flags & GRID_LINE_WRAPPED) { if (gl->flags & GRID_LINE_WRAPPED) {
s->cy--; s->cy--;
s->cx = screen_size_x(s) - 1; s->cx = screen_size_x(s) - 1;
@@ -917,7 +917,7 @@ screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
u_int sx = screen_size_x(s); u_int sx = screen_size_x(s);
gl = &s->grid->linedata[s->grid->hsize + s->cy]; gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
if (gl->cellsize == 0 && bg == 8) if (gl->cellsize == 0 && bg == 8)
return; return;
@@ -940,7 +940,7 @@ screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg)
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
u_int sx = screen_size_x(s); u_int sx = screen_size_x(s);
gl = &s->grid->linedata[s->grid->hsize + s->cy]; gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
if (s->cx > sx - 1 || (s->cx >= gl->cellsize && bg == 8)) if (s->cx > sx - 1 || (s->cx >= gl->cellsize && bg == 8))
return; return;
@@ -1043,7 +1043,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg)
struct grid *gd = s->grid; struct grid *gd = s->grid;
struct grid_line *gl; struct grid_line *gl;
gl = &gd->linedata[gd->hsize + s->cy]; gl = grid_get_line(gd, gd->hsize + s->cy);
if (wrapped) if (wrapped)
gl->flags |= GRID_LINE_WRAPPED; gl->flags |= GRID_LINE_WRAPPED;
else else
@@ -1343,7 +1343,7 @@ screen_write_collect_add(struct screen_write_ctx *ctx,
collect = 0; collect = 0;
else if (s->mode & MODE_INSERT) else if (s->mode & MODE_INSERT)
collect = 0; collect = 0;
else if (s->sel.flag) else if (s->sel != NULL)
collect = 0; collect = 0;
if (!collect) { if (!collect) {
screen_write_collect_end(ctx); screen_write_collect_end(ctx);
@@ -1433,7 +1433,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
screen_write_initctx(ctx, &ttyctx); screen_write_initctx(ctx, &ttyctx);
/* Handle overwriting of UTF-8 characters. */ /* Handle overwriting of UTF-8 characters. */
gl = &s->grid->linedata[s->grid->hsize + s->cy]; gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
if (gl->flags & GRID_LINE_EXTENDED) { if (gl->flags & GRID_LINE_EXTENDED) {
grid_view_get_cell(gd, s->cx, s->cy, &now_gc); grid_view_get_cell(gd, s->cx, s->cy, &now_gc);
if (screen_write_overwrite(ctx, &now_gc, width)) if (screen_write_overwrite(ctx, &now_gc, width))

View File

@@ -24,6 +24,22 @@
#include "tmux.h" #include "tmux.h"
/* Selected area in screen. */
struct screen_sel {
int hidden;
int rectangle;
int modekeys;
u_int sx;
u_int sy;
u_int ex;
u_int ey;
struct grid_cell cell;
};
/* Entry on title stack. */
struct screen_title_entry { struct screen_title_entry {
char *text; char *text;
@@ -66,6 +82,7 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
s->cstyle = 0; s->cstyle = 0;
s->ccolour = xstrdup(""); s->ccolour = xstrdup("");
s->tabs = NULL; s->tabs = NULL;
s->sel = NULL;
screen_reinit(s); screen_reinit(s);
} }
@@ -94,6 +111,7 @@ screen_reinit(struct screen *s)
void void
screen_free(struct screen *s) screen_free(struct screen *s)
{ {
free(s->sel);
free(s->tabs); free(s->tabs);
free(s->title); free(s->title);
free(s->ccolour); free(s->ccolour);
@@ -280,9 +298,8 @@ screen_resize_y(struct screen *s, u_int sy)
s->cy -= needed; s->cy -= needed;
} }
/* Resize line arrays. */ /* Resize line array. */
gd->linedata = xreallocarray(gd->linedata, gd->hsize + sy, grid_adjust_lines(gd, gd->hsize + sy);
sizeof *gd->linedata);
/* Size increasing. */ /* Size increasing. */
if (sy > oldy) { if (sy > oldy) {
@@ -305,7 +322,7 @@ screen_resize_y(struct screen *s, u_int sy)
/* Then fill the rest in with blanks. */ /* Then fill the rest in with blanks. */
for (i = gd->hsize + sy - needed; i < gd->hsize + sy; i++) for (i = gd->hsize + sy - needed; i < gd->hsize + sy; i++)
memset(&gd->linedata[i], 0, sizeof gd->linedata[i]); memset(grid_get_line(gd, i), 0, sizeof(struct grid_line));
} }
/* Set the new size, and reset the scroll region. */ /* Set the new size, and reset the scroll region. */
@@ -317,51 +334,49 @@ screen_resize_y(struct screen *s, u_int sy)
/* Set selection. */ /* Set selection. */
void void
screen_set_selection(struct screen *s, u_int sx, u_int sy, screen_set_selection(struct screen *s, u_int sx, u_int sy,
u_int ex, u_int ey, u_int rectflag, struct grid_cell *gc) u_int ex, u_int ey, u_int rectangle, int modekeys, struct grid_cell *gc)
{ {
struct screen_sel *sel = &s->sel; if (s->sel == NULL)
s->sel = xcalloc(1, sizeof *s->sel);
memcpy(&sel->cell, gc, sizeof sel->cell); memcpy(&s->sel->cell, gc, sizeof s->sel->cell);
sel->flag = 1; s->sel->hidden = 0;
sel->hidden = 0; s->sel->rectangle = rectangle;
s->sel->modekeys = modekeys;
sel->rectflag = rectflag; s->sel->sx = sx;
s->sel->sy = sy;
sel->sx = sx; sel->sy = sy; s->sel->ex = ex;
sel->ex = ex; sel->ey = ey; s->sel->ey = ey;
} }
/* Clear selection. */ /* Clear selection. */
void void
screen_clear_selection(struct screen *s) screen_clear_selection(struct screen *s)
{ {
struct screen_sel *sel = &s->sel; free(s->sel);
s->sel = NULL;
sel->flag = 0;
sel->hidden = 0;
sel->lineflag = LINE_SEL_NONE;
} }
/* Hide selection. */ /* Hide selection. */
void void
screen_hide_selection(struct screen *s) screen_hide_selection(struct screen *s)
{ {
struct screen_sel *sel = &s->sel; if (s->sel != NULL)
s->sel->hidden = 1;
sel->hidden = 1;
} }
/* Check if cell in selection. */ /* Check if cell in selection. */
int int
screen_check_selection(struct screen *s, u_int px, u_int py) screen_check_selection(struct screen *s, u_int px, u_int py)
{ {
struct screen_sel *sel = &s->sel; struct screen_sel *sel = s->sel;
u_int xx; u_int xx;
if (!sel->flag || sel->hidden) if (sel == NULL || sel->hidden)
return (0); return (0);
if (sel->rectflag) { if (sel->rectangle) {
if (sel->sy < sel->ey) { if (sel->sy < sel->ey) {
/* start line < end line -- downward selection. */ /* start line < end line -- downward selection. */
if (py < sel->sy || py > sel->ey) if (py < sel->sy || py > sel->ey)
@@ -454,10 +469,10 @@ void
screen_select_cell(struct screen *s, struct grid_cell *dst, screen_select_cell(struct screen *s, struct grid_cell *dst,
const struct grid_cell *src) const struct grid_cell *src)
{ {
if (!s->sel.flag || s->sel.hidden) if (s->sel == NULL || s->sel->hidden)
return; return;
memcpy(dst, &s->sel.cell, sizeof *dst); memcpy(dst, &s->sel->cell, sizeof *dst);
utf8_copy(&dst->data, &src->data); utf8_copy(&dst->data, &src->data);
dst->attr = dst->attr & ~GRID_ATTR_CHARSET; dst->attr = dst->attr & ~GRID_ATTR_CHARSET;

View File

@@ -41,6 +41,8 @@ static void server_client_check_redraw(struct client *);
static void server_client_set_title(struct client *); static void server_client_set_title(struct client *);
static void server_client_reset_state(struct client *); static void server_client_reset_state(struct client *);
static int server_client_assume_paste(struct session *); static int server_client_assume_paste(struct session *);
static void server_client_clear_identify(struct client *,
struct window_pane *);
static void server_client_dispatch(struct imsg *, void *); static void server_client_dispatch(struct imsg *, void *);
static void server_client_dispatch_command(struct client *, struct imsg *); static void server_client_dispatch_command(struct client *, struct imsg *);
@@ -91,7 +93,7 @@ server_client_set_identify(struct client *c, u_int delay)
} }
/* Clear identify mode on client. */ /* Clear identify mode on client. */
void static void
server_client_clear_identify(struct client *c, struct window_pane *wp) server_client_clear_identify(struct client *c, struct window_pane *wp)
{ {
if (~c->flags & CLIENT_IDENTIFY) if (~c->flags & CLIENT_IDENTIFY)
@@ -813,7 +815,7 @@ server_client_handle_key(struct client *c, key_code key)
struct window_pane *wp; struct window_pane *wp;
struct timeval tv; struct timeval tv;
struct key_table *table, *first; struct key_table *table, *first;
struct key_binding bd_find, *bd; struct key_binding *bd;
int xtimeout, flags; int xtimeout, flags;
struct cmd_find_state fs; struct cmd_find_state fs;
key_code key0; key_code key0;
@@ -882,11 +884,11 @@ server_client_handle_key(struct client *c, key_code key)
/* Forward mouse keys if disabled. */ /* Forward mouse keys if disabled. */
if (KEYC_IS_MOUSE(key) && !options_get_number(s->options, "mouse")) if (KEYC_IS_MOUSE(key) && !options_get_number(s->options, "mouse"))
goto forward; goto forward_key;
/* Treat everything as a regular key when pasting is detected. */ /* Treat everything as a regular key when pasting is detected. */
if (!KEYC_IS_MOUSE(key) && server_client_assume_paste(s)) if (!KEYC_IS_MOUSE(key) && server_client_assume_paste(s))
goto forward; goto forward_key;
/* /*
* Work out the current key table. If the pane is in a mode, use * Work out the current key table. If the pane is in a mode, use
@@ -901,11 +903,11 @@ server_client_handle_key(struct client *c, key_code key)
table = c->keytable; table = c->keytable;
first = table; first = table;
table_changed:
/* /*
* The prefix always takes precedence and forces a switch to the prefix * The prefix always takes precedence and forces a switch to the prefix
* table, unless we are already there. * table, unless we are already there.
*/ */
retry:
key0 = (key & ~KEYC_XTERM); key0 = (key & ~KEYC_XTERM);
if ((key0 == (key_code)options_get_number(s->options, "prefix") || if ((key0 == (key_code)options_get_number(s->options, "prefix") ||
key0 == (key_code)options_get_number(s->options, "prefix2")) && key0 == (key_code)options_get_number(s->options, "prefix2")) &&
@@ -924,9 +926,9 @@ retry:
if (c->flags & CLIENT_REPEAT) if (c->flags & CLIENT_REPEAT)
log_debug("currently repeating"); log_debug("currently repeating");
try_again:
/* Try to see if there is a key binding in the current table. */ /* Try to see if there is a key binding in the current table. */
bd_find.key = key0; bd = key_bindings_get(table, key0);
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
if (bd != NULL) { if (bd != NULL) {
/* /*
* Key was matched in this table. If currently repeating but a * Key was matched in this table. If currently repeating but a
@@ -939,7 +941,7 @@ retry:
c->flags &= ~CLIENT_REPEAT; c->flags &= ~CLIENT_REPEAT;
server_status_client(c); server_status_client(c);
table = c->keytable; table = c->keytable;
goto retry; goto table_changed;
} }
log_debug("found in key table %s", table->name); log_debug("found in key table %s", table->name);
@@ -973,6 +975,14 @@ retry:
return; return;
} }
/*
* No match, try the ANY key.
*/
if (key0 != KEYC_ANY) {
key0 = KEYC_ANY;
goto try_again;
}
/* /*
* No match in this table. If not in the root table or if repeating, * No match in this table. If not in the root table or if repeating,
* switch the client back to the root table and try again. * switch the client back to the root table and try again.
@@ -984,7 +994,7 @@ retry:
c->flags &= ~CLIENT_REPEAT; c->flags &= ~CLIENT_REPEAT;
server_status_client(c); server_status_client(c);
table = c->keytable; table = c->keytable;
goto retry; goto table_changed;
} }
/* /*
@@ -997,7 +1007,7 @@ retry:
return; return;
} }
forward: forward_key:
if (c->flags & CLIENT_READONLY) if (c->flags & CLIENT_READONLY)
return; return;
if (wp != NULL) if (wp != NULL)
@@ -1158,10 +1168,6 @@ server_client_check_focus(struct window_pane *wp)
push = wp->flags & PANE_FOCUSPUSH; push = wp->flags & PANE_FOCUSPUSH;
wp->flags &= ~PANE_FOCUSPUSH; wp->flags &= ~PANE_FOCUSPUSH;
/* If we don't care about focus, forget it. */
if (!(wp->base.mode & MODE_FOCUSON))
return;
/* If we're not the active pane in our window, we're not focused. */ /* If we're not the active pane in our window, we're not focused. */
if (wp->window->active != wp) if (wp->window->active != wp)
goto not_focused; goto not_focused;
@@ -1185,14 +1191,20 @@ server_client_check_focus(struct window_pane *wp)
} }
not_focused: not_focused:
if (push || (wp->flags & PANE_FOCUSED)) if (push || (wp->flags & PANE_FOCUSED)) {
bufferevent_write(wp->event, "\033[O", 3); if (wp->base.mode & MODE_FOCUSON)
bufferevent_write(wp->event, "\033[O", 3);
notify_pane("pane-focus-out", wp);
}
wp->flags &= ~PANE_FOCUSED; wp->flags &= ~PANE_FOCUSED;
return; return;
focused: focused:
if (push || !(wp->flags & PANE_FOCUSED)) if (push || !(wp->flags & PANE_FOCUSED)) {
bufferevent_write(wp->event, "\033[I", 3); if (wp->base.mode & MODE_FOCUSON)
bufferevent_write(wp->event, "\033[I", 3);
notify_pane("pane-focus-in", wp);
}
wp->flags |= PANE_FOCUSED; wp->flags |= PANE_FOCUSED;
} }
@@ -1861,15 +1873,19 @@ server_client_add_message(struct client *c, const char *fmt, ...)
/* Get client working directory. */ /* Get client working directory. */
const char * const char *
server_client_get_cwd(struct client *c) server_client_get_cwd(struct client *c, struct session *s)
{ {
struct session *s; const char *home;
if (c != NULL && c->session == NULL && c->cwd != NULL) if (c != NULL && c->session == NULL && c->cwd != NULL)
return (c->cwd); return (c->cwd);
if (s != NULL && s->cwd != NULL)
return (s->cwd);
if (c != NULL && (s = c->session) != NULL && s->cwd != NULL) if (c != NULL && (s = c->session) != NULL && s->cwd != NULL)
return (s->cwd); return (s->cwd);
return ("."); if ((home = find_home()) != NULL)
return (home);
return ("/");
} }
/* Resolve an absolute path or relative to client working directory. */ /* Resolve an absolute path or relative to client working directory. */
@@ -1881,7 +1897,7 @@ server_client_get_path(struct client *c, const char *file)
if (*file == '/') if (*file == '/')
path = xstrdup(file); path = xstrdup(file);
else else
xasprintf(&path, "%s/%s", server_client_get_cwd(c), file); xasprintf(&path, "%s/%s", server_client_get_cwd(c, NULL), file);
if (realpath(path, resolved) == NULL) if (realpath(path, resolved) == NULL)
return (path); return (path);
free(path); free(path);

View File

@@ -175,6 +175,22 @@ server_lock_client(struct client *c)
proc_send(c->peer, MSG_LOCK, -1, cmd, strlen(cmd) + 1); proc_send(c->peer, MSG_LOCK, -1, cmd, strlen(cmd) + 1);
} }
void
server_kill_pane(struct window_pane *wp)
{
struct window *w = wp->window;
if (window_count_panes(w) == 1) {
server_kill_window(w);
recalculate_sizes();
} else {
server_unzoom_window(w);
layout_close_pane(wp);
window_remove_pane(w, wp);
server_redraw_window(w);
}
}
void void
server_kill_window(struct window *w) server_kill_window(struct window *w)
{ {

View File

@@ -201,7 +201,6 @@ server_start(struct tmuxproc *client, struct event_base *base, int lockfd,
RB_INIT(&all_window_panes); RB_INIT(&all_window_panes);
TAILQ_INIT(&clients); TAILQ_INIT(&clients);
RB_INIT(&sessions); RB_INIT(&sessions);
RB_INIT(&session_groups);
key_bindings_init(); key_bindings_init();
gettimeofday(&start_time, NULL); gettimeofday(&start_time, NULL);

View File

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

64
tmux.1
View File

@@ -855,6 +855,8 @@ the initial size is 80 x 24;
and and
.Fl y .Fl y
can be used to specify a different size. can be used to specify a different size.
.Ql -
uses the size of the current client if any.
.Pp .Pp
If run from a terminal, any If run from a terminal, any
.Xr termios 4 .Xr termios 4
@@ -966,7 +968,7 @@ show debugging information about jobs and terminals.
Execute commands from Execute commands from
.Ar path .Ar path
(which may be a (which may be a
.Xr glob 3 .Xr glob 7
pattern). pattern).
If If
.Fl q .Fl q
@@ -1463,6 +1465,8 @@ The following keys may be used in tree mode:
.It Li "Enter" Ta "Choose selected item" .It Li "Enter" Ta "Choose selected item"
.It Li "Up" Ta "Select previous item" .It Li "Up" Ta "Select previous item"
.It Li "Down" Ta "Select next item" .It Li "Down" Ta "Select next item"
.It Li "x" Ta "Kill selected item"
.It Li "X" Ta "Kill tagged items"
.It Li "<" Ta "Scroll list of previews left" .It Li "<" Ta "Scroll list of previews left"
.It Li ">" Ta "Scroll list of previews right" .It Li ">" Ta "Scroll list of previews right"
.It Li "C-s" Ta "Search by name" .It Li "C-s" Ta "Search by name"
@@ -2753,8 +2757,7 @@ to
from the 256-colour set, from the 256-colour set,
.Ic default , .Ic default ,
or a hexadecimal RGB string such as or a hexadecimal RGB string such as
.Ql #ffffff , .Ql #ffffff .
which chooses the closest match from the default 256-colour set.
.Pp .Pp
The attributes is either The attributes is either
.Ic none .Ic none
@@ -3424,6 +3427,14 @@ Run when the program running in a pane exits, but
is on so the pane has not closed. is on so the pane has not closed.
.It pane-exited .It pane-exited
Run when the program running in a pane exits. Run when the program running in a pane exits.
.It pane-focus-in
Run when the focus enters a pane, if the
.Ic focus-events
option is on.
.It pane-focus-out
Run when the focus exits a pane, if the
.Ic focus-events
option is on.
.It pane-set-clipboard .It pane-set-clipboard
Run when the terminal clipboard is set using the Run when the terminal clipboard is set using the
.Xr xterm 1 .Xr xterm 1
@@ -3445,12 +3456,14 @@ Run when a window is unlinked from a session.
Hooks are managed with these commands: Hooks are managed with these commands:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Xo Ic set-hook .It Xo Ic set-hook
.Op Fl gu .Op Fl gRu
.Op Fl t Ar target-session .Op Fl t Ar target-session
.Ar hook-name .Ar hook-name
.Ar command .Ar command
.Xc .Xc
Sets (or with Without
.Fl R ,
sets (or with
.Fl u .Fl u
unsets) hook unsets) hook
.Ar hook-name .Ar hook-name
@@ -3466,6 +3479,12 @@ hooks (for
with with
.Fl t ) . .Fl t ) .
Like options, session hooks inherit from the global ones. Like options, session hooks inherit from the global ones.
.Pp
With
.Fl R ,
run
.Ar hook-name
immediately.
.It Xo Ic show-hooks .It Xo Ic show-hooks
.Op Fl g .Op Fl g
.Op Fl t Ar target-session .Op Fl t Ar target-session
@@ -3545,11 +3564,17 @@ The possible variables are listed in the table below, or the name of a
.Nm .Nm
option may be used for an option's value. option may be used for an option's value.
Some variables have a shorter alias such as Some variables have a shorter alias such as
.Ql #S , .Ql #S ;
and
.Ql ## .Ql ##
is replaced by a single is replaced by a single
.Ql # . .Ql # ,
.Ql #,
by a
.Ql \&,
and
.Ql #}
by a
.Ql } .
.Pp .Pp
Conditionals are available by prefixing with Conditionals are available by prefixing with
.Ql \&? .Ql \&?
@@ -3571,6 +3596,22 @@ if
is enabled, or is enabled, or
.Ql no .Ql no
if not. if not.
Conditionals can be nested arbitrarily.
Inside a conditional,
.Ql \&,
and
.Ql }
must be escaped as
.Ql #,
and
.Ql #} ,
unless they are part of a
.Ql #{...}
replacement.
For example:
.Bd -literal -offset indent
#{?pane_in_mode,#[fg=white#,bg=red],#[fg=red#,bg=white]}#W .
.Ed
.Pp .Pp
Comparisons may be expressed by prefixing two comma-separated Comparisons may be expressed by prefixing two comma-separated
alternatives by alternatives by
@@ -3598,7 +3639,7 @@ and
.Ql && .Ql &&
evaluate to true if either or both of two comma-separated alternatives are evaluate to true if either or both of two comma-separated alternatives are
true, for example true, for example
.Ql #{||,#{pane_in_mode},#{alternate_on}} . .Ql #{||:#{pane_in_mode},#{alternate_on}} .
A A
.Ql C .Ql C
performs a search for an performs a search for an
@@ -3745,6 +3786,7 @@ The following variables are available, where appropriate:
.It Li "pane_tty" Ta "" Ta "Pseudo terminal of pane" .It Li "pane_tty" Ta "" Ta "Pseudo terminal of pane"
.It Li "pane_width" Ta "" Ta "Width of pane" .It Li "pane_width" Ta "" Ta "Width of pane"
.It Li "pid" Ta "" Ta "Server PID" .It Li "pid" Ta "" Ta "Server PID"
.It Li "rectangle_toggle" Ta "" Ta "1 if rectangle selection is activated"
.It Li "scroll_region_lower" Ta "" Ta "Bottom of scroll region in pane" .It Li "scroll_region_lower" Ta "" Ta "Bottom of scroll region in pane"
.It Li "scroll_region_upper" Ta "" Ta "Top of scroll region in pane" .It Li "scroll_region_upper" Ta "" Ta "Top of scroll region in pane"
.It Li "scroll_position" Ta "" Ta "Scroll position in copy mode" .It Li "scroll_position" Ta "" Ta "Scroll position in copy mode"
@@ -3826,7 +3868,9 @@ for
or or
.Ic new-session ) . .Ic new-session ) .
.It .It
An escape sequence: An escape sequence (if the
.Ic allow-rename
option is turned on):
.Bd -literal -offset indent .Bd -literal -offset indent
$ printf '\e033kWINDOW_NAME\e033\e\e' $ printf '\e033kWINDOW_NAME\e033\e\e'
.Ed .Ed

109
tmux.h
View File

@@ -19,8 +19,6 @@
#ifndef TMUX_H #ifndef TMUX_H
#define TMUX_H #define TMUX_H
#define PROTOCOL_VERSION 8
#include <sys/time.h> #include <sys/time.h>
#include <sys/uio.h> #include <sys/uio.h>
@@ -56,6 +54,9 @@ struct session;
struct tmuxpeer; struct tmuxpeer;
struct tmuxproc; struct tmuxproc;
/* Client-server protocol version. */
#define PROTOCOL_VERSION 8
/* Default global configuration file. */ /* Default global configuration file. */
#ifndef TMUX_CONF #ifndef TMUX_CONF
#define TMUX_CONF "/etc/tmux.conf" #define TMUX_CONF "/etc/tmux.conf"
@@ -140,6 +141,9 @@ enum {
KEYC_FOCUS_IN = KEYC_BASE, KEYC_FOCUS_IN = KEYC_BASE,
KEYC_FOCUS_OUT, KEYC_FOCUS_OUT,
/* "Any" key, used if not found in key table. */
KEYC_ANY,
/* Paste brackets. */ /* Paste brackets. */
KEYC_PASTE_START, KEYC_PASTE_START,
KEYC_PASTE_END, KEYC_PASTE_END,
@@ -511,10 +515,11 @@ struct msg_stderr_data {
#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL) #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
/* /*
* A single UTF-8 character. UTF8_SIZE must be big enough to hold at least one * A single UTF-8 character. UTF8_SIZE must be big enough to hold
* combining character as well. * combining characters as well, currently at most five (of three
* bytes) are supported.
*/ */
#define UTF8_SIZE 9 #define UTF8_SIZE 18
struct utf8_data { struct utf8_data {
u_char data[UTF8_SIZE]; u_char data[UTF8_SIZE];
@@ -645,30 +650,8 @@ struct job {
}; };
LIST_HEAD(joblist, job); LIST_HEAD(joblist, job);
/* Screen selection. */
struct screen_sel {
int flag;
int hidden;
int rectflag;
enum {
LINE_SEL_NONE,
LINE_SEL_LEFT_RIGHT,
LINE_SEL_RIGHT_LEFT,
} lineflag;
int modekeys;
u_int sx;
u_int sy;
u_int ex;
u_int ey;
struct grid_cell cell;
};
/* Virtual screen. */ /* Virtual screen. */
struct screen_sel;
struct screen_titles; struct screen_titles;
struct screen { struct screen {
char *title; char *title;
@@ -689,7 +672,7 @@ struct screen {
bitstr_t *tabs; bitstr_t *tabs;
struct screen_sel sel; struct screen_sel *sel;
}; };
/* Screen write context. */ /* Screen write context. */
@@ -736,28 +719,6 @@ struct window_mode {
}; };
#define WINDOW_MODE_TIMEOUT 180 #define WINDOW_MODE_TIMEOUT 180
/* Structures for choose mode. */
struct window_choose_data {
struct client *start_client;
struct session *start_session;
u_int idx;
int type;
#define TREE_OTHER 0x0
#define TREE_WINDOW 0x1
#define TREE_SESSION 0x2
struct session *tree_session; /* session of items in tree */
struct winlink *wl;
int pane_id;
char *ft_template;
struct format_tree *ft;
char *command;
};
/* Child window structure. */ /* Child window structure. */
struct window_pane { struct window_pane {
u_int id; u_int id;
@@ -866,12 +827,11 @@ struct window {
int flags; int flags;
#define WINDOW_BELL 0x1 #define WINDOW_BELL 0x1
#define WINDOW_ACTIVITY 0x2 #define WINDOW_ACTIVITY 0x2
/* 0x4 unused */ #define WINDOW_SILENCE 0x4
#define WINDOW_SILENCE 0x8 #define WINDOW_ZOOMED 0x8
#define WINDOW_ZOOMED 0x1000 #define WINDOW_FORCEWIDTH 0x10
#define WINDOW_FORCEWIDTH 0x2000 #define WINDOW_FORCEHEIGHT 0x20
#define WINDOW_FORCEHEIGHT 0x4000 #define WINDOW_STYLECHANGED 0x40
#define WINDOW_STYLECHANGED 0x8000
#define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE) #define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE)
int alerts_queued; int alerts_queued;
@@ -1402,6 +1362,7 @@ struct client {
void (*identify_callback)(struct client *, void (*identify_callback)(struct client *,
struct window_pane *); struct window_pane *);
void *identify_callback_data; void *identify_callback_data;
struct cmdq_item *identify_callback_item;
char *message_string; char *message_string;
struct event message_timer; struct event message_timer;
@@ -1447,7 +1408,7 @@ struct key_binding {
RB_HEAD(key_bindings, key_binding); RB_HEAD(key_bindings, key_binding);
struct key_table { struct key_table {
const char *name; const char *name;
struct key_bindings key_bindings; struct key_bindings key_bindings;
u_int references; u_int references;
@@ -1468,6 +1429,7 @@ enum options_table_type {
OPTIONS_TABLE_STYLE, OPTIONS_TABLE_STYLE,
OPTIONS_TABLE_ARRAY, OPTIONS_TABLE_ARRAY,
}; };
enum options_table_scope { enum options_table_scope {
OPTIONS_TABLE_NONE, OPTIONS_TABLE_NONE,
OPTIONS_TABLE_SERVER, OPTIONS_TABLE_SERVER,
@@ -1598,6 +1560,7 @@ void printflike(4, 5) hooks_insert(struct hooks *, struct cmdq_item *,
struct cmd_find_state *, const char *, ...); struct cmd_find_state *, const char *, ...);
/* notify.c */ /* notify.c */
void notify_hook(struct cmdq_item *, const char *);
void notify_input(struct window_pane *, struct evbuffer *); void notify_input(struct window_pane *, struct evbuffer *);
void notify_client(const char *, struct client *); void notify_client(const char *, struct client *);
void notify_session(const char *, struct session *); void notify_session(const char *, struct session *);
@@ -1776,13 +1739,13 @@ long long args_strtonum(struct args *, u_char, long long, long long,
/* cmd-find.c */ /* cmd-find.c */
int cmd_find_target(struct cmd_find_state *, struct cmdq_item *, int cmd_find_target(struct cmd_find_state *, struct cmdq_item *,
const char *, enum cmd_find_type, int); const char *, enum cmd_find_type, int);
struct client *cmd_find_best_client(struct session *);
struct client *cmd_find_client(struct cmdq_item *, const char *, int); struct client *cmd_find_client(struct cmdq_item *, const char *, int);
void cmd_find_clear_state(struct cmd_find_state *, int); void cmd_find_clear_state(struct cmd_find_state *, int);
int cmd_find_empty_state(struct cmd_find_state *); int cmd_find_empty_state(struct cmd_find_state *);
int cmd_find_valid_state(struct cmd_find_state *); int cmd_find_valid_state(struct cmd_find_state *);
void cmd_find_copy_state(struct cmd_find_state *, void cmd_find_copy_state(struct cmd_find_state *,
struct cmd_find_state *); struct cmd_find_state *);
void cmd_find_log_state(const char *, struct cmd_find_state *);
void cmd_find_from_session(struct cmd_find_state *, void cmd_find_from_session(struct cmd_find_state *,
struct session *, int); struct session *, int);
void cmd_find_from_winlink(struct cmd_find_state *, void cmd_find_from_winlink(struct cmd_find_state *,
@@ -1802,6 +1765,7 @@ int cmd_find_from_mouse(struct cmd_find_state *,
int cmd_find_from_nothing(struct cmd_find_state *, int); int cmd_find_from_nothing(struct cmd_find_state *, int);
/* cmd.c */ /* cmd.c */
void cmd_log_argv(int, char **, const char *);
int cmd_pack_argv(int, char **, char *, size_t); int cmd_pack_argv(int, char **, char *, size_t);
int cmd_unpack_argv(char *, size_t, int, char ***); int cmd_unpack_argv(char *, size_t, int, char ***);
char **cmd_copy_argv(int, char **); char **cmd_copy_argv(int, char **);
@@ -1851,13 +1815,13 @@ void cmd_wait_for_flush(void);
int client_main(struct event_base *, int, char **, int); int client_main(struct event_base *, int, char **, int);
/* key-bindings.c */ /* key-bindings.c */
RB_PROTOTYPE(key_bindings, key_binding, entry, key_bindings_cmp);
RB_PROTOTYPE(key_tables, key_table, entry, key_table_cmp);
extern struct key_tables key_tables;
int key_table_cmp(struct key_table *, struct key_table *);
int key_bindings_cmp(struct key_binding *, struct key_binding *);
struct key_table *key_bindings_get_table(const char *, int); struct key_table *key_bindings_get_table(const char *, int);
struct key_table *key_bindings_first_table(void);
struct key_table *key_bindings_next_table(struct key_table *);
void key_bindings_unref_table(struct key_table *); void key_bindings_unref_table(struct key_table *);
struct key_binding *key_bindings_get(struct key_table *, key_code);
struct key_binding *key_bindings_first(struct key_table *);
struct key_binding *key_bindings_next(struct key_table *, struct key_binding *);
void key_bindings_add(const char *, key_code, int, struct cmd_list *); void key_bindings_add(const char *, key_code, int, struct cmd_list *);
void key_bindings_remove(const char *, key_code); void key_bindings_remove(const char *, key_code);
void key_bindings_remove_table(const char *); void key_bindings_remove_table(const char *);
@@ -1891,7 +1855,6 @@ void server_add_accept(int);
/* server-client.c */ /* server-client.c */
u_int server_client_how_many(void); u_int server_client_how_many(void);
void server_client_set_identify(struct client *, u_int); void server_client_set_identify(struct client *, u_int);
void server_client_clear_identify(struct client *, struct window_pane *);
void server_client_set_key_table(struct client *, const char *); void server_client_set_key_table(struct client *, const char *);
const char *server_client_get_key_table(struct client *); const char *server_client_get_key_table(struct client *);
int server_client_check_nested(struct client *); int server_client_check_nested(struct client *);
@@ -1909,7 +1872,7 @@ void server_client_push_stderr(struct client *);
void printflike(2, 3) server_client_add_message(struct client *, const char *, void printflike(2, 3) server_client_add_message(struct client *, const char *,
...); ...);
char *server_client_get_path(struct client *, const char *); char *server_client_get_path(struct client *, const char *);
const char *server_client_get_cwd(struct client *); const char *server_client_get_cwd(struct client *, struct session *);
/* server-fn.c */ /* server-fn.c */
void server_redraw_client(struct client *); void server_redraw_client(struct client *);
@@ -1924,6 +1887,7 @@ void server_status_window(struct window *);
void server_lock(void); void server_lock(void);
void server_lock_session(struct session *); void server_lock_session(struct session *);
void server_lock_client(struct client *); void server_lock_client(struct client *);
void server_kill_pane(struct window_pane *);
void server_kill_window(struct window *); void server_kill_window(struct window *);
int server_link_window(struct session *, int server_link_window(struct session *,
struct winlink *, struct session *, int, int, int, char **); struct winlink *, struct session *, int, int, int, char **);
@@ -2008,6 +1972,8 @@ char *grid_string_cells(struct grid *, u_int, u_int, u_int,
void grid_duplicate_lines(struct grid *, u_int, struct grid *, u_int, void grid_duplicate_lines(struct grid *, u_int, struct grid *, u_int,
u_int); u_int);
void grid_reflow(struct grid *, u_int, u_int *); void grid_reflow(struct grid *, u_int, u_int *);
struct grid_line *grid_get_line(struct grid *, u_int);
void grid_adjust_lines(struct grid *, u_int);
/* grid-view.c */ /* grid-view.c */
void grid_view_get_cell(struct grid *, u_int, u_int, struct grid_cell *); void grid_view_get_cell(struct grid *, u_int, u_int, struct grid_cell *);
@@ -2104,8 +2070,8 @@ void screen_set_title(struct screen *, const char *);
void screen_push_title(struct screen *); void screen_push_title(struct screen *);
void screen_pop_title(struct screen *); void screen_pop_title(struct screen *);
void screen_resize(struct screen *, u_int, u_int, int); void screen_resize(struct screen *, u_int, u_int, int);
void screen_set_selection(struct screen *, void screen_set_selection(struct screen *, u_int, u_int, u_int, u_int,
u_int, u_int, u_int, u_int, u_int, struct grid_cell *); u_int, int, struct grid_cell *);
void screen_clear_selection(struct screen *); void screen_clear_selection(struct screen *);
void screen_hide_selection(struct screen *); void screen_hide_selection(struct screen *);
int screen_check_selection(struct screen *, u_int, u_int); int screen_check_selection(struct screen *, u_int, u_int);
@@ -2205,6 +2171,9 @@ void layout_free_cell(struct layout_cell *);
void layout_print_cell(struct layout_cell *, const char *, u_int); void layout_print_cell(struct layout_cell *, const char *, u_int);
void layout_destroy_cell(struct window *, struct layout_cell *, void layout_destroy_cell(struct window *, struct layout_cell *,
struct layout_cell **); struct layout_cell **);
void layout_resize_layout(struct window *, struct layout_cell *,
enum layout_type, int, int);
struct layout_cell *layout_search_by_border(struct layout_cell *, u_int, u_int);
void layout_set_size(struct layout_cell *, u_int, u_int, u_int, void layout_set_size(struct layout_cell *, u_int, u_int, u_int,
u_int); u_int);
void layout_make_leaf(struct layout_cell *, struct window_pane *); void layout_make_leaf(struct layout_cell *, struct window_pane *);
@@ -2249,7 +2218,6 @@ void mode_tree_expand_current(struct mode_tree_data *);
void mode_tree_set_current(struct mode_tree_data *, uint64_t); void mode_tree_set_current(struct mode_tree_data *, uint64_t);
void mode_tree_each_tagged(struct mode_tree_data *, mode_tree_each_cb, void mode_tree_each_tagged(struct mode_tree_data *, mode_tree_each_cb,
struct client *, key_code, int); struct client *, key_code, int);
void mode_tree_up(struct mode_tree_data *, int);
void mode_tree_down(struct mode_tree_data *, int); void mode_tree_down(struct mode_tree_data *, int);
struct mode_tree_data *mode_tree_start(struct window_pane *, struct args *, struct mode_tree_data *mode_tree_start(struct window_pane *, struct args *,
mode_tree_build_cb, mode_tree_draw_cb, mode_tree_search_cb, mode_tree_build_cb, mode_tree_draw_cb, mode_tree_search_cb,
@@ -2319,11 +2287,8 @@ void control_notify_session_window_changed(struct session *);
/* session.c */ /* session.c */
extern struct sessions sessions; extern struct sessions sessions;
extern struct session_groups session_groups;
int session_cmp(struct session *, struct session *); int session_cmp(struct session *, struct session *);
RB_PROTOTYPE(sessions, session, entry, session_cmp); RB_PROTOTYPE(sessions, session, entry, session_cmp);
int session_group_cmp(struct session_group *, struct session_group *);
RB_PROTOTYPE(session_groups, session_group, entry, session_group_cmp);
int session_alive(struct session *); int session_alive(struct session *);
struct session *session_find(const char *); struct session *session_find(const char *);
struct session *session_find_by_id_str(const char *); struct session *session_find_by_id_str(const char *);

View File

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

View File

@@ -494,8 +494,9 @@ tty_term_find(char *name, int fd, char **cause)
goto error; goto error;
} }
/* Figure out if we have 256. */ /* Figure out if we have 256 colours (or more). */
if (tty_term_number(term, TTYC_COLORS) == 256) if (tty_term_number(term, TTYC_COLORS) >= 256 ||
tty_term_has(term, TTYC_RGB))
term->flags |= TERM_256COLOURS; term->flags |= TERM_256COLOURS;
/* /*

41
tty.c
View File

@@ -913,6 +913,7 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
int flags, cleared = 0; int flags, cleared = 0;
char buf[512]; char buf[512];
size_t len, old_len; size_t len, old_len;
u_int cellsize;
flags = (tty->flags & TTY_NOCURSOR); flags = (tty->flags & TTY_NOCURSOR);
tty->flags |= TTY_NOCURSOR; tty->flags |= TTY_NOCURSOR;
@@ -926,15 +927,17 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
* there may be empty background cells after it (from BCE). * there may be empty background cells after it (from BCE).
*/ */
sx = screen_size_x(s); sx = screen_size_x(s);
if (sx > gd->linedata[gd->hsize + py].cellsize)
sx = gd->linedata[gd->hsize + py].cellsize; cellsize = grid_get_line(gd, gd->hsize + py)->cellsize;
if (sx > cellsize)
sx = cellsize;
if (sx > tty->sx) if (sx > tty->sx)
sx = tty->sx; sx = tty->sx;
ux = 0; ux = 0;
if (wp == NULL || if (wp == NULL ||
py == 0 || py == 0 ||
(~gd->linedata[gd->hsize + py - 1].flags & GRID_LINE_WRAPPED) || (~grid_get_line(gd, gd->hsize + py - 1)->flags & GRID_LINE_WRAPPED) ||
ox != 0 || ox != 0 ||
tty->cx < tty->sx || tty->cx < tty->sx ||
screen_size_x(s) < tty->sx) { screen_size_x(s) < tty->sx) {
@@ -1244,13 +1247,18 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
tty_margin_pane(tty, ctx); tty_margin_pane(tty, ctx);
/* /*
* If we want to wrap a pane, the cursor needs to be exactly on the * If we want to wrap a pane while using margins, the cursor needs to
* right of the region. But if the pane isn't on the right, it may be * be exactly on the right of the region. If the cursor is entirely off
* off the edge - if so, move the cursor back to the right. * the edge - move it back to the right. Some terminals are funny about
* this and insert extra spaces, so only use the right if margins are
* enabled.
*/ */
if (ctx->xoff + ctx->ocx > tty->rright) if (ctx->xoff + ctx->ocx > tty->rright) {
tty_cursor(tty, tty->rright, ctx->yoff + ctx->ocy); if (!tty_use_margin(tty))
else tty_cursor(tty, 0, ctx->yoff + ctx->ocy);
else
tty_cursor(tty, tty->rright, ctx->yoff + ctx->ocy);
} else
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
tty_putc(tty, '\n'); tty_putc(tty, '\n');
@@ -1275,11 +1283,16 @@ tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx)
tty_margin_pane(tty, ctx); tty_margin_pane(tty, ctx);
if (ctx->num == 1 || !tty_term_has(tty->term, TTYC_INDN)) { if (ctx->num == 1 || !tty_term_has(tty->term, TTYC_INDN)) {
tty_cursor(tty, tty->rright, tty->rlower); if (!tty_use_margin(tty))
tty_cursor(tty, 0, tty->rlower);
else
tty_cursor(tty, tty->rright, tty->rlower);
for (i = 0; i < ctx->num; i++) for (i = 0; i < ctx->num; i++)
tty_putc(tty, '\n'); tty_putc(tty, '\n');
} else } else {
tty_cursor(tty, 0, tty->cy);
tty_putcode1(tty, TTYC_INDN, ctx->num); tty_putcode1(tty, TTYC_INDN, ctx->num);
}
} }
void void
@@ -1990,8 +2003,7 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc)
char s[32]; char s[32];
/* Is this a 24-bit or 256-colour colour? */ /* Is this a 24-bit or 256-colour colour? */
if (gc->fg & COLOUR_FLAG_RGB || if (gc->fg & COLOUR_FLAG_RGB || gc->fg & COLOUR_FLAG_256) {
gc->fg & COLOUR_FLAG_256) {
if (tty_try_colour(tty, gc->fg, "38") == 0) if (tty_try_colour(tty, gc->fg, "38") == 0)
goto save_fg; goto save_fg;
/* Should not get here, already converted in tty_check_fg. */ /* Should not get here, already converted in tty_check_fg. */
@@ -2020,8 +2032,7 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc)
char s[32]; char s[32];
/* Is this a 24-bit or 256-colour colour? */ /* Is this a 24-bit or 256-colour colour? */
if (gc->bg & COLOUR_FLAG_RGB || if (gc->bg & COLOUR_FLAG_RGB || gc->bg & COLOUR_FLAG_256) {
gc->bg & COLOUR_FLAG_256) {
if (tty_try_colour(tty, gc->bg, "48") == 0) if (tty_try_colour(tty, gc->bg, "48") == 0)
goto save_bg; goto save_bg;
/* Should not get here, already converted in tty_check_bg. */ /* Should not get here, already converted in tty_check_bg. */

View File

@@ -65,8 +65,9 @@ static void window_copy_update_cursor(struct window_pane *, u_int, u_int);
static void window_copy_start_selection(struct window_pane *); static void window_copy_start_selection(struct window_pane *);
static int window_copy_adjust_selection(struct window_pane *, u_int *, static int window_copy_adjust_selection(struct window_pane *, u_int *,
u_int *); u_int *);
static int window_copy_set_selection(struct window_pane *, int);
static int window_copy_update_selection(struct window_pane *, int); static int window_copy_update_selection(struct window_pane *, int);
static void window_copy_synchronize_cursor(struct window_pane *wp); static void window_copy_synchronize_cursor(struct window_pane *);
static void *window_copy_get_selection(struct window_pane *, size_t *); static void *window_copy_get_selection(struct window_pane *, size_t *);
static void window_copy_copy_buffer(struct window_pane *, const char *, static void window_copy_copy_buffer(struct window_pane *, const char *,
void *, size_t); void *, size_t);
@@ -151,12 +152,12 @@ struct window_copy_mode_data {
struct screen *backing; struct screen *backing;
int backing_written; /* backing display started */ int backing_written; /* backing display started */
u_int oy; /* number of lines scrolled up */ u_int oy; /* number of lines scrolled up */
u_int selx; /* beginning of selection */ u_int selx; /* beginning of selection */
u_int sely; u_int sely;
u_int endselx; /* end of selection */ u_int endselx; /* end of selection */
u_int endsely; u_int endsely;
enum { enum {
@@ -165,14 +166,20 @@ struct window_copy_mode_data {
CURSORDRAG_SEL, /* start is synchronized with cursor */ CURSORDRAG_SEL, /* start is synchronized with cursor */
} cursordrag; } cursordrag;
int modekeys;
enum {
LINE_SEL_NONE,
LINE_SEL_LEFT_RIGHT,
LINE_SEL_RIGHT_LEFT,
} lineflag; /* line selection mode */
int rectflag; /* in rectangle copy mode? */ int rectflag; /* in rectangle copy mode? */
int scroll_exit; /* exit on scroll to end? */ int scroll_exit; /* exit on scroll to end? */
u_int cx; u_int cx;
u_int cy; u_int cy;
u_int lastcx; /* position in last line w/ content */ u_int lastcx; /* position in last line w/ content */
u_int lastsx; /* size of last line w/ content */ u_int lastsx; /* size of last line w/ content */
int searchtype; int searchtype;
char *searchstr; char *searchstr;
@@ -194,21 +201,10 @@ window_copy_init(struct window_pane *wp, __unused struct cmd_find_state *fs,
struct window_copy_mode_data *data; struct window_copy_mode_data *data;
struct screen *s; struct screen *s;
wp->modedata = data = xmalloc(sizeof *data); wp->modedata = data = xcalloc(1, sizeof *data);
data->oy = 0;
data->cx = 0;
data->cy = 0;
data->cursordrag = CURSORDRAG_NONE; data->cursordrag = CURSORDRAG_NONE;
data->lineflag = LINE_SEL_NONE;
data->lastcx = 0;
data->lastsx = 0;
data->backing_written = 0;
data->rectflag = 0;
data->scroll_exit = 0;
if (wp->searchstr != NULL) { if (wp->searchstr != NULL) {
data->searchtype = WINDOW_COPY_SEARCHUP; data->searchtype = WINDOW_COPY_SEARCHUP;
@@ -228,7 +224,7 @@ window_copy_init(struct window_pane *wp, __unused struct cmd_find_state *fs,
s = &data->screen; s = &data->screen;
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
s->sel.modekeys = options_get_number(wp->window->options, "mode-keys"); data->modekeys = options_get_number(wp->window->options, "mode-keys");
data->backing = NULL; data->backing = NULL;
@@ -357,7 +353,7 @@ window_copy_pageup(struct window_pane *wp, int half_page)
oy = screen_hsize(data->backing) + data->cy - data->oy; oy = screen_hsize(data->backing) + data->cy - data->oy;
ox = window_copy_find_length(wp, oy); ox = window_copy_find_length(wp, oy);
if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely) if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
window_copy_other_end(wp); window_copy_other_end(wp);
if (data->cx != ox) { if (data->cx != ox) {
@@ -379,7 +375,7 @@ window_copy_pageup(struct window_pane *wp, int half_page)
else else
data->oy += n; data->oy += n;
if (!data->screen.sel.flag || !data->rectflag) { if (data->screen.sel == NULL || !data->rectflag) {
py = screen_hsize(data->backing) + data->cy - data->oy; py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py); px = window_copy_find_length(wp, py);
if ((data->cx >= data->lastsx && data->cx != px) || if ((data->cx >= data->lastsx && data->cx != px) ||
@@ -401,7 +397,7 @@ window_copy_pagedown(struct window_pane *wp, int half_page, int scroll_exit)
oy = screen_hsize(data->backing) + data->cy - data->oy; oy = screen_hsize(data->backing) + data->cy - data->oy;
ox = window_copy_find_length(wp, oy); ox = window_copy_find_length(wp, oy);
if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT && oy == data->sely) if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->sely)
window_copy_other_end(wp); window_copy_other_end(wp);
if (data->cx != ox) { if (data->cx != ox) {
@@ -423,7 +419,7 @@ window_copy_pagedown(struct window_pane *wp, int half_page, int scroll_exit)
else else
data->oy -= n; data->oy -= n;
if (!data->screen.sel.flag || !data->rectflag) { if (data->screen.sel == NULL || !data->rectflag) {
py = screen_hsize(data->backing) + data->cy - data->oy; py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py); px = window_copy_find_length(wp, py);
if ((data->cx >= data->lastsx && data->cx != px) || if ((data->cx >= data->lastsx && data->cx != px) ||
@@ -554,7 +550,7 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
if (m != NULL) if (m != NULL)
window_copy_start_drag(c, m); window_copy_start_drag(c, m);
else { else {
sn->sel.lineflag = LINE_SEL_NONE; data->lineflag = LINE_SEL_NONE;
window_copy_start_selection(wp); window_copy_start_selection(wp);
redraw = 1; redraw = 1;
} }
@@ -763,7 +759,7 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
window_copy_cursor_previous_word(wp, ws); window_copy_cursor_previous_word(wp, ws);
} }
if (strcmp(command, "rectangle-toggle") == 0) { if (strcmp(command, "rectangle-toggle") == 0) {
sn->sel.lineflag = LINE_SEL_NONE; data->lineflag = LINE_SEL_NONE;
window_copy_rectangle_toggle(wp); window_copy_rectangle_toggle(wp);
} }
if (strcmp(command, "scroll-down") == 0 || if (strcmp(command, "scroll-down") == 0 ||
@@ -800,7 +796,7 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
} }
} }
if (strcmp(command, "select-line") == 0) { if (strcmp(command, "select-line") == 0) {
sn->sel.lineflag = LINE_SEL_LEFT_RIGHT; data->lineflag = LINE_SEL_LEFT_RIGHT;
data->rectflag = 0; data->rectflag = 0;
window_copy_cursor_start_of_line(wp); window_copy_cursor_start_of_line(wp);
window_copy_start_selection(wp); window_copy_start_selection(wp);
@@ -810,7 +806,7 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
redraw = 1; redraw = 1;
} }
if (strcmp(command, "select-word") == 0) { if (strcmp(command, "select-word") == 0) {
sn->sel.lineflag = LINE_SEL_LEFT_RIGHT; data->lineflag = LINE_SEL_LEFT_RIGHT;
data->rectflag = 0; data->rectflag = 0;
ws = options_get_string(s->options, "word-separators"); ws = options_get_string(s->options, "word-separators");
window_copy_cursor_previous_word(wp, ws); window_copy_cursor_previous_word(wp, ws);
@@ -1434,7 +1430,6 @@ static void
window_copy_start_selection(struct window_pane *wp) window_copy_start_selection(struct window_pane *wp)
{ {
struct window_copy_mode_data *data = wp->modedata; struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
data->selx = data->cx; data->selx = data->cx;
data->sely = screen_hsize(data->backing) + data->cy - data->oy; data->sely = screen_hsize(data->backing) + data->cy - data->oy;
@@ -1444,8 +1439,7 @@ window_copy_start_selection(struct window_pane *wp)
data->cursordrag = CURSORDRAG_ENDSEL; data->cursordrag = CURSORDRAG_ENDSEL;
s->sel.flag = 1; window_copy_set_selection(wp, 1);
window_copy_update_selection(wp, 1);
} }
static int static int
@@ -1482,6 +1476,17 @@ window_copy_adjust_selection(struct window_pane *wp, u_int *selx, u_int *sely)
static int static int
window_copy_update_selection(struct window_pane *wp, int may_redraw) window_copy_update_selection(struct window_pane *wp, int may_redraw)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
return (0);
return (window_copy_set_selection(wp, may_redraw));
}
static int
window_copy_set_selection(struct window_pane *wp, int may_redraw)
{ {
struct window_copy_mode_data *data = wp->modedata; struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen; struct screen *s = &data->screen;
@@ -1490,9 +1495,6 @@ window_copy_update_selection(struct window_pane *wp, int may_redraw)
u_int sx, sy, cy, endsx, endsy; u_int sx, sy, cy, endsx, endsy;
int startrelpos, endrelpos; int startrelpos, endrelpos;
if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE)
return (0);
window_copy_synchronize_cursor(wp); window_copy_synchronize_cursor(wp);
/* Adjust the selection. */ /* Adjust the selection. */
@@ -1515,7 +1517,8 @@ window_copy_update_selection(struct window_pane *wp, int may_redraw)
/* Set colours and selection. */ /* Set colours and selection. */
style_apply(&gc, oo, "mode-style"); style_apply(&gc, oo, "mode-style");
gc.flags |= GRID_FLAG_NOPALETTE; gc.flags |= GRID_FLAG_NOPALETTE;
screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag, &gc); screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag,
data->modekeys, &gc);
if (data->rectflag && may_redraw) { if (data->rectflag && may_redraw) {
/* /*
@@ -1548,10 +1551,10 @@ window_copy_get_selection(struct window_pane *wp, size_t *len)
char *buf; char *buf;
size_t off; size_t off;
u_int i, xx, yy, sx, sy, ex, ey, ey_last; u_int i, xx, yy, sx, sy, ex, ey, ey_last;
u_int firstsx, lastex, restex, restsx; u_int firstsx, lastex, restex, restsx, selx;
int keys; int keys;
if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE) if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE)
return (NULL); return (NULL);
buf = xmalloc(1); buf = xmalloc(1);
@@ -1599,7 +1602,11 @@ window_copy_get_selection(struct window_pane *wp, size_t *len)
* Need to ignore the column with the cursor in it, which for * Need to ignore the column with the cursor in it, which for
* rectangular copy means knowing which side the cursor is on. * rectangular copy means knowing which side the cursor is on.
*/ */
if (data->selx < data->cx) { if (data->cursordrag == CURSORDRAG_ENDSEL)
selx = data->selx;
else
selx = data->endselx;
if (selx < data->cx) {
/* Selection start is on the left. */ /* Selection start is on the left. */
if (keys == MODEKEY_EMACS) { if (keys == MODEKEY_EMACS) {
lastex = data->cx; lastex = data->cx;
@@ -1609,12 +1616,12 @@ window_copy_get_selection(struct window_pane *wp, size_t *len)
lastex = data->cx + 1; lastex = data->cx + 1;
restex = data->cx + 1; restex = data->cx + 1;
} }
firstsx = data->selx; firstsx = selx;
restsx = data->selx; restsx = selx;
} else { } else {
/* Cursor is on the left. */ /* Cursor is on the left. */
lastex = data->selx + 1; lastex = selx + 1;
restex = data->selx + 1; restex = selx + 1;
firstsx = data->cx; firstsx = data->cx;
restsx = data->cx; restsx = data->cx;
} }
@@ -1751,7 +1758,7 @@ window_copy_copy_line(struct window_pane *wp, char **buf, size_t *off, u_int sy,
* Work out if the line was wrapped at the screen edge and all of it is * Work out if the line was wrapped at the screen edge and all of it is
* on screen. * on screen.
*/ */
gl = &gd->linedata[sy]; gl = grid_get_line(gd, sy);
if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx) if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
wrapped = 1; wrapped = 1;
@@ -1839,7 +1846,7 @@ window_copy_find_length(struct window_pane *wp, u_int py)
* width of the grid, and screen_write_copy treats them as spaces, so * width of the grid, and screen_write_copy treats them as spaces, so
* ignore them here too. * ignore them here too.
*/ */
px = s->grid->linedata[py].cellsize; px = grid_get_line(s->grid, py)->cellsize;
if (px > screen_size_x(s)) if (px > screen_size_x(s))
px = screen_size_x(s); px = screen_size_x(s);
while (px > 0) { while (px > 0) {
@@ -1856,14 +1863,13 @@ window_copy_cursor_start_of_line(struct window_pane *wp)
{ {
struct window_copy_mode_data *data = wp->modedata; struct window_copy_mode_data *data = wp->modedata;
struct screen *back_s = data->backing; struct screen *back_s = data->backing;
struct screen *s = &data->screen;
struct grid *gd = back_s->grid; struct grid *gd = back_s->grid;
u_int py; u_int py;
if (data->cx == 0 && s->sel.lineflag == LINE_SEL_NONE) { if (data->cx == 0 && data->lineflag == LINE_SEL_NONE) {
py = screen_hsize(back_s) + data->cy - data->oy; py = screen_hsize(back_s) + data->cy - data->oy;
while (py > 0 && while (py > 0 &&
gd->linedata[py-1].flags & GRID_LINE_WRAPPED) { grid_get_line(gd, py - 1)->flags & GRID_LINE_WRAPPED) {
window_copy_cursor_up(wp, 0); window_copy_cursor_up(wp, 0);
py = screen_hsize(back_s) + data->cy - data->oy; py = screen_hsize(back_s) + data->cy - data->oy;
} }
@@ -1901,22 +1907,24 @@ window_copy_cursor_end_of_line(struct window_pane *wp)
{ {
struct window_copy_mode_data *data = wp->modedata; struct window_copy_mode_data *data = wp->modedata;
struct screen *back_s = data->backing; struct screen *back_s = data->backing;
struct screen *s = &data->screen;
struct grid *gd = back_s->grid; struct grid *gd = back_s->grid;
struct grid_line *gl;
u_int px, py; u_int px, py;
py = screen_hsize(back_s) + data->cy - data->oy; py = screen_hsize(back_s) + data->cy - data->oy;
px = window_copy_find_length(wp, py); px = window_copy_find_length(wp, py);
if (data->cx == px && s->sel.lineflag == LINE_SEL_NONE) { if (data->cx == px && data->lineflag == LINE_SEL_NONE) {
if (data->screen.sel.flag && data->rectflag) if (data->screen.sel != NULL && data->rectflag)
px = screen_size_x(back_s); px = screen_size_x(back_s);
if (gd->linedata[py].flags & GRID_LINE_WRAPPED) { gl = grid_get_line(gd, py);
while (py < gd->sy + gd->hsize && if (gl->flags & GRID_LINE_WRAPPED) {
gd->linedata[py].flags & GRID_LINE_WRAPPED) { while (py < gd->sy + gd->hsize) {
gl = grid_get_line(gd, py);
if (~gl->flags & GRID_LINE_WRAPPED)
break;
window_copy_cursor_down(wp, 0); window_copy_cursor_down(wp, 0);
py = screen_hsize(back_s) py = screen_hsize(back_s) + data->cy - data->oy;
+ data->cy - data->oy;
} }
px = window_copy_find_length(wp, py); px = window_copy_find_length(wp, py);
} }
@@ -1934,13 +1942,13 @@ window_copy_other_end(struct window_pane *wp)
struct screen *s = &data->screen; struct screen *s = &data->screen;
u_int selx, sely, cy, yy, hsize; u_int selx, sely, cy, yy, hsize;
if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE) if (s->sel == NULL && data->lineflag == LINE_SEL_NONE)
return; return;
if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT) if (data->lineflag == LINE_SEL_LEFT_RIGHT)
s->sel.lineflag = LINE_SEL_RIGHT_LEFT; data->lineflag = LINE_SEL_RIGHT_LEFT;
else if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT) else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
s->sel.lineflag = LINE_SEL_LEFT_RIGHT; data->lineflag = LINE_SEL_LEFT_RIGHT;
switch (data->cursordrag) { switch (data->cursordrag) {
case CURSORDRAG_NONE: case CURSORDRAG_NONE:
@@ -2012,7 +2020,7 @@ window_copy_cursor_right(struct window_pane *wp)
py = screen_hsize(data->backing) + data->cy - data->oy; py = screen_hsize(data->backing) + data->cy - data->oy;
yy = screen_hsize(data->backing) + screen_size_y(data->backing) - 1; yy = screen_hsize(data->backing) + screen_size_y(data->backing) - 1;
if (data->screen.sel.flag && data->rectflag) if (data->screen.sel != NULL && data->rectflag)
px = screen_size_x(&data->screen); px = screen_size_x(&data->screen);
else else
px = window_copy_find_length(wp, py); px = window_copy_find_length(wp, py);
@@ -2049,7 +2057,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
data->lastsx = ox; data->lastsx = ox;
} }
if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely) if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
window_copy_other_end(wp); window_copy_other_end(wp);
data->cx = data->lastcx; data->cx = data->lastcx;
@@ -2071,7 +2079,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
} }
} }
if (!data->screen.sel.flag || !data->rectflag) { if (data->screen.sel != NULL || !data->rectflag) {
py = screen_hsize(data->backing) + data->cy - data->oy; py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py); px = window_copy_find_length(wp, py);
if ((data->cx >= data->lastsx && data->cx != px) || if ((data->cx >= data->lastsx && data->cx != px) ||
@@ -2079,9 +2087,9 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
window_copy_cursor_end_of_line(wp); window_copy_cursor_end_of_line(wp);
} }
if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT) if (data->lineflag == LINE_SEL_LEFT_RIGHT)
window_copy_cursor_end_of_line(wp); window_copy_cursor_end_of_line(wp);
else if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT) else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
window_copy_cursor_start_of_line(wp); window_copy_cursor_start_of_line(wp);
} }
@@ -2099,7 +2107,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
data->lastsx = ox; data->lastsx = ox;
} }
if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely) if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
window_copy_other_end(wp); window_copy_other_end(wp);
data->cx = data->lastcx; data->cx = data->lastcx;
@@ -2113,7 +2121,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
window_copy_redraw_lines(wp, data->cy - 1, 2); window_copy_redraw_lines(wp, data->cy - 1, 2);
} }
if (!data->screen.sel.flag || !data->rectflag) { if (data->screen.sel == NULL || !data->rectflag) {
py = screen_hsize(data->backing) + data->cy - data->oy; py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py); px = window_copy_find_length(wp, py);
if ((data->cx >= data->lastsx && data->cx != px) || if ((data->cx >= data->lastsx && data->cx != px) ||
@@ -2121,9 +2129,9 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
window_copy_cursor_end_of_line(wp); window_copy_cursor_end_of_line(wp);
} }
if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT) if (data->lineflag == LINE_SEL_LEFT_RIGHT)
window_copy_cursor_end_of_line(wp); window_copy_cursor_end_of_line(wp);
else if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT) else if (data->lineflag == LINE_SEL_RIGHT_LEFT)
window_copy_cursor_start_of_line(wp); window_copy_cursor_start_of_line(wp);
} }
@@ -2394,7 +2402,7 @@ window_copy_scroll_up(struct window_pane *wp, u_int ny)
window_copy_write_line(wp, &ctx, 1); window_copy_write_line(wp, &ctx, 1);
if (screen_size_y(s) > 3) if (screen_size_y(s) > 3)
window_copy_write_line(wp, &ctx, screen_size_y(s) - 2); window_copy_write_line(wp, &ctx, screen_size_y(s) - 2);
if (s->sel.flag && screen_size_y(s) > ny) if (s->sel != NULL && screen_size_y(s) > ny)
window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1); window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1);
screen_write_cursormove(&ctx, data->cx, data->cy); screen_write_cursormove(&ctx, data->cx, data->cy);
screen_write_stop(&ctx); screen_write_stop(&ctx);
@@ -2422,7 +2430,7 @@ window_copy_scroll_down(struct window_pane *wp, u_int ny)
screen_write_cursormove(&ctx, 0, 0); screen_write_cursormove(&ctx, 0, 0);
screen_write_insertline(&ctx, ny, 8); screen_write_insertline(&ctx, ny, 8);
window_copy_write_lines(wp, &ctx, 0, ny); window_copy_write_lines(wp, &ctx, 0, ny);
if (s->sel.flag && screen_size_y(s) > ny) if (s->sel != NULL && screen_size_y(s) > ny)
window_copy_write_line(wp, &ctx, ny); window_copy_write_line(wp, &ctx, ny);
else if (ny == 1) /* nuke position */ else if (ny == 1) /* nuke position */
window_copy_write_line(wp, &ctx, 1); window_copy_write_line(wp, &ctx, 1);
@@ -2434,13 +2442,13 @@ void
window_copy_add_formats(struct window_pane *wp, struct format_tree *ft) window_copy_add_formats(struct window_pane *wp, struct format_tree *ft)
{ {
struct window_copy_mode_data *data = wp->modedata; struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
if (wp->mode != &window_copy_mode) if (wp->mode != &window_copy_mode)
return; return;
format_add(ft, "selection_present", "%d", s->sel.flag); format_add(ft, "selection_present", "%d", data->screen.sel != NULL);
format_add(ft, "scroll_position", "%d", data->oy); format_add(ft, "scroll_position", "%d", data->oy);
format_add(ft, "rectangle_toggle", "%d", data->rectflag);
} }
static void static void

View File

@@ -18,6 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -860,8 +861,6 @@ window_tree_destroy(struct window_tree_modedata *data)
if (--data->references != 0) if (--data->references != 0)
return; return;
mode_tree_free(data->data);
for (i = 0; i < data->item_size; i++) for (i = 0; i < data->item_size; i++)
window_tree_free_item(data->item_list[i]); window_tree_free_item(data->item_list[i]);
free(data->item_list); free(data->item_list);
@@ -881,6 +880,7 @@ window_tree_free(struct window_pane *wp)
return; return;
data->dead = 1; data->dead = 1;
mode_tree_free(data->data);
window_tree_destroy(data); window_tree_destroy(data);
} }
@@ -965,7 +965,7 @@ window_tree_command_callback(struct client *c, void *modedata, const char *s,
{ {
struct window_tree_modedata *data = modedata; struct window_tree_modedata *data = modedata;
if (s == NULL || data->dead) if (s == NULL || *s == '\0' || data->dead)
return (0); return (0);
data->entered = s; data->entered = s;
@@ -987,6 +987,77 @@ window_tree_command_free(void *modedata)
window_tree_destroy(data); window_tree_destroy(data);
} }
static void
window_tree_kill_each(__unused void* modedata, void* itemdata,
__unused struct client *c, __unused key_code key)
{
struct window_tree_itemdata *item = itemdata;
struct session *s;
struct winlink *wl;
struct window_pane *wp;
window_tree_pull_item(item, &s, &wl, &wp);
switch (item->type) {
case WINDOW_TREE_NONE:
break;
case WINDOW_TREE_SESSION:
if (s != NULL) {
server_destroy_session(s);
session_destroy(s, __func__);
}
break;
case WINDOW_TREE_WINDOW:
if (wl != NULL)
server_kill_window(wl->window);
break;
case WINDOW_TREE_PANE:
if (wp != NULL)
server_kill_pane(wp);
break;
}
}
static int
window_tree_kill_current_callback(struct client *c, void *modedata,
const char *s, __unused int done)
{
struct window_tree_modedata *data = modedata;
struct mode_tree_data *mtd = data->data;
if (s == NULL || *s == '\0' || data->dead)
return (0);
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
return (0);
window_tree_kill_each(data, mode_tree_get_current(mtd), c, KEYC_NONE);
data->references++;
cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
return (0);
}
static int
window_tree_kill_tagged_callback(struct client *c, void *modedata,
const char *s, __unused int done)
{
struct window_tree_modedata *data = modedata;
struct mode_tree_data *mtd = data->data;
if (s == NULL || *s == '\0' || data->dead)
return (0);
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
return (0);
mode_tree_each_tagged(mtd, window_tree_kill_each, c, KEYC_NONE, 1);
data->references++;
cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
return (0);
}
static key_code static key_code
window_tree_mouse(struct window_tree_modedata *data, key_code key, u_int x, window_tree_mouse(struct window_tree_modedata *data, key_code key, u_int x,
struct window_tree_itemdata *item) struct window_tree_itemdata *item)
@@ -1054,10 +1125,13 @@ window_tree_key(struct window_pane *wp, struct client *c,
{ {
struct window_tree_modedata *data = wp->modedata; struct window_tree_modedata *data = wp->modedata;
struct window_tree_itemdata *item, *new_item; struct window_tree_itemdata *item, *new_item;
char *name, *prompt; char *name, *prompt = NULL;
struct cmd_find_state fs; struct cmd_find_state fs;
int finished; int finished;
u_int tagged, x, y; u_int tagged, x, y, idx;
struct session *ns;
struct winlink *nwl;
struct window_pane *nwp;
item = mode_tree_get_current(data->data); item = mode_tree_get_current(data->data);
finished = mode_tree_key(data->data, c, &key, m, &x, &y); finished = mode_tree_key(data->data, c, &key, m, &x, &y);
@@ -1074,6 +1148,46 @@ window_tree_key(struct window_pane *wp, struct client *c,
case '>': case '>':
data->offset++; data->offset++;
break; break;
case 'x':
window_tree_pull_item(item, &ns, &nwl, &nwp);
switch (item->type) {
case WINDOW_TREE_NONE:
break;
case WINDOW_TREE_SESSION:
if (ns == NULL)
break;
xasprintf(&prompt, "Kill session %s? ", ns->name);
break;
case WINDOW_TREE_WINDOW:
if (nwl == NULL)
break;
xasprintf(&prompt, "Kill window %u? ", nwl->idx);
break;
case WINDOW_TREE_PANE:
if (nwp == NULL || window_pane_index(nwp, &idx) != 0)
break;
xasprintf(&prompt, "Kill pane %u? ", idx);
break;
}
if (prompt == NULL)
break;
data->references++;
status_prompt_set(c, prompt, "",
window_tree_kill_current_callback, window_tree_command_free,
data, PROMPT_SINGLE|PROMPT_NOFORMAT);
free(prompt);
break;
case 'X':
tagged = mode_tree_count_tagged(data->data);
if (tagged == 0)
break;
xasprintf(&prompt, "Kill %u tagged? ", tagged);
data->references++;
status_prompt_set(c, prompt, "",
window_tree_kill_tagged_callback, window_tree_command_free,
data, PROMPT_SINGLE|PROMPT_NOFORMAT);
free(prompt);
break;
case ':': case ':':
tagged = mode_tree_count_tagged(data->data); tagged = mode_tree_count_tagged(data->data);
if (tagged != 0) if (tagged != 0)

View File

@@ -921,10 +921,11 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
wp->flags &= ~(PANE_STATUSREADY|PANE_STATUSDRAWN); wp->flags &= ~(PANE_STATUSREADY|PANE_STATUSDRAWN);
cmd = cmd_stringify_argv(wp->argc, wp->argv); cmd = cmd_stringify_argv(wp->argc, wp->argv);
log_debug("spawn: %s -- %s", wp->shell, cmd); log_debug("%s: shell=%s", __func__, wp->shell);
for (i = 0; i < wp->argc; i++) log_debug("%s: cmd=%s", __func__, cmd);
log_debug("spawn: argv[%d] = %s", i, wp->argv[i]); log_debug("%s: cwd=%s", __func__, cwd);
environ_log(env, "spawn: "); cmd_log_argv(wp->argc, wp->argv, __func__);
environ_log(env, "%s: environment ", __func__);
memset(&ws, 0, sizeof ws); memset(&ws, 0, sizeof ws);
ws.ws_col = screen_size_x(&wp->base); ws.ws_col = screen_size_x(&wp->base);
@@ -1005,6 +1006,8 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
execl(wp->shell, argv0, (char *)NULL); execl(wp->shell, argv0, (char *)NULL);
fatal("execl failed"); fatal("execl failed");
} }
log_debug("%s: master=%s", __func__, ttyname(wp->fd));
log_debug("%s: slave=%s", __func__, wp->tty);
#ifdef HAVE_UTEMPTER #ifdef HAVE_UTEMPTER
xsnprintf(s, sizeof s, "tmux(%lu).%%%u", (long) getpid(), wp->id); xsnprintf(s, sizeof s, "tmux(%lu).%%%u", (long) getpid(), wp->id);