mirror of
https://github.com/tmux/tmux.git
synced 2025-06-23 00:00:37 -04:00
Compare commits
270 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
96244dd727 | ||
|
b38b5d3df2 | ||
|
ad3e6ff054 | ||
|
522652913f | ||
|
43e88c892d | ||
|
d82d9468b4 | ||
|
d7f75ac985 | ||
|
1dbceaa790 | ||
|
77ca59acac | ||
|
7be0613657 | ||
|
b9ad9186fe | ||
|
3f4b154b70 | ||
|
ff73c95547 | ||
|
aa0d05f676 | ||
|
545832e9fa | ||
|
a0ac2a5d63 | ||
|
833c7fbf6d | ||
|
faf2a44890 | ||
|
d194ceb604 | ||
|
37a2c98d3d | ||
|
79b02998a6 | ||
|
1ce1e7ef27 | ||
|
7499d925da | ||
|
367f17a4ff | ||
|
3d2b26dcfe | ||
|
6106a0f2c4 | ||
|
1926c1b683 | ||
|
6cc1a607fc | ||
|
1905afb3d8 | ||
|
345a45083d | ||
|
3a3babf597 | ||
|
f367e3a6c8 | ||
|
f2283b0cb5 | ||
|
26081ac125 | ||
|
36fba4cc54 | ||
|
58b4286edb | ||
|
b0b6a6f665 | ||
|
63e5989f53 | ||
|
9da5707d3e | ||
|
55292b72d1 | ||
|
06b1ad6241 | ||
|
1efe41b9b9 | ||
|
1198eed632 | ||
|
0772fe822a | ||
|
f53fac1b56 | ||
|
68f2ac9296 | ||
|
b4f8340f16 | ||
|
d2f73c17d5 | ||
|
5db914b745 | ||
|
cd3d2910ee | ||
|
de7653f5a4 | ||
|
b905039ed2 | ||
|
f0a85d0469 | ||
|
ac2779f4d8 | ||
|
68ffe65499 | ||
|
3e14e7c48b | ||
|
b526e678b5 | ||
|
d3c39375d5 | ||
|
a7991dcbad | ||
|
47dff97834 | ||
|
2905395695 | ||
|
4bf38da4d4 | ||
|
9b37b9285e | ||
|
dfdced2ab1 | ||
|
c2a95a372f | ||
|
ef923d28ff | ||
|
53b0e0bc02 | ||
|
096c4b3e63 | ||
|
b8189d6ee3 | ||
|
f41dc91357 | ||
|
ef0c12ad9e | ||
|
9e1f110db0 | ||
|
483b2b3edb | ||
|
34a35b0f09 | ||
|
aca3ffb30a | ||
|
c3c4524def | ||
|
f101762d1b | ||
|
a541be3951 | ||
|
b7d640e764 | ||
|
969f6a60c3 | ||
|
6703cb85d9 | ||
|
111e16e772 | ||
|
3eb93383a3 | ||
|
817b621d20 | ||
|
5eb30c1543 | ||
|
d4b8635f50 | ||
|
4e4fe3eb39 | ||
|
882fb4d295 | ||
|
eaf70c955b | ||
|
3543d79048 | ||
|
94783addfc | ||
|
91c0de60b4 | ||
|
21f7db4c4d | ||
|
f224d61f37 | ||
|
d938ab5dd7 | ||
|
9a8f46e554 | ||
|
27ee0c9c3b | ||
|
251a87e2d2 | ||
|
084e6ee9ec | ||
|
18331e39bf | ||
|
250c88efdc | ||
|
9a377485be | ||
|
47a56c11f2 | ||
|
c4b9716873 | ||
|
ec119b2f9e | ||
|
5d1a6acc84 | ||
|
80eb460fc9 | ||
|
ef68debc8d | ||
|
4c12ac9fb8 | ||
|
244bb726e2 | ||
|
6ab268c7bb | ||
|
0c9f8ff189 | ||
|
dd7d04be95 | ||
|
58392d29da | ||
|
9260f5dc96 | ||
|
62a6c16b43 | ||
|
31e8d4676a | ||
|
d3cbe00f78 | ||
|
97fe3563fa | ||
|
37ad1e2f6d | ||
|
00894d188d | ||
|
2a5eba7899 | ||
|
bf30492d57 | ||
|
e00853ee82 | ||
|
e75f3a0060 | ||
|
eece41547e | ||
|
c311202b73 | ||
|
e149d29803 | ||
|
190ddda572 | ||
|
6b470c5222 | ||
|
6b32d195e8 | ||
|
bec6ce54c1 | ||
|
106d1c3538 | ||
|
ae8f2208c9 | ||
|
5c3cf2f08b | ||
|
102f34090d | ||
|
99790c90aa | ||
|
6d792e4123 | ||
|
98e322d5a5 | ||
|
01edce40f3 | ||
|
0549f87ccc | ||
|
72cd0eac29 | ||
|
f0c68533c4 | ||
|
9e4a9c51cc | ||
|
6874ec0dcc | ||
|
252f41818e | ||
|
d361f21065 | ||
|
feb090abb3 | ||
|
db771ec6e3 | ||
|
6f7db82b18 | ||
|
67cc7f6dc6 | ||
|
db978db271 | ||
|
363f35f076 | ||
|
49b7276f2a | ||
|
f57131e11b | ||
|
420af9e108 | ||
|
ceaf9b7452 | ||
|
5fd45b3892 | ||
|
64d82d5988 | ||
|
0f308bd18f | ||
|
1365f1ce52 | ||
|
7fc4e54efe | ||
|
c98c08c232 | ||
|
990c724bd8 | ||
|
b82c7b40b0 | ||
|
70299c6646 | ||
|
ea6c5053c8 | ||
|
3f4fd45d5c | ||
|
7c7e88253e | ||
|
bb94a5437d | ||
|
273f9b2027 | ||
|
b6d0b4be30 | ||
|
2dce45f427 | ||
|
a3ede3106a | ||
|
dd9722184b | ||
|
a854e36f2b | ||
|
be594ff8a4 | ||
|
c66628e52b | ||
|
350a151ee4 | ||
|
d35458e3fe | ||
|
d6883c0266 | ||
|
563ed05353 | ||
|
f527412d9b | ||
|
713cacab1e | ||
|
846f813565 | ||
|
c26d71d3e9 | ||
|
c8677d3272 | ||
|
596ea62dc3 | ||
|
1fe30bb2e8 | ||
|
809d659e64 | ||
|
09f4e43189 | ||
|
679bbdcf8f | ||
|
a0c79aa87b | ||
|
46f3846659 | ||
|
bbc3cc558c | ||
|
c8bd42de16 | ||
|
62e15e905b | ||
|
125a7b9177 | ||
|
895044c52b | ||
|
40c01c2d37 | ||
|
911d768b71 | ||
|
71a503e40c | ||
|
487b0ee124 | ||
|
eaec0a48f4 | ||
|
fdbc6cdea5 | ||
|
9623ec3ee4 | ||
|
63582c154c | ||
|
914815e70f | ||
|
354926a956 | ||
|
df303770ea | ||
|
a269c33a54 | ||
|
eb04f9314b | ||
|
a9d0461839 | ||
|
71aa4fe767 | ||
|
cfd3c02306 | ||
|
35104059ed | ||
|
934035db71 | ||
|
8ff65230e1 | ||
|
cb00e869ea | ||
|
f8b56fdc3f | ||
|
2d8b6fcf23 | ||
|
6ddee22f81 | ||
|
66c738bc10 | ||
|
bcc47add38 | ||
|
d326c51d79 | ||
|
940fdf7ed0 | ||
|
4f5d6d97d3 | ||
|
00412b570b | ||
|
6a35b8ad07 | ||
|
735082b7c2 | ||
|
5b7bdc82c8 | ||
|
a3dea81b49 | ||
|
486221f206 | ||
|
9528d7470b | ||
|
933d6b90ed | ||
|
a869693405 | ||
|
114977dd25 | ||
|
aba8ffbe7b | ||
|
455a2b3705 | ||
|
e0638c48cd | ||
|
41f6b691e3 | ||
|
0f30fa34e3 | ||
|
e486f5ffdc | ||
|
5a68730e2f | ||
|
16b44d2a5b | ||
|
34775fc235 | ||
|
f2fd8c854a | ||
|
9f2a853d87 | ||
|
7a78cdf78c | ||
|
2df15ad08c | ||
|
780a87be9a | ||
|
1e303b6a9d | ||
|
8d2aee34ab | ||
|
05116cefe6 | ||
|
ce4be58eef | ||
|
8d6eb4be40 | ||
|
38c38f1c64 | ||
|
ddf6af79e3 | ||
|
826ba515be | ||
|
729bded8bf | ||
|
b95a06d2d4 | ||
|
157d748949 | ||
|
1c1f4c1219 | ||
|
17bab32794 | ||
|
25b1cc1e8e | ||
|
89adec0ca5 | ||
|
f95d055e04 | ||
|
7b148f7b5b | ||
|
9bd039d1bc | ||
|
7c30056d96 |
5
.github/CONTRIBUTING.md
vendored
5
.github/CONTRIBUTING.md
vendored
@ -77,3 +77,8 @@ The log files are:
|
|||||||
- `tmux-out*.log`: output log file.
|
- `tmux-out*.log`: output log file.
|
||||||
|
|
||||||
Please attach the log files to your issue.
|
Please attach the log files to your issue.
|
||||||
|
|
||||||
|
## What does it mean if an issue is closed?
|
||||||
|
|
||||||
|
All it means is that work on the issue is not planned for the near future. See
|
||||||
|
the issue's comments to find out if contributions would be welcome.
|
||||||
|
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
blank_issues_enabled: false
|
@ -1,3 +1,12 @@
|
|||||||
|
---
|
||||||
|
name: Use this issue template
|
||||||
|
about: Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Issue description
|
### Issue description
|
||||||
|
|
||||||
Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md
|
Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md
|
2
.github/README.md
vendored
2
.github/README.md
vendored
@ -79,7 +79,7 @@ A small example configuration is in `example_tmux.conf`.
|
|||||||
|
|
||||||
And a bash(1) completion file at:
|
And a bash(1) completion file at:
|
||||||
|
|
||||||
https://github.com/imomaliev/tmux-bash-completion
|
https://github.com/scop/bash-completion/blob/main/completions/tmux
|
||||||
|
|
||||||
For debugging, run tmux with `-v` or `-vv` to generate server and client log
|
For debugging, run tmux with `-v` or `-vv` to generate server and client log
|
||||||
files in the current directory.
|
files in the current directory.
|
||||||
|
35
.gitignore
vendored
35
.gitignore
vendored
@ -1,23 +1,24 @@
|
|||||||
*.o
|
|
||||||
*~
|
|
||||||
*.diff
|
|
||||||
*.patch
|
|
||||||
*.core
|
*.core
|
||||||
core
|
*.dSYM
|
||||||
tags
|
*.diff
|
||||||
|
*.o
|
||||||
|
*.patch
|
||||||
|
*.swp
|
||||||
|
*~
|
||||||
.deps/
|
.deps/
|
||||||
compat/.dirstamp
|
.dirstamp
|
||||||
aclocal.m4
|
|
||||||
autom4te.cache/
|
|
||||||
config.log
|
|
||||||
config.status
|
|
||||||
etc/
|
|
||||||
tmux
|
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
configure
|
aclocal.m4
|
||||||
tmux.1.*
|
autom4te.cache/
|
||||||
*.dSYM
|
|
||||||
cmd-parse.c
|
cmd-parse.c
|
||||||
|
compat/.dirstamp
|
||||||
|
config.log
|
||||||
|
config.status
|
||||||
|
configure
|
||||||
|
core
|
||||||
|
etc/
|
||||||
fuzz/*-fuzzer
|
fuzz/*-fuzzer
|
||||||
.dirstamp
|
tags
|
||||||
|
tmux
|
||||||
|
tmux.1.*
|
||||||
|
2
CHANGES
2
CHANGES
@ -389,7 +389,7 @@ CHANGES FROM 3.2 TO 3.2a
|
|||||||
* Do not expand the filename given to -f so it can contain colons.
|
* Do not expand the filename given to -f so it can contain colons.
|
||||||
|
|
||||||
* Fixes for problems with extended keys and modifiers, scroll region,
|
* Fixes for problems with extended keys and modifiers, scroll region,
|
||||||
source-file, crosscompiling, format modifiers and other minor issues.
|
source-file, cross compiling, format modifiers and other minor issues.
|
||||||
|
|
||||||
CHANGES FROM 3.1c TO 3.2
|
CHANGES FROM 3.1c TO 3.2
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
|
|||||||
AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
|
AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
|
||||||
AM_CFLAGS += -Wno-unused-result -Wno-format-y2k
|
AM_CFLAGS += -Wno-unused-result -Wno-format-y2k
|
||||||
if IS_DARWIN
|
if IS_DARWIN
|
||||||
AM_CFLAGS += -Wno-deprecated-declarations -Wno-cast-align
|
AM_CFLAGS += -Wno-deprecated-declarations -Wno-cast-align -Wno-macro-redefined
|
||||||
endif
|
endif
|
||||||
AM_CPPFLAGS += -DDEBUG
|
AM_CPPFLAGS += -DDEBUG
|
||||||
endif
|
endif
|
||||||
@ -66,6 +66,11 @@ if IS_HAIKU
|
|||||||
AM_CPPFLAGS += -D_BSD_SOURCE
|
AM_CPPFLAGS += -D_BSD_SOURCE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Set flags for Cygwin.
|
||||||
|
if IS_CYGWIN
|
||||||
|
AM_CPPFLAGS += -DTMUX_SOCK_PERM=0
|
||||||
|
endif
|
||||||
|
|
||||||
# List of sources.
|
# List of sources.
|
||||||
dist_tmux_SOURCES = \
|
dist_tmux_SOURCES = \
|
||||||
alerts.c \
|
alerts.c \
|
||||||
|
3
README
3
README
@ -36,6 +36,7 @@ autoconf, automake and pkg-config:
|
|||||||
$ cd tmux
|
$ cd tmux
|
||||||
$ sh autogen.sh
|
$ sh autogen.sh
|
||||||
$ ./configure && make
|
$ ./configure && make
|
||||||
|
$ sudo make install
|
||||||
|
|
||||||
* Contributing
|
* Contributing
|
||||||
|
|
||||||
@ -65,7 +66,7 @@ Also see the tmux FAQ at:
|
|||||||
|
|
||||||
A bash(1) completion file is at:
|
A bash(1) completion file is at:
|
||||||
|
|
||||||
https://github.com/imomaliev/tmux-bash-completion
|
https://github.com/scop/bash-completion/blob/main/completions/tmux
|
||||||
|
|
||||||
For debugging, run tmux with -v and -vv to generate server and client log files
|
For debugging, run tmux with -v and -vv to generate server and client log files
|
||||||
in the current directory.
|
in the current directory.
|
||||||
|
@ -38,7 +38,7 @@ tmuxのドキュメントについてはtmux.1マニュアルをご覧くださ
|
|||||||
サンプル設定は本リポジトリのexample_tmux.confに
|
サンプル設定は本リポジトリのexample_tmux.confに
|
||||||
また、bash-completionファイルは下記にあります。
|
また、bash-completionファイルは下記にあります。
|
||||||
|
|
||||||
https://github.com/imomaliev/tmux-bash-completion
|
https://github.com/scop/bash-completion/blob/main/completions/tmux
|
||||||
|
|
||||||
「-v」や「-vv」を指定することでデバッグモードでの起動が可能です。カレントディレクトリにサーバーやクライアントのログファイルが生成されます。
|
「-v」や「-vv」を指定することでデバッグモードでの起動が可能です。カレントディレクトリにサーバーやクライアントのログファイルが生成されます。
|
||||||
|
|
||||||
|
32
SYNCING
32
SYNCING
@ -1,17 +1,17 @@
|
|||||||
Preamble
|
Preamble
|
||||||
========
|
========
|
||||||
|
|
||||||
Tmux portable relies on repositories "tmux" and "tmux-openbsd".
|
Tmux portable relies on repositories "tmux" and "tmux-obsd".
|
||||||
Here's a description of them:
|
Here's a description of them:
|
||||||
|
|
||||||
* "tmux" is the portable version, the one which contains code for other
|
* "tmux" is the portable version, the one which contains code for other
|
||||||
operating systems, and autotools, etc., which isn't found or needed in the
|
operating systems, and autotools, etc., which isn't found or needed in the
|
||||||
OpenBSD base system.
|
OpenBSD base system.
|
||||||
|
|
||||||
* "tmux-openbsd" is the version of tmux in OpenBSD base system which provides
|
* "tmux-obsd" is the version of tmux in OpenBSD base system which provides
|
||||||
the basis of the portable tmux version.
|
the basis of the portable tmux version.
|
||||||
|
|
||||||
Note: The "tmux-openbsd" repository is actually handled by "git cvsimport"
|
Note: The "tmux-obsd" repository is actually handled by "git cvsimport"
|
||||||
running at 15 minute intervals, so a commit made to OpenBSD's tmux CVS
|
running at 15 minute intervals, so a commit made to OpenBSD's tmux CVS
|
||||||
repository will take at least that long to appear in this git repository.
|
repository will take at least that long to appear in this git repository.
|
||||||
(It might take longer, depending on the CVS mirror used to import the
|
(It might take longer, depending on the CVS mirror used to import the
|
||||||
@ -34,11 +34,11 @@ this information has ever been set before.
|
|||||||
Cloning repositories
|
Cloning repositories
|
||||||
====================
|
====================
|
||||||
|
|
||||||
This involves having both tmux and tmux-openbsd cloned, as in:
|
This involves having both tmux and tmux-obsd cloned, as in:
|
||||||
|
|
||||||
% cd /some/where/useful
|
% cd /some/where/useful
|
||||||
% git clone https://github.com/tmux/tmux.git
|
% git clone https://github.com/tmux/tmux.git
|
||||||
% git clone https://github.com/ThomasAdam/tmux-openbsd.git
|
% git clone https://github.com/ThomasAdam/tmux-obsd.git
|
||||||
|
|
||||||
Note that you do not need additional checkouts to manage the sync -- an
|
Note that you do not need additional checkouts to manage the sync -- an
|
||||||
existing clone of either repositories will suffice. So if you already have
|
existing clone of either repositories will suffice. So if you already have
|
||||||
@ -47,30 +47,30 @@ these checkouts existing, skip that.
|
|||||||
Adding in git-remotes
|
Adding in git-remotes
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
Because the portable "tmux" git repository and the "tmux-openbsd"
|
Because the portable "tmux" git repository and the "tmux-obsd"
|
||||||
repository do not inherently share any history between each other, the
|
repository do not inherently share any history between each other, the
|
||||||
history has been faked between them. This "faking of history" is something
|
history has been faked between them. This "faking of history" is something
|
||||||
which has to be told to git for the purposes of comparing the "tmux" and
|
which has to be told to git for the purposes of comparing the "tmux" and
|
||||||
"tmux-openbsd" repositories for syncing. To do this, we must reference the
|
"tmux-obsd" repositories for syncing. To do this, we must reference the
|
||||||
clone of the "tmux-openbsd" repository from the "tmux" repository, as
|
clone of the "tmux-obsd" repository from the "tmux" repository, as
|
||||||
shown by the following command:
|
shown by the following command:
|
||||||
|
|
||||||
% cd /path/to/tmux
|
% cd /path/to/tmux
|
||||||
% git remote add obsd-tmux file:///path/to/tmux-openbsd
|
% git remote add obsd-tmux file:///path/to/tmux-obsd
|
||||||
|
|
||||||
So that now, the remote "obsd-tmux" can be used to reference branches and
|
So that now, the remote "obsd-tmux" can be used to reference branches and
|
||||||
commits from the "tmux-openbsd" repository, but from the context of the
|
commits from the "tmux-obsd" repository, but from the context of the
|
||||||
portable "tmux" repository, which makes sense because it's the "tmux"
|
portable "tmux" repository, which makes sense because it's the "tmux"
|
||||||
repository which will have the updates applied to them.
|
repository which will have the updates applied to them.
|
||||||
|
|
||||||
Fetching updates
|
Fetching updates
|
||||||
================
|
================
|
||||||
|
|
||||||
To ensure the latest commits from "tmux-openbsd" can be found from within
|
To ensure the latest commits from "tmux-obsd" can be found from within
|
||||||
"tmux", we have to ensure the "master" branch from "tmux-openbsd" is
|
"tmux", we have to ensure the "master" branch from "tmux-obsd" is
|
||||||
up-to-date first, and then reference that update in "tmux", as in:
|
up-to-date first, and then reference that update in "tmux", as in:
|
||||||
|
|
||||||
% cd /path/to/tmux-openbsd
|
% cd /path/to/tmux-obsd
|
||||||
% git checkout master
|
% git checkout master
|
||||||
% git pull
|
% git pull
|
||||||
|
|
||||||
@ -82,9 +82,9 @@ Then back in "tmux":
|
|||||||
Creating the necessary branches
|
Creating the necessary branches
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
Now that "tmux" can see commits and branches from "tmux-openbsd" by way
|
Now that "tmux" can see commits and branches from "tmux-obsd" by way
|
||||||
of the remote name "obsd-tmux", we can now create the master branch from
|
of the remote name "obsd-tmux", we can now create the master branch from
|
||||||
"tmux-openbsd" in the "tmux" repository:
|
"tmux-obsd" in the "tmux" repository:
|
||||||
|
|
||||||
% git checkout -b obsd-master obsd-tmux/master
|
% git checkout -b obsd-master obsd-tmux/master
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ Adding in the fake history points
|
|||||||
=================================
|
=================================
|
||||||
|
|
||||||
To tie both the "master" branch from "tmux" and the "obsd-master"
|
To tie both the "master" branch from "tmux" and the "obsd-master"
|
||||||
branch from "tmux-openbsd" together, the fake history points added to the
|
branch from "tmux-obsd" together, the fake history points added to the
|
||||||
"tmux" repository need to be added. To do this, we must add an
|
"tmux" repository need to be added. To do this, we must add an
|
||||||
additional refspec line, as in:
|
additional refspec line, as in:
|
||||||
|
|
||||||
|
8
alerts.c
8
alerts.c
@ -315,11 +315,11 @@ alerts_set_message(struct winlink *wl, const char *type, const char *option)
|
|||||||
if (visual == VISUAL_OFF)
|
if (visual == VISUAL_OFF)
|
||||||
continue;
|
continue;
|
||||||
if (c->session->curw == wl) {
|
if (c->session->curw == wl) {
|
||||||
status_message_set(c, -1, 1, 0, "%s in current window",
|
status_message_set(c, -1, 1, 0, 0,
|
||||||
type);
|
"%s in current window", type);
|
||||||
} else {
|
} else {
|
||||||
status_message_set(c, -1, 1, 0, "%s in window %d", type,
|
status_message_set(c, -1, 1, 0, 0,
|
||||||
wl->idx);
|
"%s in window %d", type, wl->idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ const struct cmd_entry cmd_bind_key_entry = {
|
|||||||
|
|
||||||
.args = { "nrN:T:", 1, -1, cmd_bind_key_args_parse },
|
.args = { "nrN:T:", 1, -1, cmd_bind_key_args_parse },
|
||||||
.usage = "[-nr] [-T key-table] [-N note] key "
|
.usage = "[-nr] [-T key-table] [-N note] key "
|
||||||
"[command [arguments]]",
|
"[command [argument ...]]",
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK,
|
.flags = CMD_AFTERHOOK,
|
||||||
.exec = cmd_bind_key_exec
|
.exec = cmd_bind_key_exec
|
||||||
|
@ -99,7 +99,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
|
|
||||||
w = wp->window = window_create(w->sx, w->sy, w->xpixel, w->ypixel);
|
w = wp->window = window_create(w->sx, w->sy, w->xpixel, w->ypixel);
|
||||||
options_set_parent(wp->options, w->options);
|
options_set_parent(wp->options, w->options);
|
||||||
wp->flags |= PANE_STYLECHANGED;
|
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||||
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
|
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
|
||||||
w->active = wp;
|
w->active = wp;
|
||||||
w->latest = tc;
|
w->latest = tc;
|
||||||
|
@ -39,8 +39,8 @@ const struct cmd_entry cmd_capture_pane_entry = {
|
|||||||
.name = "capture-pane",
|
.name = "capture-pane",
|
||||||
.alias = "capturep",
|
.alias = "capturep",
|
||||||
|
|
||||||
.args = { "ab:CeE:JNpPqS:Tt:", 0, 0, NULL },
|
.args = { "ab:CeE:JMNpPqS:Tt:", 0, 0, NULL },
|
||||||
.usage = "[-aCeJNpPqT] " CMD_BUFFER_USAGE " [-E end-line] "
|
.usage = "[-aCeJMNpPqT] " CMD_BUFFER_USAGE " [-E end-line] "
|
||||||
"[-S start-line] " CMD_TARGET_PANE_USAGE,
|
"[-S start-line] " CMD_TARGET_PANE_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
@ -107,14 +107,16 @@ static char *
|
|||||||
cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
||||||
struct window_pane *wp, size_t *len)
|
struct window_pane *wp, size_t *len)
|
||||||
{
|
{
|
||||||
struct grid *gd;
|
struct grid *gd;
|
||||||
const struct grid_line *gl;
|
const struct grid_line *gl;
|
||||||
struct grid_cell *gc = NULL;
|
struct screen *s;
|
||||||
int n, join_lines, flags = 0;
|
struct grid_cell *gc = NULL;
|
||||||
u_int i, sx, top, bottom, tmp;
|
struct window_mode_entry *wme;
|
||||||
char *cause, *buf, *line;
|
int n, join_lines, flags = 0;
|
||||||
const char *Sflag, *Eflag;
|
u_int i, sx, top, bottom, tmp;
|
||||||
size_t linelen;
|
char *cause, *buf, *line;
|
||||||
|
const char *Sflag, *Eflag;
|
||||||
|
size_t linelen;
|
||||||
|
|
||||||
sx = screen_size_x(&wp->base);
|
sx = screen_size_x(&wp->base);
|
||||||
if (args_has(args, 'a')) {
|
if (args_has(args, 'a')) {
|
||||||
@ -126,8 +128,20 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
|||||||
}
|
}
|
||||||
return (xstrdup(""));
|
return (xstrdup(""));
|
||||||
}
|
}
|
||||||
} else
|
s = &wp->base;
|
||||||
|
} else if (args_has(args, 'M')) {
|
||||||
|
wme = TAILQ_FIRST(&wp->modes);
|
||||||
|
if (wme != NULL && wme->mode->get_screen != NULL) {
|
||||||
|
s = wme->mode->get_screen (wme);
|
||||||
|
gd = s->grid;
|
||||||
|
} else {
|
||||||
|
s = &wp->base;
|
||||||
|
gd = wp->base.grid;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s = &wp->base;
|
||||||
gd = wp->base.grid;
|
gd = wp->base.grid;
|
||||||
|
}
|
||||||
|
|
||||||
Sflag = args_get(args, 'S');
|
Sflag = args_get(args, 'S');
|
||||||
if (Sflag != NULL && strcmp(Sflag, "-") == 0)
|
if (Sflag != NULL && strcmp(Sflag, "-") == 0)
|
||||||
@ -181,7 +195,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
|||||||
|
|
||||||
buf = NULL;
|
buf = NULL;
|
||||||
for (i = top; i <= bottom; i++) {
|
for (i = top; i <= bottom; i++) {
|
||||||
line = grid_string_cells(gd, 0, i, sx, &gc, flags, wp->screen);
|
line = grid_string_cells(gd, 0, i, sx, &gc, flags, s);
|
||||||
linelen = strlen(line);
|
linelen = strlen(line);
|
||||||
|
|
||||||
buf = cmd_capture_pane_append(buf, len, line, linelen);
|
buf = cmd_capture_pane_append(buf, len, line, linelen);
|
||||||
|
@ -33,7 +33,7 @@ const struct cmd_entry cmd_choose_tree_entry = {
|
|||||||
.name = "choose-tree",
|
.name = "choose-tree",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "F:f:GK:NO:rst:wZ", 0, 1, cmd_choose_tree_args_parse },
|
.args = { "F:f:GK:NO:rst:wyZ", 0, 1, cmd_choose_tree_args_parse },
|
||||||
.usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] "
|
.usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] "
|
||||||
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ const struct cmd_entry cmd_choose_client_entry = {
|
|||||||
.name = "choose-client",
|
.name = "choose-client",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "F:f:K:NO:rt:Z", 0, 1, cmd_choose_tree_args_parse },
|
.args = { "F:f:K:NO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
|
||||||
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
|
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
|
||||||
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ const struct cmd_entry cmd_choose_buffer_entry = {
|
|||||||
.name = "choose-buffer",
|
.name = "choose-buffer",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "F:f:K:NO:rt:Z", 0, 1, cmd_choose_tree_args_parse },
|
.args = { "F:f:K:NO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
|
||||||
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
|
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
|
||||||
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ const struct cmd_entry cmd_customize_mode_entry = {
|
|||||||
.name = "customize-mode",
|
.name = "customize-mode",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "F:f:Nt:Z", 0, 0, NULL },
|
.args = { "F:f:Nt:yZ", 0, 0, NULL },
|
||||||
.usage = "[-NZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
|
.usage = "[-NZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
@ -44,7 +44,7 @@ const struct cmd_entry cmd_command_prompt_entry = {
|
|||||||
|
|
||||||
.args = { "1bFkiI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse },
|
.args = { "1bFkiI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse },
|
||||||
.usage = "[-1bFkiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
|
.usage = "[-1bFkiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
|
||||||
" [-T type] [template]",
|
" [-T prompt-type] [template]",
|
||||||
|
|
||||||
.flags = CMD_CLIENT_TFLAG,
|
.flags = CMD_CLIENT_TFLAG,
|
||||||
.exec = cmd_command_prompt_exec
|
.exec = cmd_command_prompt_exec
|
||||||
|
@ -42,7 +42,7 @@ const struct cmd_entry cmd_confirm_before_entry = {
|
|||||||
.alias = "confirm",
|
.alias = "confirm",
|
||||||
|
|
||||||
.args = { "bc:p:t:y", 1, 1, cmd_confirm_before_args_parse },
|
.args = { "bc:p:t:y", 1, 1, cmd_confirm_before_args_parse },
|
||||||
.usage = "[-by] [-c confirm_key] [-p prompt] " CMD_TARGET_CLIENT_USAGE
|
.usage = "[-by] [-c confirm-key] [-p prompt] " CMD_TARGET_CLIENT_USAGE
|
||||||
" command",
|
" command",
|
||||||
|
|
||||||
.flags = CMD_CLIENT_TFLAG,
|
.flags = CMD_CLIENT_TFLAG,
|
||||||
@ -130,7 +130,7 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s,
|
|||||||
|
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
if (s[0] != cdata->confirm_key && (s[0] != '\0' || !cdata->default_yes))
|
if (s[0] != cdata->confirm_key && (s[0] != '\r' || !cdata->default_yes))
|
||||||
goto out;
|
goto out;
|
||||||
retcode = 0;
|
retcode = 0;
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ const struct cmd_entry cmd_copy_mode_entry = {
|
|||||||
.name = "copy-mode",
|
.name = "copy-mode",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "deHMs:t:uq", 0, 0, NULL },
|
.args = { "deHMqSs:t:u", 0, 0, NULL },
|
||||||
.usage = "[-deHMuq] [-s src-pane] " CMD_TARGET_PANE_USAGE,
|
.usage = "[-deHMqSu] [-s src-pane] " CMD_TARGET_PANE_USAGE,
|
||||||
|
|
||||||
.source = { 's', CMD_FIND_PANE, 0 },
|
.source = { 's', CMD_FIND_PANE, 0 },
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
@ -92,7 +92,12 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (args_has(args, 'u'))
|
if (args_has(args, 'u'))
|
||||||
window_copy_pageup(wp, 0);
|
window_copy_pageup(wp, 0);
|
||||||
if (args_has(args, 'd'))
|
if (args_has(args, 'd'))
|
||||||
window_copy_pagedown(wp, 0, args_has(args, 'e'));
|
window_copy_pagedown(wp, 0, args_has(args, 'e'));
|
||||||
|
if (args_has(args, 'S')) {
|
||||||
|
window_copy_scroll(wp, c->tty.mouse_slider_mpos, event->m.y,
|
||||||
|
args_has(args, 'e'));
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
@ -41,8 +41,8 @@ const struct cmd_entry cmd_display_menu_entry = {
|
|||||||
.args = { "b:c:C:H:s:S:MOt:T:x:y:", 1, -1, cmd_display_menu_args_parse },
|
.args = { "b:c:C:H:s:S:MOt:T:x:y:", 1, -1, cmd_display_menu_args_parse },
|
||||||
.usage = "[-MO] [-b border-lines] [-c target-client] "
|
.usage = "[-MO] [-b border-lines] [-c target-client] "
|
||||||
"[-C starting-choice] [-H selected-style] [-s style] "
|
"[-C starting-choice] [-H selected-style] [-s style] "
|
||||||
"[-S border-style] " CMD_TARGET_PANE_USAGE "[-T title] "
|
"[-S border-style] " CMD_TARGET_PANE_USAGE " [-T title] "
|
||||||
"[-x position] [-y position] name key command ...",
|
"[-x position] [-y position] name [key] [command] ...",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
@ -58,8 +58,8 @@ const struct cmd_entry cmd_display_popup_entry = {
|
|||||||
.usage = "[-BCE] [-b border-lines] [-c target-client] "
|
.usage = "[-BCE] [-b border-lines] [-c target-client] "
|
||||||
"[-d start-directory] [-e environment] [-h height] "
|
"[-d start-directory] [-e environment] [-h height] "
|
||||||
"[-s style] [-S border-style] " CMD_TARGET_PANE_USAGE
|
"[-s style] [-S border-style] " CMD_TARGET_PANE_USAGE
|
||||||
"[-T title] [-w width] [-x position] [-y position] "
|
" [-T title] [-w width] [-x position] [-y position] "
|
||||||
"[shell-command]",
|
"[shell-command [argument ...]]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
|
@ -39,8 +39,8 @@ const struct cmd_entry cmd_display_message_entry = {
|
|||||||
.name = "display-message",
|
.name = "display-message",
|
||||||
.alias = "display",
|
.alias = "display",
|
||||||
|
|
||||||
.args = { "ac:d:lINpt:F:v", 0, 1, NULL },
|
.args = { "aCc:d:lINpt:F:v", 0, 1, NULL },
|
||||||
.usage = "[-aIlNpv] [-c target-client] [-d delay] [-F format] "
|
.usage = "[-aCIlNpv] [-c target-client] [-d delay] [-F format] "
|
||||||
CMD_TARGET_PANE_USAGE " [message]",
|
CMD_TARGET_PANE_USAGE " [message]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||||
@ -69,6 +69,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
const char *template;
|
const char *template;
|
||||||
char *msg, *cause;
|
char *msg, *cause;
|
||||||
int delay = -1, flags, Nflag = args_has(args, 'N');
|
int delay = -1, flags, Nflag = args_has(args, 'N');
|
||||||
|
int Cflag = args_has(args, 'C');
|
||||||
struct format_tree *ft;
|
struct format_tree *ft;
|
||||||
u_int count = args_count(args);
|
u_int count = args_count(args);
|
||||||
struct evbuffer *evb;
|
struct evbuffer *evb;
|
||||||
@ -150,7 +151,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
server_client_print(tc, 0, evb);
|
server_client_print(tc, 0, evb);
|
||||||
evbuffer_free(evb);
|
evbuffer_free(evb);
|
||||||
} else if (tc != NULL)
|
} else if (tc != NULL)
|
||||||
status_message_set(tc, delay, 0, Nflag, "%s", msg);
|
status_message_set(tc, delay, 0, Nflag, Cflag, "%s", msg);
|
||||||
free(msg);
|
free(msg);
|
||||||
|
|
||||||
format_free(ft);
|
format_free(ft);
|
||||||
|
@ -157,7 +157,7 @@ cmd_if_shell_callback(struct job *job)
|
|||||||
if (cmdlist == NULL) {
|
if (cmdlist == NULL) {
|
||||||
if (cdata->item == NULL) {
|
if (cdata->item == NULL) {
|
||||||
*error = toupper((u_char)*error);
|
*error = toupper((u_char)*error);
|
||||||
status_message_set(c, -1, 1, 0, "%s", error);
|
status_message_set(c, -1, 1, 0, 0, "%s", error);
|
||||||
} else
|
} else
|
||||||
cmdq_error(cdata->item, "%s", error);
|
cmdq_error(cdata->item, "%s", error);
|
||||||
free(error);
|
free(error);
|
||||||
|
@ -149,7 +149,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
|
|
||||||
src_wp->window = dst_w;
|
src_wp->window = dst_w;
|
||||||
options_set_parent(src_wp->options, dst_w->options);
|
options_set_parent(src_wp->options, dst_w->options);
|
||||||
src_wp->flags |= PANE_STYLECHANGED;
|
src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||||
if (flags & SPAWN_BEFORE)
|
if (flags & SPAWN_BEFORE)
|
||||||
TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry);
|
TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry);
|
||||||
else
|
else
|
||||||
|
@ -91,7 +91,7 @@ cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
|
|||||||
struct key_binding *bd;
|
struct key_binding *bd;
|
||||||
const char *key;
|
const char *key;
|
||||||
char *tmp, *note;
|
char *tmp, *note;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
|
||||||
table = key_bindings_get_table(tablename, 0);
|
table = key_bindings_get_table(tablename, 0);
|
||||||
if (table == NULL)
|
if (table == NULL)
|
||||||
@ -114,8 +114,8 @@ cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
|
|||||||
note = xstrdup(bd->note);
|
note = xstrdup(bd->note);
|
||||||
tmp = utf8_padcstr(key, keywidth + 1);
|
tmp = utf8_padcstr(key, keywidth + 1);
|
||||||
if (args_has(args, '1') && tc != NULL) {
|
if (args_has(args, '1') && tc != NULL) {
|
||||||
status_message_set(tc, -1, 1, 0, "%s%s%s", prefix, tmp,
|
status_message_set(tc, -1, 1, 0, 0, "%s%s%s", prefix,
|
||||||
note);
|
tmp, note);
|
||||||
} else
|
} else
|
||||||
cmdq_print(item, "%s%s%s", prefix, tmp, note);
|
cmdq_print(item, "%s%s%s", prefix, tmp, note);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
@ -298,8 +298,8 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
free(cp);
|
free(cp);
|
||||||
|
|
||||||
if (args_has(args, '1') && tc != NULL) {
|
if (args_has(args, '1') && tc != NULL) {
|
||||||
status_message_set(tc, -1, 1, 0, "bind-key %s",
|
status_message_set(tc, -1, 1, 0, 0,
|
||||||
tmp);
|
"bind-key %s", tmp);
|
||||||
} else
|
} else
|
||||||
cmdq_print(item, "bind-key %s", tmp);
|
cmdq_print(item, "bind-key %s", tmp);
|
||||||
free(key);
|
free(key);
|
||||||
@ -321,6 +321,31 @@ out:
|
|||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_list_single_command(const struct cmd_entry *entry, struct format_tree *ft,
|
||||||
|
const char *template, struct cmdq_item *item)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
char *line;
|
||||||
|
|
||||||
|
format_add(ft, "command_list_name", "%s", entry->name);
|
||||||
|
if (entry->alias != NULL)
|
||||||
|
s = entry->alias;
|
||||||
|
else
|
||||||
|
s = "";
|
||||||
|
format_add(ft, "command_list_alias", "%s", s);
|
||||||
|
if (entry->usage != NULL)
|
||||||
|
s = entry->usage;
|
||||||
|
else
|
||||||
|
s = "";
|
||||||
|
format_add(ft, "command_list_usage", "%s", s);
|
||||||
|
|
||||||
|
line = format_expand(ft, template);
|
||||||
|
if (*line != '\0')
|
||||||
|
cmdq_print(item, "%s", line);
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
|
||||||
static enum cmd_retval
|
static enum cmd_retval
|
||||||
cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
|
cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
|
||||||
{
|
{
|
||||||
@ -328,8 +353,8 @@ cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
|
|||||||
const struct cmd_entry **entryp;
|
const struct cmd_entry **entryp;
|
||||||
const struct cmd_entry *entry;
|
const struct cmd_entry *entry;
|
||||||
struct format_tree *ft;
|
struct format_tree *ft;
|
||||||
const char *template, *s, *command;
|
const char *template, *command;
|
||||||
char *line;
|
char *cause;
|
||||||
|
|
||||||
if ((template = args_get(args, 'F')) == NULL) {
|
if ((template = args_get(args, 'F')) == NULL) {
|
||||||
template = "#{command_list_name}"
|
template = "#{command_list_name}"
|
||||||
@ -341,30 +366,19 @@ cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
|
|||||||
format_defaults(ft, NULL, NULL, NULL, NULL);
|
format_defaults(ft, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
command = args_string(args, 0);
|
command = args_string(args, 0);
|
||||||
for (entryp = cmd_table; *entryp != NULL; entryp++) {
|
if (command == NULL) {
|
||||||
entry = *entryp;
|
for (entryp = cmd_table; *entryp != NULL; entryp++)
|
||||||
if (command != NULL &&
|
cmd_list_single_command(*entryp, ft, template, item);
|
||||||
(strcmp(entry->name, command) != 0 &&
|
} else {
|
||||||
(entry->alias == NULL ||
|
entry = cmd_find(command, &cause);
|
||||||
strcmp(entry->alias, command) != 0)))
|
if (entry != NULL)
|
||||||
continue;
|
cmd_list_single_command(entry, ft, template, item);
|
||||||
|
else {
|
||||||
format_add(ft, "command_list_name", "%s", entry->name);
|
cmdq_error(item, "%s", cause);
|
||||||
if (entry->alias != NULL)
|
free(cause);
|
||||||
s = entry->alias;
|
format_free(ft);
|
||||||
else
|
return (CMD_RETURN_ERROR);
|
||||||
s = "";
|
}
|
||||||
format_add(ft, "command_list_alias", "%s", s);
|
|
||||||
if (entry->usage != NULL)
|
|
||||||
s = entry->usage;
|
|
||||||
else
|
|
||||||
s = "";
|
|
||||||
format_add(ft, "command_list_usage", "%s", s);
|
|
||||||
|
|
||||||
line = format_expand(ft, template);
|
|
||||||
if (*line != '\0')
|
|
||||||
cmdq_print(item, "%s", line);
|
|
||||||
free(line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
format_free(ft);
|
format_free(ft);
|
||||||
|
@ -43,7 +43,7 @@ const struct cmd_entry cmd_new_session_entry = {
|
|||||||
.usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] "
|
.usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] "
|
||||||
"[-f flags] [-n window-name] [-s session-name] "
|
"[-f flags] [-n window-name] [-s session-name] "
|
||||||
CMD_TARGET_SESSION_USAGE " [-x width] [-y height] "
|
CMD_TARGET_SESSION_USAGE " [-x width] [-y height] "
|
||||||
"[shell-command]",
|
"[shell-command [argument ...]]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
|
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
|
||||||
|
|
||||||
|
@ -40,7 +40,8 @@ const struct cmd_entry cmd_new_window_entry = {
|
|||||||
|
|
||||||
.args = { "abc:de:F:kn:PSt:", 0, -1, NULL },
|
.args = { "abc:de:F:kn:PSt:", 0, -1, NULL },
|
||||||
.usage = "[-abdkPS] [-c start-directory] [-e environment] [-F format] "
|
.usage = "[-abdkPS] [-c start-directory] [-e environment] [-F format] "
|
||||||
"[-n window-name] " CMD_TARGET_WINDOW_USAGE " [shell-command]",
|
"[-n window-name] " CMD_TARGET_WINDOW_USAGE
|
||||||
|
" [shell-command [argument ...]]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
|
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
|
||||||
|
|
||||||
|
32
cmd-parse.y
32
cmd-parse.y
@ -223,9 +223,16 @@ assignment : EQUALS
|
|||||||
{
|
{
|
||||||
struct cmd_parse_state *ps = &parse_state;
|
struct cmd_parse_state *ps = &parse_state;
|
||||||
int flags = ps->input->flags;
|
int flags = ps->input->flags;
|
||||||
|
int flag = 1;
|
||||||
|
struct cmd_parse_scope *scope;
|
||||||
|
|
||||||
if ((~flags & CMD_PARSE_PARSEONLY) &&
|
if (ps->scope != NULL) {
|
||||||
(ps->scope == NULL || ps->scope->flag))
|
flag = ps->scope->flag;
|
||||||
|
TAILQ_FOREACH(scope, &ps->stack, entry)
|
||||||
|
flag = flag && scope->flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((~flags & CMD_PARSE_PARSEONLY) && flag)
|
||||||
environ_put(global_environ, $1, 0);
|
environ_put(global_environ, $1, 0);
|
||||||
free($1);
|
free($1);
|
||||||
}
|
}
|
||||||
@ -234,9 +241,16 @@ hidden_assignment : HIDDEN EQUALS
|
|||||||
{
|
{
|
||||||
struct cmd_parse_state *ps = &parse_state;
|
struct cmd_parse_state *ps = &parse_state;
|
||||||
int flags = ps->input->flags;
|
int flags = ps->input->flags;
|
||||||
|
int flag = 1;
|
||||||
|
struct cmd_parse_scope *scope;
|
||||||
|
|
||||||
if ((~flags & CMD_PARSE_PARSEONLY) &&
|
if (ps->scope != NULL) {
|
||||||
(ps->scope == NULL || ps->scope->flag))
|
flag = ps->scope->flag;
|
||||||
|
TAILQ_FOREACH(scope, &ps->stack, entry)
|
||||||
|
flag = flag && scope->flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((~flags & CMD_PARSE_PARSEONLY) && flag)
|
||||||
environ_put(global_environ, $2, ENVIRON_HIDDEN);
|
environ_put(global_environ, $2, ENVIRON_HIDDEN);
|
||||||
free($2);
|
free($2);
|
||||||
}
|
}
|
||||||
@ -1613,6 +1627,7 @@ yylex_token_tilde(char **buf, size_t *len)
|
|||||||
static char *
|
static char *
|
||||||
yylex_token(int ch)
|
yylex_token(int ch)
|
||||||
{
|
{
|
||||||
|
struct cmd_parse_state *ps = &parse_state;
|
||||||
char *buf;
|
char *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
enum { START,
|
enum { START,
|
||||||
@ -1636,9 +1651,12 @@ yylex_token(int ch)
|
|||||||
ch = '\r';
|
ch = '\r';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (state == NONE && ch == '\n') {
|
if (ch == '\n') {
|
||||||
log_debug("%s: end at EOL", __func__);
|
if (state == NONE) {
|
||||||
break;
|
log_debug("%s: end at EOL", __func__);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ps->input->line++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Whitespace or ; or } ends a token unless inside quotes. */
|
/* Whitespace or ; or } ends a token unless inside quotes. */
|
||||||
|
@ -834,9 +834,9 @@ cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
|
|||||||
|
|
||||||
/* Show message from command. */
|
/* Show message from command. */
|
||||||
void
|
void
|
||||||
cmdq_print_data(struct cmdq_item *item, int parse, struct evbuffer *evb)
|
cmdq_print_data(struct cmdq_item *item, struct evbuffer *evb)
|
||||||
{
|
{
|
||||||
server_client_print(item->client, parse, evb);
|
server_client_print(item->client, 1, evb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Show message from command. */
|
/* Show message from command. */
|
||||||
@ -854,7 +854,7 @@ cmdq_print(struct cmdq_item *item, const char *fmt, ...)
|
|||||||
evbuffer_add_vprintf(evb, fmt, ap);
|
evbuffer_add_vprintf(evb, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
cmdq_print_data(item, 0, evb);
|
cmdq_print_data(item, evb);
|
||||||
evbuffer_free(evb);
|
evbuffer_free(evb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -892,7 +892,7 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
|
|||||||
c->retval = 1;
|
c->retval = 1;
|
||||||
} else {
|
} else {
|
||||||
*msg = toupper((u_char) *msg);
|
*msg = toupper((u_char) *msg);
|
||||||
status_message_set(c, -1, 1, 0, "%s", msg);
|
status_message_set(c, -1, 1, 0, 0, "%s", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(msg);
|
free(msg);
|
||||||
|
@ -36,7 +36,7 @@ const struct cmd_entry cmd_refresh_client_entry = {
|
|||||||
|
|
||||||
.args = { "A:B:cC:Df:r:F:l::LRSt:U", 0, 1, NULL },
|
.args = { "A:B:cC:Df:r:F:l::LRSt:U", 0, 1, NULL },
|
||||||
.usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] "
|
.usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] "
|
||||||
"[-C XxY] [-f flags] [-r pane:report]" CMD_TARGET_CLIENT_USAGE
|
"[-C XxY] [-f flags] [-r pane:report] " CMD_TARGET_CLIENT_USAGE
|
||||||
" [adjustment]",
|
" [adjustment]",
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
|
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
|
||||||
|
@ -36,7 +36,7 @@ const struct cmd_entry cmd_respawn_pane_entry = {
|
|||||||
|
|
||||||
.args = { "c:e:kt:", 0, -1, NULL },
|
.args = { "c:e:kt:", 0, -1, NULL },
|
||||||
.usage = "[-k] [-c start-directory] [-e environment] "
|
.usage = "[-k] [-c start-directory] [-e environment] "
|
||||||
CMD_TARGET_PANE_USAGE " [shell-command]",
|
CMD_TARGET_PANE_USAGE " [shell-command [argument ...]]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ const struct cmd_entry cmd_respawn_window_entry = {
|
|||||||
|
|
||||||
.args = { "c:e:kt:", 0, -1, NULL },
|
.args = { "c:e:kt:", 0, -1, NULL },
|
||||||
.usage = "[-k] [-c start-directory] [-e environment] "
|
.usage = "[-k] [-c start-directory] [-e environment] "
|
||||||
CMD_TARGET_WINDOW_USAGE " [shell-command]",
|
CMD_TARGET_WINDOW_USAGE " [shell-command [argument ...]]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_WINDOW, 0 },
|
.target = { 't', CMD_FIND_WINDOW, 0 },
|
||||||
|
|
||||||
|
@ -44,8 +44,8 @@ const struct cmd_entry cmd_run_shell_entry = {
|
|||||||
.name = "run-shell",
|
.name = "run-shell",
|
||||||
.alias = "run",
|
.alias = "run",
|
||||||
|
|
||||||
.args = { "bd:Ct:c:", 0, 2, cmd_run_shell_args_parse },
|
.args = { "bd:Ct:Es:c:", 0, 1, cmd_run_shell_args_parse },
|
||||||
.usage = "[-bC] [-c start-directory] [-d delay] " CMD_TARGET_PANE_USAGE
|
.usage = "[-bCE] [-c start-directory] [-d delay] " CMD_TARGET_PANE_USAGE
|
||||||
" [shell-command]",
|
" [shell-command]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||||
@ -158,6 +158,9 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
else
|
else
|
||||||
cdata->cwd = xstrdup(server_client_get_cwd(c, s));
|
cdata->cwd = xstrdup(server_client_get_cwd(c, s));
|
||||||
|
|
||||||
|
if (args_has(args, 'E'))
|
||||||
|
cdata->flags |= JOB_SHOWSTDERR;
|
||||||
|
|
||||||
cdata->s = s;
|
cdata->s = s;
|
||||||
if (s != NULL)
|
if (s != NULL)
|
||||||
session_add_ref(s, __func__);
|
session_add_ref(s, __func__);
|
||||||
@ -204,7 +207,7 @@ cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
|
|||||||
if (cmdlist == NULL) {
|
if (cmdlist == NULL) {
|
||||||
if (cdata->item == NULL) {
|
if (cdata->item == NULL) {
|
||||||
*error = toupper((u_char)*error);
|
*error = toupper((u_char)*error);
|
||||||
status_message_set(c, -1, 1, 0, "%s", error);
|
status_message_set(c, -1, 1, 0, 0, "%s", error);
|
||||||
} else
|
} else
|
||||||
cmdq_error(cdata->item, "%s", error);
|
cmdq_error(cdata->item, "%s", error);
|
||||||
free(error);
|
free(error);
|
||||||
|
@ -101,7 +101,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (evb == NULL)
|
if (evb == NULL)
|
||||||
fatalx("out of memory");
|
fatalx("out of memory");
|
||||||
evbuffer_add(evb, bufdata, bufsize);
|
evbuffer_add(evb, bufdata, bufsize);
|
||||||
cmdq_print_data(item, 1, evb);
|
cmdq_print_data(item, evb);
|
||||||
evbuffer_free(evb);
|
evbuffer_free(evb);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
@ -149,12 +149,14 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
markedwp = marked_pane.wp;
|
markedwp = marked_pane.wp;
|
||||||
|
|
||||||
if (lastwp != NULL) {
|
if (lastwp != NULL) {
|
||||||
lastwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
|
lastwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
|
||||||
|
PANE_THEMECHANGED);
|
||||||
server_redraw_window_borders(lastwp->window);
|
server_redraw_window_borders(lastwp->window);
|
||||||
server_status_window(lastwp->window);
|
server_status_window(lastwp->window);
|
||||||
}
|
}
|
||||||
if (markedwp != NULL) {
|
if (markedwp != NULL) {
|
||||||
markedwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
|
markedwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
|
||||||
|
PANE_THEMECHANGED);
|
||||||
server_redraw_window_borders(markedwp->window);
|
server_redraw_window_borders(markedwp->window);
|
||||||
server_status_window(markedwp->window);
|
server_status_window(markedwp->window);
|
||||||
}
|
}
|
||||||
@ -169,7 +171,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
options_set_string(oo, "window-active-style", 0, "%s", style);
|
options_set_string(oo, "window-active-style", 0, "%s", style);
|
||||||
wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
|
wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||||
}
|
}
|
||||||
if (args_has(args, 'g')) {
|
if (args_has(args, 'g')) {
|
||||||
cmdq_print(item, "%s", options_get_string(oo, "window-style"));
|
cmdq_print(item, "%s", options_get_string(oo, "window-style"));
|
||||||
|
@ -35,7 +35,7 @@ const struct cmd_entry cmd_send_keys_entry = {
|
|||||||
|
|
||||||
.args = { "c:FHKlMN:Rt:X", 0, -1, NULL },
|
.args = { "c:FHKlMN:Rt:X", 0, -1, NULL },
|
||||||
.usage = "[-FHKlMRX] [-c target-client] [-N repeat-count] "
|
.usage = "[-FHKlMRX] [-c target-client] [-N repeat-count] "
|
||||||
CMD_TARGET_PANE_USAGE " key ...",
|
CMD_TARGET_PANE_USAGE " [key ...]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
@ -73,11 +73,13 @@ cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after,
|
|||||||
if (args_has(args, 'K')) {
|
if (args_has(args, 'K')) {
|
||||||
if (tc == NULL)
|
if (tc == NULL)
|
||||||
return (item);
|
return (item);
|
||||||
event = xmalloc(sizeof *event);
|
event = xcalloc(1, sizeof *event);
|
||||||
event->key = key|KEYC_SENT;
|
event->key = key|KEYC_SENT;
|
||||||
memset(&event->m, 0, sizeof event->m);
|
memset(&event->m, 0, sizeof event->m);
|
||||||
if (server_client_handle_key(tc, event) == 0)
|
if (server_client_handle_key(tc, event) == 0) {
|
||||||
|
free(event->buf);
|
||||||
free(event);
|
free(event);
|
||||||
|
}
|
||||||
return (item);
|
return (item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +217,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (args_has(args, 'R')) {
|
if (args_has(args, 'R')) {
|
||||||
colour_palette_clear(&wp->palette);
|
colour_palette_clear(&wp->palette);
|
||||||
input_reset(wp->ictx, 1);
|
input_reset(wp->ictx, 1);
|
||||||
wp->flags |= (PANE_STYLECHANGED|PANE_REDRAW);
|
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED|PANE_REDRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
|
@ -35,7 +35,7 @@ const struct cmd_entry cmd_set_buffer_entry = {
|
|||||||
|
|
||||||
.args = { "ab:t:n:w", 0, 1, NULL },
|
.args = { "ab:t:n:w", 0, 1, NULL },
|
||||||
.usage = "[-aw] " CMD_BUFFER_USAGE " [-n new-buffer-name] "
|
.usage = "[-aw] " CMD_BUFFER_USAGE " [-n new-buffer-name] "
|
||||||
CMD_TARGET_CLIENT_USAGE " data",
|
CMD_TARGET_CLIENT_USAGE " [data]",
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL,
|
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL,
|
||||||
.exec = cmd_set_buffer_exec
|
.exec = cmd_set_buffer_exec
|
||||||
|
@ -35,7 +35,7 @@ const struct cmd_entry cmd_set_environment_entry = {
|
|||||||
.alias = "setenv",
|
.alias = "setenv",
|
||||||
|
|
||||||
.args = { "Fhgrt:u", 1, 2, NULL },
|
.args = { "Fhgrt:u", 1, 2, NULL },
|
||||||
.usage = "[-Fhgru] " CMD_TARGET_SESSION_USAGE " name [value]",
|
.usage = "[-Fhgru] " CMD_TARGET_SESSION_USAGE " variable [value]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
|
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ const struct cmd_entry cmd_show_environment_entry = {
|
|||||||
.alias = "showenv",
|
.alias = "showenv",
|
||||||
|
|
||||||
.args = { "hgst:", 0, 1, NULL },
|
.args = { "hgst:", 0, 1, NULL },
|
||||||
.usage = "[-hgs] " CMD_TARGET_SESSION_USAGE " [name]",
|
.usage = "[-hgs] " CMD_TARGET_SESSION_USAGE " [variable]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
|
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ const struct cmd_entry cmd_show_hooks_entry = {
|
|||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "gpt:w", 0, 1, NULL },
|
.args = { "gpt:w", 0, 1, NULL },
|
||||||
.usage = "[-gpw] " CMD_TARGET_PANE_USAGE,
|
.usage = "[-gpw] " CMD_TARGET_PANE_USAGE " [hook]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ const struct cmd_entry cmd_show_prompt_history_entry = {
|
|||||||
.alias = "showphist",
|
.alias = "showphist",
|
||||||
|
|
||||||
.args = { "T:", 0, 0, NULL },
|
.args = { "T:", 0, 0, NULL },
|
||||||
.usage = "[-T type]",
|
.usage = "[-T prompt-type]",
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK,
|
.flags = CMD_AFTERHOOK,
|
||||||
.exec = cmd_show_prompt_history_exec
|
.exec = cmd_show_prompt_history_exec
|
||||||
@ -43,7 +43,7 @@ const struct cmd_entry cmd_clear_prompt_history_entry = {
|
|||||||
.alias = "clearphist",
|
.alias = "clearphist",
|
||||||
|
|
||||||
.args = { "T:", 0, 0, NULL },
|
.args = { "T:", 0, 0, NULL },
|
||||||
.usage = "[-T type]",
|
.usage = "[-T prompt-type]",
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK,
|
.flags = CMD_AFTERHOOK,
|
||||||
.exec = cmd_show_prompt_history_exec
|
.exec = cmd_show_prompt_history_exec
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
* Sources a configuration file.
|
* Sources a configuration file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define CMD_SOURCE_FILE_DEPTH_LIMIT 50
|
||||||
|
static u_int cmd_source_file_depth;
|
||||||
|
|
||||||
static enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmdq_item *);
|
static enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmdq_item *);
|
||||||
|
|
||||||
const struct cmd_entry cmd_source_file_entry = {
|
const struct cmd_entry cmd_source_file_entry = {
|
||||||
@ -59,6 +62,16 @@ struct cmd_source_file_data {
|
|||||||
static enum cmd_retval
|
static enum cmd_retval
|
||||||
cmd_source_file_complete_cb(struct cmdq_item *item, __unused void *data)
|
cmd_source_file_complete_cb(struct cmdq_item *item, __unused void *data)
|
||||||
{
|
{
|
||||||
|
struct client *c = cmdq_get_client(item);
|
||||||
|
|
||||||
|
if (c == NULL) {
|
||||||
|
cmd_source_file_depth--;
|
||||||
|
log_debug("%s: depth now %u", __func__, cmd_source_file_depth);
|
||||||
|
} else {
|
||||||
|
c->source_file_depth--;
|
||||||
|
log_debug("%s: depth now %u", __func__, c->source_file_depth);
|
||||||
|
}
|
||||||
|
|
||||||
cfg_print_causes(item);
|
cfg_print_causes(item);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
@ -121,7 +134,16 @@ cmd_source_file_done(struct client *c, const char *path, int error,
|
|||||||
static void
|
static void
|
||||||
cmd_source_file_add(struct cmd_source_file_data *cdata, const char *path)
|
cmd_source_file_add(struct cmd_source_file_data *cdata, const char *path)
|
||||||
{
|
{
|
||||||
|
char resolved[PATH_MAX];
|
||||||
|
|
||||||
|
if (realpath(path, resolved) == NULL) {
|
||||||
|
log_debug("%s: realpath(\"%s\") failed: %s", __func__,
|
||||||
|
path, strerror(errno));
|
||||||
|
} else
|
||||||
|
path = resolved;
|
||||||
|
|
||||||
log_debug("%s: %s", __func__, path);
|
log_debug("%s: %s", __func__, path);
|
||||||
|
|
||||||
cdata->files = xreallocarray(cdata->files, cdata->nfiles + 1,
|
cdata->files = xreallocarray(cdata->files, cdata->nfiles + 1,
|
||||||
sizeof *cdata->files);
|
sizeof *cdata->files);
|
||||||
cdata->files[cdata->nfiles++] = xstrdup(path);
|
cdata->files[cdata->nfiles++] = xstrdup(path);
|
||||||
@ -140,6 +162,22 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
int result;
|
int result;
|
||||||
u_int i, j;
|
u_int i, j;
|
||||||
|
|
||||||
|
if (c == NULL) {
|
||||||
|
if (cmd_source_file_depth >= CMD_SOURCE_FILE_DEPTH_LIMIT) {
|
||||||
|
cmdq_error(item, "too many nested files");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
cmd_source_file_depth++;
|
||||||
|
log_debug("%s: depth now %u", __func__, cmd_source_file_depth);
|
||||||
|
} else {
|
||||||
|
if (c->source_file_depth >= CMD_SOURCE_FILE_DEPTH_LIMIT) {
|
||||||
|
cmdq_error(item, "too many nested files");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
c->source_file_depth++;
|
||||||
|
log_debug("%s: depth now %u", __func__, c->source_file_depth);
|
||||||
|
}
|
||||||
|
|
||||||
cdata = xcalloc(1, sizeof *cdata);
|
cdata = xcalloc(1, sizeof *cdata);
|
||||||
cdata->item = item;
|
cdata->item = item;
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ const struct cmd_entry cmd_split_window_entry = {
|
|||||||
.args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL },
|
.args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL },
|
||||||
.usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] "
|
.usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] "
|
||||||
"[-F format] [-l size] " CMD_TARGET_PANE_USAGE
|
"[-F format] [-l size] " CMD_TARGET_PANE_USAGE
|
||||||
"[shell-command]",
|
" [shell-command [argument ...]]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
|
@ -101,10 +101,10 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
|
|
||||||
src_wp->window = dst_w;
|
src_wp->window = dst_w;
|
||||||
options_set_parent(src_wp->options, dst_w->options);
|
options_set_parent(src_wp->options, dst_w->options);
|
||||||
src_wp->flags |= PANE_STYLECHANGED;
|
src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||||
dst_wp->window = src_w;
|
dst_wp->window = src_w;
|
||||||
options_set_parent(dst_wp->options, src_w->options);
|
options_set_parent(dst_wp->options, src_w->options);
|
||||||
dst_wp->flags |= PANE_STYLECHANGED;
|
dst_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||||
|
|
||||||
sx = src_wp->sx; sy = src_wp->sy;
|
sx = src_wp->sx; sy = src_wp->sy;
|
||||||
xoff = src_wp->xoff; yoff = src_wp->yoff;
|
xoff = src_wp->xoff; yoff = src_wp->yoff;
|
||||||
@ -132,9 +132,12 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
window_pane_stack_remove(&dst_w->last_panes, dst_wp);
|
window_pane_stack_remove(&dst_w->last_panes, dst_wp);
|
||||||
colour_palette_from_option(&src_wp->palette, src_wp->options);
|
colour_palette_from_option(&src_wp->palette, src_wp->options);
|
||||||
colour_palette_from_option(&dst_wp->palette, dst_wp->options);
|
colour_palette_from_option(&dst_wp->palette, dst_wp->options);
|
||||||
|
layout_fix_panes(src_w, NULL);
|
||||||
|
server_redraw_window(src_w);
|
||||||
}
|
}
|
||||||
server_redraw_window(src_w);
|
layout_fix_panes(dst_w, NULL);
|
||||||
server_redraw_window(dst_w);
|
server_redraw_window(dst_w);
|
||||||
|
|
||||||
notify_window("window-layout-changed", src_w);
|
notify_window("window-layout-changed", src_w);
|
||||||
if (src_w != dst_w)
|
if (src_w != dst_w)
|
||||||
notify_window("window-layout-changed", dst_w);
|
notify_window("window-layout-changed", dst_w);
|
||||||
|
6
cmd.c
6
cmd.c
@ -444,7 +444,7 @@ cmd_get_alias(const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Look up a command entry by name. */
|
/* Look up a command entry by name. */
|
||||||
static const struct cmd_entry *
|
const struct cmd_entry *
|
||||||
cmd_find(const char *name, char **cause)
|
cmd_find(const char *name, char **cause)
|
||||||
{
|
{
|
||||||
const struct cmd_entry **loop, *entry, *found = NULL;
|
const struct cmd_entry **loop, *entry, *found = NULL;
|
||||||
@ -636,7 +636,7 @@ cmd_list_free(struct cmd_list *cmdlist)
|
|||||||
|
|
||||||
/* Copy a command list, expanding %s in arguments. */
|
/* Copy a command list, expanding %s in arguments. */
|
||||||
struct cmd_list *
|
struct cmd_list *
|
||||||
cmd_list_copy(struct cmd_list *cmdlist, int argc, char **argv)
|
cmd_list_copy(const struct cmd_list *cmdlist, int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct cmd *cmd;
|
struct cmd *cmd;
|
||||||
struct cmd_list *new_cmdlist;
|
struct cmd_list *new_cmdlist;
|
||||||
@ -667,7 +667,7 @@ cmd_list_copy(struct cmd_list *cmdlist, int argc, char **argv)
|
|||||||
|
|
||||||
/* Get a command list as a string. */
|
/* Get a command list as a string. */
|
||||||
char *
|
char *
|
||||||
cmd_list_print(struct cmd_list *cmdlist, int escaped)
|
cmd_list_print(const struct cmd_list *cmdlist, int escaped)
|
||||||
{
|
{
|
||||||
struct cmd *cmd, *next;
|
struct cmd *cmd, *next;
|
||||||
char *buf, *this;
|
char *buf, *this;
|
||||||
|
42
colour.c
42
colour.c
@ -182,6 +182,46 @@ colour_tostring(int c)
|
|||||||
return ("invalid");
|
return ("invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert background colour to theme. */
|
||||||
|
enum client_theme
|
||||||
|
colour_totheme(int c)
|
||||||
|
{
|
||||||
|
int r, g, b, brightness;
|
||||||
|
|
||||||
|
if (c == -1)
|
||||||
|
return (THEME_UNKNOWN);
|
||||||
|
|
||||||
|
if (c & COLOUR_FLAG_RGB) {
|
||||||
|
r = (c >> 16) & 0xff;
|
||||||
|
g = (c >> 8) & 0xff;
|
||||||
|
b = (c >> 0) & 0xff;
|
||||||
|
|
||||||
|
brightness = r + g + b;
|
||||||
|
if (brightness > 382)
|
||||||
|
return (THEME_LIGHT);
|
||||||
|
return (THEME_DARK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c & COLOUR_FLAG_256)
|
||||||
|
return (colour_totheme(colour_256toRGB(c)));
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
case 90:
|
||||||
|
return (THEME_DARK);
|
||||||
|
case 7:
|
||||||
|
case 97:
|
||||||
|
return (THEME_LIGHT);
|
||||||
|
default:
|
||||||
|
if (c >= 0 && c <= 7)
|
||||||
|
return (colour_totheme(colour_256toRGB(c)));
|
||||||
|
if (c >= 90 && c <= 97)
|
||||||
|
return (colour_totheme(colour_256toRGB(8 + c - 90)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (THEME_UNKNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
/* Convert colour from string. */
|
/* Convert colour from string. */
|
||||||
int
|
int
|
||||||
colour_fromstring(const char *s)
|
colour_fromstring(const char *s)
|
||||||
@ -948,7 +988,7 @@ colour_byname(const char *name)
|
|||||||
|
|
||||||
if (strncmp(name, "grey", 4) == 0 || strncmp(name, "gray", 4) == 0) {
|
if (strncmp(name, "grey", 4) == 0 || strncmp(name, "gray", 4) == 0) {
|
||||||
if (name[4] == '\0')
|
if (name[4] == '\0')
|
||||||
return (-1);
|
return (0xbebebe|COLOUR_FLAG_RGB);
|
||||||
c = strtonum(name + 4, 0, 100, &errstr);
|
c = strtonum(name + 4, 0, 100, &errstr);
|
||||||
if (errstr != NULL)
|
if (errstr != NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
20
compat.h
20
compat.h
@ -38,6 +38,14 @@
|
|||||||
#include <event2/bufferevent_compat.h>
|
#include <event2/bufferevent_compat.h>
|
||||||
#else
|
#else
|
||||||
#include <event.h>
|
#include <event.h>
|
||||||
|
#ifndef EVBUFFER_EOL_LF
|
||||||
|
/*
|
||||||
|
* This doesn't really work because evbuffer_readline is broken, but gets us to
|
||||||
|
* build with very old (older than 1.4.14) libevent.
|
||||||
|
*/
|
||||||
|
#define EVBUFFER_EOL_LF
|
||||||
|
#define evbuffer_readln(a, b, c) evbuffer_readline(a)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_MALLOC_TRIM
|
#ifdef HAVE_MALLOC_TRIM
|
||||||
@ -442,7 +450,7 @@ void *recallocarray(void *, size_t, size_t, size_t);
|
|||||||
/* systemd.c */
|
/* systemd.c */
|
||||||
int systemd_activated(void);
|
int systemd_activated(void);
|
||||||
int systemd_create_socket(int, char **);
|
int systemd_create_socket(int, char **);
|
||||||
int systemd_move_pid_to_new_cgroup(pid_t, char **);
|
int systemd_move_to_new_cgroup(char **);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_UTF8PROC
|
#ifdef HAVE_UTF8PROC
|
||||||
@ -458,11 +466,11 @@ int utf8proc_wctomb(char *, wchar_t);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* getopt.c */
|
/* getopt.c */
|
||||||
extern int BSDopterr;
|
extern int BSDopterr;
|
||||||
extern int BSDoptind;
|
extern int BSDoptind;
|
||||||
extern int BSDoptopt;
|
extern int BSDoptopt;
|
||||||
extern int BSDoptreset;
|
extern int BSDoptreset;
|
||||||
extern char *BSDoptarg;
|
extern char *BSDoptarg;
|
||||||
int BSDgetopt(int, char *const *, const char *);
|
int BSDgetopt(int, char *const *, const char *);
|
||||||
#define getopt(ac, av, o) BSDgetopt(ac, av, o)
|
#define getopt(ac, av, o) BSDgetopt(ac, av, o)
|
||||||
#define opterr BSDopterr
|
#define opterr BSDopterr
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
clock_gettime(int clock, struct timespec *ts)
|
clock_gettime(__unused int clock, struct timespec *ts)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
|
115
compat/getopt.c
115
compat/getopt.c
@ -1,115 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1987, 1993, 1994
|
|
||||||
* The Regents of the University of California. All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the University nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt.c */
|
|
||||||
|
|
||||||
#include "compat.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
int BSDopterr = 1, /* if error message should be printed */
|
|
||||||
BSDoptind = 1, /* index into parent argv vector */
|
|
||||||
BSDoptopt, /* character checked for validity */
|
|
||||||
BSDoptreset; /* reset getopt */
|
|
||||||
char *BSDoptarg; /* argument associated with option */
|
|
||||||
|
|
||||||
#define BADCH (int)'?'
|
|
||||||
#define BADARG (int)':'
|
|
||||||
#define EMSG ""
|
|
||||||
|
|
||||||
/*
|
|
||||||
* getopt --
|
|
||||||
* Parse argc/argv argument vector.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
BSDgetopt(int nargc, char *const *nargv, const char *ostr)
|
|
||||||
{
|
|
||||||
static const char *place = EMSG; /* option letter processing */
|
|
||||||
char *oli; /* option letter list index */
|
|
||||||
|
|
||||||
if (ostr == NULL)
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
if (BSDoptreset || !*place) { /* update scanning pointer */
|
|
||||||
BSDoptreset = 0;
|
|
||||||
if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') {
|
|
||||||
place = EMSG;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
if (place[1] && *++place == '-') { /* found "--" */
|
|
||||||
if (place[1])
|
|
||||||
return (BADCH);
|
|
||||||
++BSDoptind;
|
|
||||||
place = EMSG;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
} /* option letter okay? */
|
|
||||||
if ((BSDoptopt = (int)*place++) == (int)':' ||
|
|
||||||
!(oli = strchr(ostr, BSDoptopt))) {
|
|
||||||
/*
|
|
||||||
* if the user didn't specify '-' as an option,
|
|
||||||
* assume it means -1.
|
|
||||||
*/
|
|
||||||
if (BSDoptopt == (int)'-')
|
|
||||||
return (-1);
|
|
||||||
if (!*place)
|
|
||||||
++BSDoptind;
|
|
||||||
if (BSDopterr && *ostr != ':')
|
|
||||||
(void)fprintf(stderr,
|
|
||||||
"%s: unknown option -- %c\n", getprogname(),
|
|
||||||
BSDoptopt);
|
|
||||||
return (BADCH);
|
|
||||||
}
|
|
||||||
if (*++oli != ':') { /* don't need argument */
|
|
||||||
BSDoptarg = NULL;
|
|
||||||
if (!*place)
|
|
||||||
++BSDoptind;
|
|
||||||
}
|
|
||||||
else { /* need an argument */
|
|
||||||
if (*place) /* no white space */
|
|
||||||
BSDoptarg = (char *)place;
|
|
||||||
else if (nargc <= ++BSDoptind) { /* no arg */
|
|
||||||
place = EMSG;
|
|
||||||
if (*ostr == ':')
|
|
||||||
return (BADARG);
|
|
||||||
if (BSDopterr)
|
|
||||||
(void)fprintf(stderr,
|
|
||||||
"%s: option requires an argument -- %c\n",
|
|
||||||
getprogname(), BSDoptopt);
|
|
||||||
return (BADCH);
|
|
||||||
}
|
|
||||||
else /* white space */
|
|
||||||
BSDoptarg = nargv[BSDoptind];
|
|
||||||
place = EMSG;
|
|
||||||
++BSDoptind;
|
|
||||||
}
|
|
||||||
return (BSDoptopt); /* dump back option letter */
|
|
||||||
}
|
|
577
compat/getopt_long.c
Normal file
577
compat/getopt_long.c
Normal file
@ -0,0 +1,577 @@
|
|||||||
|
/* This file is obtained from OpenSSH:
|
||||||
|
* Repository: https://github.com/openssh/openssh-portable
|
||||||
|
* Commit: b5b405fee7f3e79d44e2d2971a4b6b4cc53f112e
|
||||||
|
* File: /openbsd-compat/getopt_long.c */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* Sponsored in part by the Defense Advanced Research Projects
|
||||||
|
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||||
|
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||||
|
*/
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to The NetBSD Foundation
|
||||||
|
* by Dieter Baron and Thomas Klausner.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt_long.c */
|
||||||
|
#include "compat.h"
|
||||||
|
|
||||||
|
/* The following macro constants are taken from getopt.h of OpenSSH:
|
||||||
|
* Repository: https://github.com/openssh/openssh-portable
|
||||||
|
* Commit: b5b405fee7f3e79d44e2d2971a4b6b4cc53f112e
|
||||||
|
* File: /openbsd-compat/getopt.h
|
||||||
|
*
|
||||||
|
* ---- BEGIN - Copyright notice and license of getopt.h ----
|
||||||
|
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to The NetBSD Foundation
|
||||||
|
* by Dieter Baron and Thomas Klausner.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
* ---- END ----
|
||||||
|
*/
|
||||||
|
#define no_argument 0
|
||||||
|
#define required_argument 1
|
||||||
|
#define optional_argument 2
|
||||||
|
|
||||||
|
#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET)
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <err.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#endif
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
struct option {
|
||||||
|
/* name of long option */
|
||||||
|
const char *name;
|
||||||
|
/*
|
||||||
|
* one of no_argument, required_argument, and optional_argument:
|
||||||
|
* whether option takes an argument
|
||||||
|
*/
|
||||||
|
int has_arg;
|
||||||
|
/* if not NULL, set *flag to val when option found */
|
||||||
|
int *flag;
|
||||||
|
/* if flag not NULL, value to set *flag to; else return value */
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
|
||||||
|
int opterr = 1; /* if error message should be printed */
|
||||||
|
int optind = 1; /* index into parent argv vector */
|
||||||
|
int optopt = '?'; /* character checked for validity */
|
||||||
|
int optreset; /* reset getopt */
|
||||||
|
char *optarg; /* argument associated with option */
|
||||||
|
|
||||||
|
#define PRINT_ERROR ((opterr) && (*options != ':'))
|
||||||
|
|
||||||
|
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
|
||||||
|
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
|
||||||
|
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
|
||||||
|
|
||||||
|
/* return values */
|
||||||
|
#define BADCH (int)'?'
|
||||||
|
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
|
||||||
|
#define INORDER (int)1
|
||||||
|
|
||||||
|
#define EMSG (char *)""
|
||||||
|
|
||||||
|
static int getopt_internal(int, char * const *, const char *,
|
||||||
|
const struct option *, int *, int);
|
||||||
|
static int parse_long_options(char * const *, const char *,
|
||||||
|
const struct option *, int *, int);
|
||||||
|
static int gcd(int, int);
|
||||||
|
static void permute_args(int, int, int, char * const *);
|
||||||
|
|
||||||
|
static char *place = EMSG; /* option letter processing */
|
||||||
|
|
||||||
|
/* XXX: set optreset to 1 rather than these two */
|
||||||
|
static int nonopt_start = -1; /* first non option argument (for permute) */
|
||||||
|
static int nonopt_end = -1; /* first option after non options (for permute) */
|
||||||
|
|
||||||
|
/* Error messages */
|
||||||
|
static const char recargchar[] = "option requires an argument -- %c";
|
||||||
|
static const char recargstring[] = "option requires an argument -- %s";
|
||||||
|
static const char ambig[] = "ambiguous option -- %.*s";
|
||||||
|
static const char noarg[] = "option doesn't take an argument -- %.*s";
|
||||||
|
static const char illoptchar[] = "unknown option -- %c";
|
||||||
|
static const char illoptstring[] = "unknown option -- %s";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the greatest common divisor of a and b.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
gcd(int a, int b)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
c = a % b;
|
||||||
|
while (c != 0) {
|
||||||
|
a = b;
|
||||||
|
b = c;
|
||||||
|
c = a % b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exchange the block from nonopt_start to nonopt_end with the block
|
||||||
|
* from nonopt_end to opt_end (keeping the same order of arguments
|
||||||
|
* in each block).
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
permute_args(int panonopt_start, int panonopt_end, int opt_end,
|
||||||
|
char * const *nargv)
|
||||||
|
{
|
||||||
|
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
|
||||||
|
char *swap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* compute lengths of blocks and number and size of cycles
|
||||||
|
*/
|
||||||
|
nnonopts = panonopt_end - panonopt_start;
|
||||||
|
nopts = opt_end - panonopt_end;
|
||||||
|
ncycle = gcd(nnonopts, nopts);
|
||||||
|
cyclelen = (opt_end - panonopt_start) / ncycle;
|
||||||
|
|
||||||
|
for (i = 0; i < ncycle; i++) {
|
||||||
|
cstart = panonopt_end+i;
|
||||||
|
pos = cstart;
|
||||||
|
for (j = 0; j < cyclelen; j++) {
|
||||||
|
if (pos >= panonopt_end)
|
||||||
|
pos -= nnonopts;
|
||||||
|
else
|
||||||
|
pos += nopts;
|
||||||
|
swap = nargv[pos];
|
||||||
|
/* LINTED const cast */
|
||||||
|
((char **) nargv)[pos] = nargv[cstart];
|
||||||
|
/* LINTED const cast */
|
||||||
|
((char **)nargv)[cstart] = swap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* parse_long_options --
|
||||||
|
* Parse long options in argc/argv argument vector.
|
||||||
|
* Returns -1 if short_too is set and the option does not match long_options.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parse_long_options(char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx, int short_too)
|
||||||
|
{
|
||||||
|
char *current_argv, *has_equal;
|
||||||
|
size_t current_argv_len;
|
||||||
|
int i, match;
|
||||||
|
|
||||||
|
current_argv = place;
|
||||||
|
match = -1;
|
||||||
|
|
||||||
|
optind++;
|
||||||
|
|
||||||
|
if ((has_equal = strchr(current_argv, '=')) != NULL) {
|
||||||
|
/* argument found (--option=arg) */
|
||||||
|
current_argv_len = has_equal - current_argv;
|
||||||
|
has_equal++;
|
||||||
|
} else
|
||||||
|
current_argv_len = strlen(current_argv);
|
||||||
|
|
||||||
|
for (i = 0; long_options[i].name; i++) {
|
||||||
|
/* find matching long option */
|
||||||
|
if (strncmp(current_argv, long_options[i].name,
|
||||||
|
current_argv_len))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strlen(long_options[i].name) == current_argv_len) {
|
||||||
|
/* exact match */
|
||||||
|
match = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If this is a known short option, don't allow
|
||||||
|
* a partial match of a single character.
|
||||||
|
*/
|
||||||
|
if (short_too && current_argv_len == 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (match == -1) /* partial match */
|
||||||
|
match = i;
|
||||||
|
else {
|
||||||
|
/* ambiguous abbreviation */
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(ambig, (int)current_argv_len,
|
||||||
|
current_argv);
|
||||||
|
optopt = 0;
|
||||||
|
return (BADCH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (match != -1) { /* option found */
|
||||||
|
if (long_options[match].has_arg == no_argument
|
||||||
|
&& has_equal) {
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(noarg, (int)current_argv_len,
|
||||||
|
current_argv);
|
||||||
|
/*
|
||||||
|
* XXX: GNU sets optopt to val regardless of flag
|
||||||
|
*/
|
||||||
|
if (long_options[match].flag == NULL)
|
||||||
|
optopt = long_options[match].val;
|
||||||
|
else
|
||||||
|
optopt = 0;
|
||||||
|
return (BADARG);
|
||||||
|
}
|
||||||
|
if (long_options[match].has_arg == required_argument ||
|
||||||
|
long_options[match].has_arg == optional_argument) {
|
||||||
|
if (has_equal)
|
||||||
|
optarg = has_equal;
|
||||||
|
else if (long_options[match].has_arg ==
|
||||||
|
required_argument) {
|
||||||
|
/*
|
||||||
|
* optional argument doesn't use next nargv
|
||||||
|
*/
|
||||||
|
optarg = nargv[optind++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((long_options[match].has_arg == required_argument)
|
||||||
|
&& (optarg == NULL)) {
|
||||||
|
/*
|
||||||
|
* Missing argument; leading ':' indicates no error
|
||||||
|
* should be generated.
|
||||||
|
*/
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(recargstring,
|
||||||
|
current_argv);
|
||||||
|
/*
|
||||||
|
* XXX: GNU sets optopt to val regardless of flag
|
||||||
|
*/
|
||||||
|
if (long_options[match].flag == NULL)
|
||||||
|
optopt = long_options[match].val;
|
||||||
|
else
|
||||||
|
optopt = 0;
|
||||||
|
--optind;
|
||||||
|
return (BADARG);
|
||||||
|
}
|
||||||
|
} else { /* unknown option */
|
||||||
|
if (short_too) {
|
||||||
|
--optind;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(illoptstring, current_argv);
|
||||||
|
optopt = 0;
|
||||||
|
return (BADCH);
|
||||||
|
}
|
||||||
|
if (idx)
|
||||||
|
*idx = match;
|
||||||
|
if (long_options[match].flag) {
|
||||||
|
*long_options[match].flag = long_options[match].val;
|
||||||
|
return (0);
|
||||||
|
} else
|
||||||
|
return (long_options[match].val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getopt_internal --
|
||||||
|
* Parse argc/argv argument vector. Called by user level routines.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
getopt_internal(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx, int flags)
|
||||||
|
{
|
||||||
|
char *oli; /* option letter list index */
|
||||||
|
int optchar, short_too;
|
||||||
|
static int posixly_correct = -1;
|
||||||
|
|
||||||
|
if (options == NULL)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX Some GNU programs (like cvs) set optind to 0 instead of
|
||||||
|
* XXX using optreset. Work around this braindamage.
|
||||||
|
*/
|
||||||
|
if (optind == 0)
|
||||||
|
optind = optreset = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable GNU extensions if POSIXLY_CORRECT is set or options
|
||||||
|
* string begins with a '+'.
|
||||||
|
*/
|
||||||
|
if (posixly_correct == -1 || optreset)
|
||||||
|
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
|
||||||
|
if (*options == '-')
|
||||||
|
flags |= FLAG_ALLARGS;
|
||||||
|
else if (posixly_correct || *options == '+')
|
||||||
|
flags &= ~FLAG_PERMUTE;
|
||||||
|
if (*options == '+' || *options == '-')
|
||||||
|
options++;
|
||||||
|
|
||||||
|
optarg = NULL;
|
||||||
|
if (optreset)
|
||||||
|
nonopt_start = nonopt_end = -1;
|
||||||
|
start:
|
||||||
|
if (optreset || !*place) { /* update scanning pointer */
|
||||||
|
optreset = 0;
|
||||||
|
if (optind >= nargc) { /* end of argument vector */
|
||||||
|
place = EMSG;
|
||||||
|
if (nonopt_end != -1) {
|
||||||
|
/* do permutation, if we have to */
|
||||||
|
permute_args(nonopt_start, nonopt_end,
|
||||||
|
optind, nargv);
|
||||||
|
optind -= nonopt_end - nonopt_start;
|
||||||
|
}
|
||||||
|
else if (nonopt_start != -1) {
|
||||||
|
/*
|
||||||
|
* If we skipped non-options, set optind
|
||||||
|
* to the first of them.
|
||||||
|
*/
|
||||||
|
optind = nonopt_start;
|
||||||
|
}
|
||||||
|
nonopt_start = nonopt_end = -1;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (*(place = nargv[optind]) != '-' ||
|
||||||
|
(place[1] == '\0' && strchr(options, '-') == NULL)) {
|
||||||
|
place = EMSG; /* found non-option */
|
||||||
|
if (flags & FLAG_ALLARGS) {
|
||||||
|
/*
|
||||||
|
* GNU extension:
|
||||||
|
* return non-option as argument to option 1
|
||||||
|
*/
|
||||||
|
optarg = nargv[optind++];
|
||||||
|
return (INORDER);
|
||||||
|
}
|
||||||
|
if (!(flags & FLAG_PERMUTE)) {
|
||||||
|
/*
|
||||||
|
* If no permutation wanted, stop parsing
|
||||||
|
* at first non-option.
|
||||||
|
*/
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
/* do permutation */
|
||||||
|
if (nonopt_start == -1)
|
||||||
|
nonopt_start = optind;
|
||||||
|
else if (nonopt_end != -1) {
|
||||||
|
permute_args(nonopt_start, nonopt_end,
|
||||||
|
optind, nargv);
|
||||||
|
nonopt_start = optind -
|
||||||
|
(nonopt_end - nonopt_start);
|
||||||
|
nonopt_end = -1;
|
||||||
|
}
|
||||||
|
optind++;
|
||||||
|
/* process next argument */
|
||||||
|
goto start;
|
||||||
|
}
|
||||||
|
if (nonopt_start != -1 && nonopt_end == -1)
|
||||||
|
nonopt_end = optind;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have "-" do nothing, if "--" we are done.
|
||||||
|
*/
|
||||||
|
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
|
||||||
|
optind++;
|
||||||
|
place = EMSG;
|
||||||
|
/*
|
||||||
|
* We found an option (--), so if we skipped
|
||||||
|
* non-options, we have to permute.
|
||||||
|
*/
|
||||||
|
if (nonopt_end != -1) {
|
||||||
|
permute_args(nonopt_start, nonopt_end,
|
||||||
|
optind, nargv);
|
||||||
|
optind -= nonopt_end - nonopt_start;
|
||||||
|
}
|
||||||
|
nonopt_start = nonopt_end = -1;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check long options if:
|
||||||
|
* 1) we were passed some
|
||||||
|
* 2) the arg is not just "-"
|
||||||
|
* 3) either the arg starts with -- we are getopt_long_only()
|
||||||
|
*/
|
||||||
|
if (long_options != NULL && place != nargv[optind] &&
|
||||||
|
(*place == '-' || (flags & FLAG_LONGONLY))) {
|
||||||
|
short_too = 0;
|
||||||
|
if (*place == '-')
|
||||||
|
place++; /* --foo long option */
|
||||||
|
else if (*place != ':' && strchr(options, *place) != NULL)
|
||||||
|
short_too = 1; /* could be short option too */
|
||||||
|
|
||||||
|
optchar = parse_long_options(nargv, options, long_options,
|
||||||
|
idx, short_too);
|
||||||
|
if (optchar != -1) {
|
||||||
|
place = EMSG;
|
||||||
|
return (optchar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((optchar = (int)*place++) == (int)':' ||
|
||||||
|
(optchar == (int)'-' && *place != '\0') ||
|
||||||
|
(oli = strchr(options, optchar)) == NULL) {
|
||||||
|
/*
|
||||||
|
* If the user specified "-" and '-' isn't listed in
|
||||||
|
* options, return -1 (non-option) as per POSIX.
|
||||||
|
* Otherwise, it is an unknown option character (or ':').
|
||||||
|
*/
|
||||||
|
if (optchar == (int)'-' && *place == '\0')
|
||||||
|
return (-1);
|
||||||
|
if (!*place)
|
||||||
|
++optind;
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(illoptchar, optchar);
|
||||||
|
optopt = optchar;
|
||||||
|
return (BADCH);
|
||||||
|
}
|
||||||
|
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
|
||||||
|
/* -W long-option */
|
||||||
|
if (*place) /* no space */
|
||||||
|
/* NOTHING */;
|
||||||
|
else if (++optind >= nargc) { /* no arg */
|
||||||
|
place = EMSG;
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(recargchar, optchar);
|
||||||
|
optopt = optchar;
|
||||||
|
return (BADARG);
|
||||||
|
} else /* white space */
|
||||||
|
place = nargv[optind];
|
||||||
|
optchar = parse_long_options(nargv, options, long_options,
|
||||||
|
idx, 0);
|
||||||
|
place = EMSG;
|
||||||
|
return (optchar);
|
||||||
|
}
|
||||||
|
if (*++oli != ':') { /* doesn't take argument */
|
||||||
|
if (!*place)
|
||||||
|
++optind;
|
||||||
|
} else { /* takes (optional) argument */
|
||||||
|
optarg = NULL;
|
||||||
|
if (*place) /* no white space */
|
||||||
|
optarg = place;
|
||||||
|
else if (oli[1] != ':') { /* arg not optional */
|
||||||
|
if (++optind >= nargc) { /* no arg */
|
||||||
|
place = EMSG;
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(recargchar, optchar);
|
||||||
|
optopt = optchar;
|
||||||
|
return (BADARG);
|
||||||
|
} else
|
||||||
|
optarg = nargv[optind];
|
||||||
|
}
|
||||||
|
place = EMSG;
|
||||||
|
++optind;
|
||||||
|
}
|
||||||
|
/* dump back option letter */
|
||||||
|
return (optchar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getopt --
|
||||||
|
* Parse argc/argv argument vector.
|
||||||
|
*
|
||||||
|
* [eventually this will replace the BSD getopt]
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
getopt(int nargc, char * const *nargv, const char *options)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't pass FLAG_PERMUTE to getopt_internal() since
|
||||||
|
* the BSD getopt(3) (unlike GNU) has never done this.
|
||||||
|
*
|
||||||
|
* Furthermore, since many privileged programs call getopt()
|
||||||
|
* before dropping privileges it makes sense to keep things
|
||||||
|
* as simple (and bug-free) as possible.
|
||||||
|
*/
|
||||||
|
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* getopt_long --
|
||||||
|
* Parse argc/argv argument vector.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
getopt_long(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (getopt_internal(nargc, nargv, options, long_options, idx,
|
||||||
|
FLAG_PERMUTE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getopt_long_only --
|
||||||
|
* Parse argc/argv argument vector.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
getopt_long_only(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (getopt_internal(nargc, nargv, options, long_options, idx,
|
||||||
|
FLAG_PERMUTE|FLAG_LONGONLY));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */
|
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: imsg-buffer.c,v 1.18 2023/12/12 15:47:41 claudio Exp $ */
|
/* $OpenBSD: imsg-buffer.c,v 1.31 2024/11/26 13:57:31 claudio Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
|
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
|
||||||
@ -45,25 +45,37 @@
|
|||||||
#undef be64toh
|
#undef be64toh
|
||||||
#define be64toh ntohll
|
#define be64toh ntohll
|
||||||
|
|
||||||
static int ibuf_realloc(struct ibuf *, size_t);
|
struct msgbuf {
|
||||||
static void ibuf_enqueue(struct msgbuf *, struct ibuf *);
|
TAILQ_HEAD(, ibuf) bufs;
|
||||||
static void ibuf_dequeue(struct msgbuf *, struct ibuf *);
|
TAILQ_HEAD(, ibuf) rbufs;
|
||||||
|
uint32_t queued;
|
||||||
|
char *rbuf;
|
||||||
|
struct ibuf *rpmsg;
|
||||||
|
struct ibuf *(*readhdr)(struct ibuf *, void *, int *);
|
||||||
|
void *rarg;
|
||||||
|
size_t roff;
|
||||||
|
size_t hdrsize;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void msgbuf_read_enqueue(struct msgbuf *, struct ibuf *);
|
||||||
|
static void msgbuf_enqueue(struct msgbuf *, struct ibuf *);
|
||||||
|
static void msgbuf_dequeue(struct msgbuf *, struct ibuf *);
|
||||||
static void msgbuf_drain(struct msgbuf *, size_t);
|
static void msgbuf_drain(struct msgbuf *, size_t);
|
||||||
|
|
||||||
|
#define IBUF_FD_MARK_ON_STACK -2
|
||||||
|
|
||||||
struct ibuf *
|
struct ibuf *
|
||||||
ibuf_open(size_t len)
|
ibuf_open(size_t len)
|
||||||
{
|
{
|
||||||
struct ibuf *buf;
|
struct ibuf *buf;
|
||||||
|
|
||||||
if (len == 0) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
|
if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
if ((buf->buf = calloc(len, 1)) == NULL) {
|
if (len > 0) {
|
||||||
free(buf);
|
if ((buf->buf = calloc(len, 1)) == NULL) {
|
||||||
return (NULL);
|
free(buf);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
buf->size = buf->max = len;
|
buf->size = buf->max = len;
|
||||||
buf->fd = -1;
|
buf->fd = -1;
|
||||||
@ -96,39 +108,36 @@ ibuf_dynamic(size_t len, size_t max)
|
|||||||
return (buf);
|
return (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
ibuf_realloc(struct ibuf *buf, size_t len)
|
|
||||||
{
|
|
||||||
unsigned char *b;
|
|
||||||
|
|
||||||
/* on static buffers max is eq size and so the following fails */
|
|
||||||
if (len > SIZE_MAX - buf->wpos || buf->wpos + len > buf->max) {
|
|
||||||
errno = ERANGE;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
b = recallocarray(buf->buf, buf->size, buf->wpos + len, 1);
|
|
||||||
if (b == NULL)
|
|
||||||
return (-1);
|
|
||||||
buf->buf = b;
|
|
||||||
buf->size = buf->wpos + len;
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
ibuf_reserve(struct ibuf *buf, size_t len)
|
ibuf_reserve(struct ibuf *buf, size_t len)
|
||||||
{
|
{
|
||||||
void *b;
|
void *b;
|
||||||
|
|
||||||
if (len > SIZE_MAX - buf->wpos || buf->max == 0) {
|
if (len > SIZE_MAX - buf->wpos) {
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
if (buf->fd == IBUF_FD_MARK_ON_STACK) {
|
||||||
|
/* can not grow stack buffers */
|
||||||
|
errno = EINVAL;
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (buf->wpos + len > buf->size)
|
if (buf->wpos + len > buf->size) {
|
||||||
if (ibuf_realloc(buf, len) == -1)
|
unsigned char *nb;
|
||||||
|
|
||||||
|
/* check if buffer is allowed to grow */
|
||||||
|
if (buf->wpos + len > buf->max) {
|
||||||
|
errno = ERANGE;
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
}
|
||||||
|
nb = realloc(buf->buf, buf->wpos + len);
|
||||||
|
if (nb == NULL)
|
||||||
|
return (NULL);
|
||||||
|
memset(nb + buf->size, 0, buf->wpos + len - buf->size);
|
||||||
|
buf->buf = nb;
|
||||||
|
buf->size = buf->wpos + len;
|
||||||
|
}
|
||||||
|
|
||||||
b = buf->buf + buf->wpos;
|
b = buf->buf + buf->wpos;
|
||||||
buf->wpos += len;
|
buf->wpos += len;
|
||||||
@ -153,13 +162,6 @@ ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from)
|
|||||||
return ibuf_add(buf, ibuf_data(from), ibuf_size(from));
|
return ibuf_add(buf, ibuf_data(from), ibuf_size(from));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove after tree is converted */
|
|
||||||
int
|
|
||||||
ibuf_add_buf(struct ibuf *buf, const struct ibuf *from)
|
|
||||||
{
|
|
||||||
return ibuf_add_ibuf(buf, from);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
ibuf_add_n8(struct ibuf *buf, uint64_t value)
|
ibuf_add_n8(struct ibuf *buf, uint64_t value)
|
||||||
{
|
{
|
||||||
@ -367,7 +369,8 @@ ibuf_size(const struct ibuf *buf)
|
|||||||
size_t
|
size_t
|
||||||
ibuf_left(const struct ibuf *buf)
|
ibuf_left(const struct ibuf *buf)
|
||||||
{
|
{
|
||||||
if (buf->max == 0)
|
/* on stack buffers have no space left */
|
||||||
|
if (buf->fd == IBUF_FD_MARK_ON_STACK)
|
||||||
return (0);
|
return (0);
|
||||||
return (buf->max - buf->wpos);
|
return (buf->max - buf->wpos);
|
||||||
}
|
}
|
||||||
@ -379,8 +382,8 @@ ibuf_truncate(struct ibuf *buf, size_t len)
|
|||||||
buf->wpos = buf->rpos + len;
|
buf->wpos = buf->rpos + len;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
if (buf->max == 0) {
|
if (buf->fd == IBUF_FD_MARK_ON_STACK) {
|
||||||
/* only allow to truncate down */
|
/* only allow to truncate down for stack buffers */
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
@ -396,7 +399,7 @@ ibuf_rewind(struct ibuf *buf)
|
|||||||
void
|
void
|
||||||
ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
|
ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
|
||||||
{
|
{
|
||||||
ibuf_enqueue(msgbuf, buf);
|
msgbuf_enqueue(msgbuf, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -405,7 +408,7 @@ ibuf_from_buffer(struct ibuf *buf, void *data, size_t len)
|
|||||||
memset(buf, 0, sizeof(*buf));
|
memset(buf, 0, sizeof(*buf));
|
||||||
buf->buf = data;
|
buf->buf = data;
|
||||||
buf->size = buf->wpos = len;
|
buf->size = buf->wpos = len;
|
||||||
buf->fd = -1;
|
buf->fd = IBUF_FD_MARK_ON_STACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -440,6 +443,24 @@ ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ibuf_get_h16(struct ibuf *buf, uint16_t *value)
|
||||||
|
{
|
||||||
|
return ibuf_get(buf, value, sizeof(*value));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ibuf_get_h32(struct ibuf *buf, uint32_t *value)
|
||||||
|
{
|
||||||
|
return ibuf_get(buf, value, sizeof(*value));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ibuf_get_h64(struct ibuf *buf, uint64_t *value)
|
||||||
|
{
|
||||||
|
return ibuf_get(buf, value, sizeof(*value));
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ibuf_get_n8(struct ibuf *buf, uint8_t *value)
|
ibuf_get_n8(struct ibuf *buf, uint8_t *value)
|
||||||
{
|
{
|
||||||
@ -476,22 +497,21 @@ ibuf_get_n64(struct ibuf *buf, uint64_t *value)
|
|||||||
return (rv);
|
return (rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
char *
|
||||||
ibuf_get_h16(struct ibuf *buf, uint16_t *value)
|
ibuf_get_string(struct ibuf *buf, size_t len)
|
||||||
{
|
{
|
||||||
return ibuf_get(buf, value, sizeof(*value));
|
char *str;
|
||||||
}
|
|
||||||
|
|
||||||
int
|
if (ibuf_size(buf) < len) {
|
||||||
ibuf_get_h32(struct ibuf *buf, uint32_t *value)
|
errno = EBADMSG;
|
||||||
{
|
return (NULL);
|
||||||
return ibuf_get(buf, value, sizeof(*value));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int
|
str = strndup(ibuf_data(buf), len);
|
||||||
ibuf_get_h64(struct ibuf *buf, uint64_t *value)
|
if (str == NULL)
|
||||||
{
|
return (NULL);
|
||||||
return ibuf_get(buf, value, sizeof(*value));
|
buf->rpos += len;
|
||||||
|
return (str);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -511,9 +531,10 @@ ibuf_free(struct ibuf *buf)
|
|||||||
{
|
{
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return;
|
return;
|
||||||
if (buf->max == 0) /* if buf lives on the stack */
|
/* if buf lives on the stack abort before causing more harm */
|
||||||
abort(); /* abort before causing more harm */
|
if (buf->fd == IBUF_FD_MARK_ON_STACK)
|
||||||
if (buf->fd != -1)
|
abort();
|
||||||
|
if (buf->fd >= 0)
|
||||||
close(buf->fd);
|
close(buf->fd);
|
||||||
freezero(buf->buf, buf->size);
|
freezero(buf->buf, buf->size);
|
||||||
free(buf);
|
free(buf);
|
||||||
@ -522,7 +543,7 @@ ibuf_free(struct ibuf *buf)
|
|||||||
int
|
int
|
||||||
ibuf_fd_avail(struct ibuf *buf)
|
ibuf_fd_avail(struct ibuf *buf)
|
||||||
{
|
{
|
||||||
return (buf->fd != -1);
|
return (buf->fd >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -530,6 +551,9 @@ ibuf_fd_get(struct ibuf *buf)
|
|||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
/* negative fds are internal use and equivalent to -1 */
|
||||||
|
if (buf->fd < 0)
|
||||||
|
return (-1);
|
||||||
fd = buf->fd;
|
fd = buf->fd;
|
||||||
buf->fd = -1;
|
buf->fd = -1;
|
||||||
return (fd);
|
return (fd);
|
||||||
@ -538,15 +562,107 @@ ibuf_fd_get(struct ibuf *buf)
|
|||||||
void
|
void
|
||||||
ibuf_fd_set(struct ibuf *buf, int fd)
|
ibuf_fd_set(struct ibuf *buf, int fd)
|
||||||
{
|
{
|
||||||
if (buf->max == 0) /* if buf lives on the stack */
|
/* if buf lives on the stack abort before causing more harm */
|
||||||
abort(); /* abort before causing more harm */
|
if (buf->fd == IBUF_FD_MARK_ON_STACK)
|
||||||
if (buf->fd != -1)
|
abort();
|
||||||
|
if (buf->fd >= 0)
|
||||||
close(buf->fd);
|
close(buf->fd);
|
||||||
buf->fd = fd;
|
buf->fd = -1;
|
||||||
|
if (fd >= 0)
|
||||||
|
buf->fd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct msgbuf *
|
||||||
|
msgbuf_new(void)
|
||||||
|
{
|
||||||
|
struct msgbuf *msgbuf;
|
||||||
|
|
||||||
|
if ((msgbuf = calloc(1, sizeof(*msgbuf))) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
msgbuf->queued = 0;
|
||||||
|
TAILQ_INIT(&msgbuf->bufs);
|
||||||
|
TAILQ_INIT(&msgbuf->rbufs);
|
||||||
|
|
||||||
|
return msgbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct msgbuf *
|
||||||
|
msgbuf_new_reader(size_t hdrsz,
|
||||||
|
struct ibuf *(*readhdr)(struct ibuf *, void *, int *), void *arg)
|
||||||
|
{
|
||||||
|
struct msgbuf *msgbuf;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
if (hdrsz == 0 || hdrsz > IBUF_READ_SIZE / 2) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((buf = malloc(IBUF_READ_SIZE)) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
msgbuf = msgbuf_new();
|
||||||
|
if (msgbuf == NULL) {
|
||||||
|
free(buf);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
msgbuf->rbuf = buf;
|
||||||
|
msgbuf->hdrsize = hdrsz;
|
||||||
|
msgbuf->readhdr = readhdr;
|
||||||
|
msgbuf->rarg = arg;
|
||||||
|
|
||||||
|
return (msgbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
msgbuf_free(struct msgbuf *msgbuf)
|
||||||
|
{
|
||||||
|
if (msgbuf == NULL)
|
||||||
|
return;
|
||||||
|
msgbuf_clear(msgbuf);
|
||||||
|
free(msgbuf->rbuf);
|
||||||
|
free(msgbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
msgbuf_queuelen(struct msgbuf *msgbuf)
|
||||||
|
{
|
||||||
|
return (msgbuf->queued);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
msgbuf_clear(struct msgbuf *msgbuf)
|
||||||
|
{
|
||||||
|
struct ibuf *buf;
|
||||||
|
|
||||||
|
/* write side */
|
||||||
|
while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
|
||||||
|
msgbuf_dequeue(msgbuf, buf);
|
||||||
|
msgbuf->queued = 0;
|
||||||
|
|
||||||
|
/* read side */
|
||||||
|
while ((buf = TAILQ_FIRST(&msgbuf->rbufs)) != NULL) {
|
||||||
|
TAILQ_REMOVE(&msgbuf->rbufs, buf, entry);
|
||||||
|
ibuf_free(buf);
|
||||||
|
}
|
||||||
|
msgbuf->roff = 0;
|
||||||
|
ibuf_free(msgbuf->rpmsg);
|
||||||
|
msgbuf->rpmsg = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ibuf *
|
||||||
|
msgbuf_get(struct msgbuf *msgbuf)
|
||||||
|
{
|
||||||
|
struct ibuf *buf;
|
||||||
|
|
||||||
|
if ((buf = TAILQ_FIRST(&msgbuf->rbufs)) != NULL)
|
||||||
|
TAILQ_REMOVE(&msgbuf->rbufs, buf, entry);
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ibuf_write(struct msgbuf *msgbuf)
|
ibuf_write(int fd, struct msgbuf *msgbuf)
|
||||||
{
|
{
|
||||||
struct iovec iov[IOV_MAX];
|
struct iovec iov[IOV_MAX];
|
||||||
struct ibuf *buf;
|
struct ibuf *buf;
|
||||||
@ -561,63 +677,25 @@ ibuf_write(struct msgbuf *msgbuf)
|
|||||||
iov[i].iov_len = ibuf_size(buf);
|
iov[i].iov_len = ibuf_size(buf);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
if (i == 0)
|
||||||
|
return (0); /* nothing queued */
|
||||||
|
|
||||||
again:
|
again:
|
||||||
if ((n = writev(msgbuf->fd, iov, i)) == -1) {
|
if ((n = writev(fd, iov, i)) == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
goto again;
|
goto again;
|
||||||
if (errno == ENOBUFS)
|
if (errno == EAGAIN || errno == ENOBUFS)
|
||||||
errno = EAGAIN;
|
/* lets retry later again */
|
||||||
|
return (0);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n == 0) { /* connection closed */
|
|
||||||
errno = 0;
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
msgbuf_drain(msgbuf, n);
|
msgbuf_drain(msgbuf, n);
|
||||||
|
return (0);
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
msgbuf_init(struct msgbuf *msgbuf)
|
|
||||||
{
|
|
||||||
msgbuf->queued = 0;
|
|
||||||
msgbuf->fd = -1;
|
|
||||||
TAILQ_INIT(&msgbuf->bufs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
msgbuf_drain(struct msgbuf *msgbuf, size_t n)
|
|
||||||
{
|
|
||||||
struct ibuf *buf, *next;
|
|
||||||
|
|
||||||
for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
|
|
||||||
buf = next) {
|
|
||||||
next = TAILQ_NEXT(buf, entry);
|
|
||||||
if (n >= ibuf_size(buf)) {
|
|
||||||
n -= ibuf_size(buf);
|
|
||||||
ibuf_dequeue(msgbuf, buf);
|
|
||||||
} else {
|
|
||||||
buf->rpos += n;
|
|
||||||
n = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
msgbuf_clear(struct msgbuf *msgbuf)
|
|
||||||
{
|
|
||||||
struct ibuf *buf;
|
|
||||||
|
|
||||||
while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
|
|
||||||
ibuf_dequeue(msgbuf, buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
msgbuf_write(struct msgbuf *msgbuf)
|
msgbuf_write(int fd, struct msgbuf *msgbuf)
|
||||||
{
|
{
|
||||||
struct iovec iov[IOV_MAX];
|
struct iovec iov[IOV_MAX];
|
||||||
struct ibuf *buf, *buf0 = NULL;
|
struct ibuf *buf, *buf0 = NULL;
|
||||||
@ -645,6 +723,9 @@ msgbuf_write(struct msgbuf *msgbuf)
|
|||||||
buf0 = buf;
|
buf0 = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
return (0); /* nothing queued */
|
||||||
|
|
||||||
msg.msg_iov = iov;
|
msg.msg_iov = iov;
|
||||||
msg.msg_iovlen = i;
|
msg.msg_iovlen = i;
|
||||||
|
|
||||||
@ -658,20 +739,16 @@ msgbuf_write(struct msgbuf *msgbuf)
|
|||||||
*(int *)CMSG_DATA(cmsg) = buf0->fd;
|
*(int *)CMSG_DATA(cmsg) = buf0->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
again:
|
again:
|
||||||
if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
|
if ((n = sendmsg(fd, &msg, 0)) == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
goto again;
|
goto again;
|
||||||
if (errno == ENOBUFS)
|
if (errno == EAGAIN || errno == ENOBUFS)
|
||||||
errno = EAGAIN;
|
/* lets retry later again */
|
||||||
|
return (0);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n == 0) { /* connection closed */
|
|
||||||
errno = 0;
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assumption: fd got sent if sendmsg sent anything
|
* assumption: fd got sent if sendmsg sent anything
|
||||||
* this works because fds are passed one at a time
|
* this works because fds are passed one at a time
|
||||||
@ -683,28 +760,209 @@ again:
|
|||||||
|
|
||||||
msgbuf_drain(msgbuf, n);
|
msgbuf_drain(msgbuf, n);
|
||||||
|
|
||||||
return (1);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
static int
|
||||||
msgbuf_queuelen(struct msgbuf *msgbuf)
|
ibuf_read_process(struct msgbuf *msgbuf, int fd)
|
||||||
{
|
{
|
||||||
return (msgbuf->queued);
|
struct ibuf rbuf, msg;
|
||||||
|
ssize_t sz;
|
||||||
|
|
||||||
|
ibuf_from_buffer(&rbuf, msgbuf->rbuf, msgbuf->roff);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (msgbuf->rpmsg == NULL) {
|
||||||
|
if (ibuf_size(&rbuf) < msgbuf->hdrsize)
|
||||||
|
break;
|
||||||
|
/* get size from header */
|
||||||
|
ibuf_from_buffer(&msg, ibuf_data(&rbuf),
|
||||||
|
msgbuf->hdrsize);
|
||||||
|
if ((msgbuf->rpmsg = msgbuf->readhdr(&msg,
|
||||||
|
msgbuf->rarg, &fd)) == NULL)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ibuf_left(msgbuf->rpmsg) <= ibuf_size(&rbuf))
|
||||||
|
sz = ibuf_left(msgbuf->rpmsg);
|
||||||
|
else
|
||||||
|
sz = ibuf_size(&rbuf);
|
||||||
|
|
||||||
|
/* neither call below can fail */
|
||||||
|
if (ibuf_get_ibuf(&rbuf, sz, &msg) == -1 ||
|
||||||
|
ibuf_add_ibuf(msgbuf->rpmsg, &msg) == -1)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (ibuf_left(msgbuf->rpmsg) == 0) {
|
||||||
|
msgbuf_read_enqueue(msgbuf, msgbuf->rpmsg);
|
||||||
|
msgbuf->rpmsg = NULL;
|
||||||
|
}
|
||||||
|
} while (ibuf_size(&rbuf) > 0);
|
||||||
|
|
||||||
|
if (ibuf_size(&rbuf) > 0)
|
||||||
|
memmove(msgbuf->rbuf, ibuf_data(&rbuf), ibuf_size(&rbuf));
|
||||||
|
msgbuf->roff = ibuf_size(&rbuf);
|
||||||
|
|
||||||
|
if (fd != -1)
|
||||||
|
close(fd);
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
/* XXX how to properly clean up is unclear */
|
||||||
|
if (fd != -1)
|
||||||
|
close(fd);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ibuf_read(int fd, struct msgbuf *msgbuf)
|
||||||
|
{
|
||||||
|
struct iovec iov;
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
if (msgbuf->rbuf == NULL) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
iov.iov_base = msgbuf->rbuf + msgbuf->roff;
|
||||||
|
iov.iov_len = IBUF_READ_SIZE - msgbuf->roff;
|
||||||
|
|
||||||
|
again:
|
||||||
|
if ((n = readv(fd, &iov, 1)) == -1) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
goto again;
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
/* lets retry later again */
|
||||||
|
return (1);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (n == 0) /* connection closed */
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
msgbuf->roff += n;
|
||||||
|
/* new data arrived, try to process it */
|
||||||
|
return (ibuf_read_process(msgbuf, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
msgbuf_read(int fd, struct msgbuf *msgbuf)
|
||||||
|
{
|
||||||
|
struct msghdr msg;
|
||||||
|
struct cmsghdr *cmsg;
|
||||||
|
union {
|
||||||
|
struct cmsghdr hdr;
|
||||||
|
char buf[CMSG_SPACE(sizeof(int) * 1)];
|
||||||
|
} cmsgbuf;
|
||||||
|
struct iovec iov;
|
||||||
|
ssize_t n;
|
||||||
|
int fdpass = -1;
|
||||||
|
|
||||||
|
if (msgbuf->rbuf == NULL) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
|
||||||
|
|
||||||
|
iov.iov_base = msgbuf->rbuf + msgbuf->roff;
|
||||||
|
iov.iov_len = IBUF_READ_SIZE - msgbuf->roff;
|
||||||
|
msg.msg_iov = &iov;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
msg.msg_control = &cmsgbuf.buf;
|
||||||
|
msg.msg_controllen = sizeof(cmsgbuf.buf);
|
||||||
|
|
||||||
|
again:
|
||||||
|
if ((n = recvmsg(fd, &msg, 0)) == -1) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
goto again;
|
||||||
|
if (errno == EMSGSIZE)
|
||||||
|
/*
|
||||||
|
* Not enough fd slots: fd passing failed, retry
|
||||||
|
* to receive the message without fd.
|
||||||
|
* imsg_get_fd() will return -1 in that case.
|
||||||
|
*/
|
||||||
|
goto again;
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
/* lets retry later again */
|
||||||
|
return (1);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (n == 0) /* connection closed */
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
msgbuf->roff += n;
|
||||||
|
|
||||||
|
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
||||||
|
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||||
|
if (cmsg->cmsg_level == SOL_SOCKET &&
|
||||||
|
cmsg->cmsg_type == SCM_RIGHTS) {
|
||||||
|
int i, j, f;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We only accept one file descriptor. Due to C
|
||||||
|
* padding rules, our control buffer might contain
|
||||||
|
* more than one fd, and we must close them.
|
||||||
|
*/
|
||||||
|
j = ((char *)cmsg + cmsg->cmsg_len -
|
||||||
|
(char *)CMSG_DATA(cmsg)) / sizeof(int);
|
||||||
|
for (i = 0; i < j; i++) {
|
||||||
|
f = ((int *)CMSG_DATA(cmsg))[i];
|
||||||
|
if (i == 0)
|
||||||
|
fdpass = f;
|
||||||
|
else
|
||||||
|
close(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* we do not handle other ctl data level */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* new data arrived, try to process it */
|
||||||
|
return (ibuf_read_process(msgbuf, fdpass));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
|
msgbuf_read_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
|
||||||
{
|
{
|
||||||
if (buf->max == 0) /* if buf lives on the stack */
|
/* if buf lives on the stack abort before causing more harm */
|
||||||
abort(); /* abort before causing more harm */
|
if (buf->fd == IBUF_FD_MARK_ON_STACK)
|
||||||
|
abort();
|
||||||
|
TAILQ_INSERT_TAIL(&msgbuf->rbufs, buf, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
msgbuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
|
||||||
|
{
|
||||||
|
/* if buf lives on the stack abort before causing more harm */
|
||||||
|
if (buf->fd == IBUF_FD_MARK_ON_STACK)
|
||||||
|
abort();
|
||||||
TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
|
TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
|
||||||
msgbuf->queued++;
|
msgbuf->queued++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
|
msgbuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
|
||||||
{
|
{
|
||||||
TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
|
TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
|
||||||
msgbuf->queued--;
|
msgbuf->queued--;
|
||||||
ibuf_free(buf);
|
ibuf_free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
msgbuf_drain(struct msgbuf *msgbuf, size_t n)
|
||||||
|
{
|
||||||
|
struct ibuf *buf, *next;
|
||||||
|
|
||||||
|
for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
|
||||||
|
buf = next) {
|
||||||
|
next = TAILQ_NEXT(buf, entry);
|
||||||
|
if (n >= ibuf_size(buf)) {
|
||||||
|
n -= ibuf_size(buf);
|
||||||
|
msgbuf_dequeue(msgbuf, buf);
|
||||||
|
} else {
|
||||||
|
buf->rpos += n;
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
296
compat/imsg.c
296
compat/imsg.c
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: imsg.c,v 1.23 2023/12/12 15:47:41 claudio Exp $ */
|
/* $OpenBSD: imsg.c,v 1.37 2024/11/26 13:57:31 claudio Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
|
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
|
||||||
@ -22,6 +22,7 @@
|
|||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -29,158 +30,110 @@
|
|||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "imsg.h"
|
#include "imsg.h"
|
||||||
|
|
||||||
struct imsg_fd {
|
#define IMSG_ALLOW_FDPASS 0x01
|
||||||
TAILQ_ENTRY(imsg_fd) entry;
|
#define IMSG_FD_MARK 0x80000000U
|
||||||
int fd;
|
|
||||||
};
|
|
||||||
|
|
||||||
int imsg_fd_overhead = 0;
|
static struct ibuf *imsg_parse_hdr(struct ibuf *, void *, int *);
|
||||||
|
|
||||||
static int imsg_dequeue_fd(struct imsgbuf *);
|
int
|
||||||
|
imsgbuf_init(struct imsgbuf *imsgbuf, int fd)
|
||||||
void
|
|
||||||
imsg_init(struct imsgbuf *imsgbuf, int fd)
|
|
||||||
{
|
{
|
||||||
msgbuf_init(&imsgbuf->w);
|
imsgbuf->w = msgbuf_new_reader(IMSG_HEADER_SIZE, imsg_parse_hdr,
|
||||||
memset(&imsgbuf->r, 0, sizeof(imsgbuf->r));
|
imsgbuf);
|
||||||
imsgbuf->fd = fd;
|
if (imsgbuf->w == NULL)
|
||||||
imsgbuf->w.fd = fd;
|
return (-1);
|
||||||
imsgbuf->pid = getpid();
|
imsgbuf->pid = getpid();
|
||||||
TAILQ_INIT(&imsgbuf->fds);
|
imsgbuf->maxsize = MAX_IMSGSIZE;
|
||||||
|
imsgbuf->fd = fd;
|
||||||
|
imsgbuf->flags = 0;
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t
|
void
|
||||||
imsg_read(struct imsgbuf *imsgbuf)
|
imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf)
|
||||||
{
|
{
|
||||||
struct msghdr msg;
|
imsgbuf->flags |= IMSG_ALLOW_FDPASS;
|
||||||
struct cmsghdr *cmsg;
|
}
|
||||||
union {
|
|
||||||
struct cmsghdr hdr;
|
|
||||||
char buf[CMSG_SPACE(sizeof(int) * 1)];
|
|
||||||
} cmsgbuf;
|
|
||||||
struct iovec iov;
|
|
||||||
ssize_t n = -1;
|
|
||||||
int fd;
|
|
||||||
struct imsg_fd *ifd;
|
|
||||||
|
|
||||||
memset(&msg, 0, sizeof(msg));
|
int
|
||||||
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
|
imsgbuf_set_maxsize(struct imsgbuf *imsgbuf, uint32_t maxsize)
|
||||||
|
{
|
||||||
iov.iov_base = imsgbuf->r.buf + imsgbuf->r.wpos;
|
if (maxsize < IMSG_HEADER_SIZE || maxsize & IMSG_FD_MARK) {
|
||||||
iov.iov_len = sizeof(imsgbuf->r.buf) - imsgbuf->r.wpos;
|
errno = EINVAL;
|
||||||
msg.msg_iov = &iov;
|
|
||||||
msg.msg_iovlen = 1;
|
|
||||||
msg.msg_control = &cmsgbuf.buf;
|
|
||||||
msg.msg_controllen = sizeof(cmsgbuf.buf);
|
|
||||||
|
|
||||||
if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL)
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
again:
|
|
||||||
if (getdtablecount() + imsg_fd_overhead +
|
|
||||||
(int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))
|
|
||||||
>= getdtablesize()) {
|
|
||||||
errno = EAGAIN;
|
|
||||||
free(ifd);
|
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
imsgbuf->maxsize = maxsize;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
if ((n = recvmsg(imsgbuf->fd, &msg, 0)) == -1) {
|
int
|
||||||
if (errno == EINTR)
|
imsgbuf_read(struct imsgbuf *imsgbuf)
|
||||||
goto again;
|
{
|
||||||
goto fail;
|
if (imsgbuf->flags & IMSG_ALLOW_FDPASS)
|
||||||
|
return msgbuf_read(imsgbuf->fd, imsgbuf->w);
|
||||||
|
else
|
||||||
|
return ibuf_read(imsgbuf->fd, imsgbuf->w);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
imsgbuf_write(struct imsgbuf *imsgbuf)
|
||||||
|
{
|
||||||
|
if (imsgbuf->flags & IMSG_ALLOW_FDPASS)
|
||||||
|
return msgbuf_write(imsgbuf->fd, imsgbuf->w);
|
||||||
|
else
|
||||||
|
return ibuf_write(imsgbuf->fd, imsgbuf->w);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
imsgbuf_flush(struct imsgbuf *imsgbuf)
|
||||||
|
{
|
||||||
|
while (imsgbuf_queuelen(imsgbuf) > 0) {
|
||||||
|
if (imsgbuf_write(imsgbuf) == -1)
|
||||||
|
return (-1);
|
||||||
}
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
imsgbuf->r.wpos += n;
|
void
|
||||||
|
imsgbuf_clear(struct imsgbuf *imsgbuf)
|
||||||
|
{
|
||||||
|
msgbuf_free(imsgbuf->w);
|
||||||
|
imsgbuf->w = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
uint32_t
|
||||||
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
imsgbuf_queuelen(struct imsgbuf *imsgbuf)
|
||||||
if (cmsg->cmsg_level == SOL_SOCKET &&
|
{
|
||||||
cmsg->cmsg_type == SCM_RIGHTS) {
|
return msgbuf_queuelen(imsgbuf->w);
|
||||||
int i;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We only accept one file descriptor. Due to C
|
|
||||||
* padding rules, our control buffer might contain
|
|
||||||
* more than one fd, and we must close them.
|
|
||||||
*/
|
|
||||||
j = ((char *)cmsg + cmsg->cmsg_len -
|
|
||||||
(char *)CMSG_DATA(cmsg)) / sizeof(int);
|
|
||||||
for (i = 0; i < j; i++) {
|
|
||||||
fd = ((int *)CMSG_DATA(cmsg))[i];
|
|
||||||
if (ifd != NULL) {
|
|
||||||
ifd->fd = fd;
|
|
||||||
TAILQ_INSERT_TAIL(&imsgbuf->fds, ifd,
|
|
||||||
entry);
|
|
||||||
ifd = NULL;
|
|
||||||
} else
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* we do not handle other ctl data level */
|
|
||||||
}
|
|
||||||
|
|
||||||
fail:
|
|
||||||
free(ifd);
|
|
||||||
return (n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
imsg_get(struct imsgbuf *imsgbuf, struct imsg *imsg)
|
imsg_get(struct imsgbuf *imsgbuf, struct imsg *imsg)
|
||||||
{
|
{
|
||||||
struct imsg m;
|
struct imsg m;
|
||||||
size_t av, left, datalen;
|
struct ibuf *buf;
|
||||||
|
|
||||||
av = imsgbuf->r.wpos;
|
if ((buf = msgbuf_get(imsgbuf->w)) == NULL)
|
||||||
|
|
||||||
if (IMSG_HEADER_SIZE > av)
|
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
memcpy(&m.hdr, imsgbuf->r.buf, sizeof(m.hdr));
|
if (ibuf_get(buf, &m.hdr, sizeof(m.hdr)) == -1)
|
||||||
if (m.hdr.len < IMSG_HEADER_SIZE ||
|
|
||||||
m.hdr.len > MAX_IMSGSIZE) {
|
|
||||||
errno = ERANGE;
|
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
|
||||||
if (m.hdr.len > av)
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
m.fd = -1;
|
if (ibuf_size(buf))
|
||||||
m.buf = NULL;
|
m.data = ibuf_data(buf);
|
||||||
m.data = NULL;
|
else
|
||||||
|
m.data = NULL;
|
||||||
datalen = m.hdr.len - IMSG_HEADER_SIZE;
|
m.buf = buf;
|
||||||
imsgbuf->r.rptr = imsgbuf->r.buf + IMSG_HEADER_SIZE;
|
m.hdr.len &= ~IMSG_FD_MARK;
|
||||||
if (datalen != 0) {
|
|
||||||
if ((m.buf = ibuf_open(datalen)) == NULL)
|
|
||||||
return (-1);
|
|
||||||
if (ibuf_add(m.buf, imsgbuf->r.rptr, datalen) == -1) {
|
|
||||||
/* this should never fail */
|
|
||||||
ibuf_free(m.buf);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
m.data = ibuf_data(m.buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m.hdr.flags & IMSGF_HASFD)
|
|
||||||
m.fd = imsg_dequeue_fd(imsgbuf);
|
|
||||||
|
|
||||||
if (m.hdr.len < av) {
|
|
||||||
left = av - m.hdr.len;
|
|
||||||
memmove(&imsgbuf->r.buf, imsgbuf->r.buf + m.hdr.len, left);
|
|
||||||
imsgbuf->r.wpos = left;
|
|
||||||
} else
|
|
||||||
imsgbuf->r.wpos = 0;
|
|
||||||
|
|
||||||
*imsg = m;
|
*imsg = m;
|
||||||
return (datalen + IMSG_HEADER_SIZE);
|
return (ibuf_size(buf) + IMSG_HEADER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
imsg_get_ibuf(struct imsg *imsg, struct ibuf *ibuf)
|
imsg_get_ibuf(struct imsg *imsg, struct ibuf *ibuf)
|
||||||
{
|
{
|
||||||
if (imsg->buf == NULL) {
|
if (ibuf_size(imsg->buf) == 0) {
|
||||||
errno = EBADMSG;
|
errno = EBADMSG;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
@ -194,7 +147,7 @@ imsg_get_data(struct imsg *imsg, void *data, size_t len)
|
|||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
if (imsg->buf == NULL || ibuf_size(imsg->buf) != len) {
|
if (ibuf_size(imsg->buf) != len) {
|
||||||
errno = EBADMSG;
|
errno = EBADMSG;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
@ -204,10 +157,7 @@ imsg_get_data(struct imsg *imsg, void *data, size_t len)
|
|||||||
int
|
int
|
||||||
imsg_get_fd(struct imsg *imsg)
|
imsg_get_fd(struct imsg *imsg)
|
||||||
{
|
{
|
||||||
int fd = imsg->fd;
|
return ibuf_fd_get(imsg->buf);
|
||||||
|
|
||||||
imsg->fd = -1;
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
@ -219,8 +169,6 @@ imsg_get_id(struct imsg *imsg)
|
|||||||
size_t
|
size_t
|
||||||
imsg_get_len(struct imsg *imsg)
|
imsg_get_len(struct imsg *imsg)
|
||||||
{
|
{
|
||||||
if (imsg->buf == NULL)
|
|
||||||
return 0;
|
|
||||||
return ibuf_size(imsg->buf);
|
return ibuf_size(imsg->buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,14 +238,13 @@ imsg_compose_ibuf(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id,
|
|||||||
struct imsg_hdr hdr;
|
struct imsg_hdr hdr;
|
||||||
int save_errno;
|
int save_errno;
|
||||||
|
|
||||||
if (ibuf_size(buf) + IMSG_HEADER_SIZE > MAX_IMSGSIZE) {
|
if (ibuf_size(buf) + IMSG_HEADER_SIZE > imsgbuf->maxsize) {
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
hdr.type = type;
|
hdr.type = type;
|
||||||
hdr.len = ibuf_size(buf) + IMSG_HEADER_SIZE;
|
hdr.len = ibuf_size(buf) + IMSG_HEADER_SIZE;
|
||||||
hdr.flags = 0;
|
|
||||||
hdr.peerid = id;
|
hdr.peerid = id;
|
||||||
if ((hdr.pid = pid) == 0)
|
if ((hdr.pid = pid) == 0)
|
||||||
hdr.pid = imsgbuf->pid;
|
hdr.pid = imsgbuf->pid;
|
||||||
@ -307,8 +254,8 @@ imsg_compose_ibuf(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id,
|
|||||||
if (imsg_add(hdrbuf, &hdr, sizeof(hdr)) == -1)
|
if (imsg_add(hdrbuf, &hdr, sizeof(hdr)) == -1)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
ibuf_close(&imsgbuf->w, hdrbuf);
|
ibuf_close(imsgbuf->w, hdrbuf);
|
||||||
ibuf_close(&imsgbuf->w, buf);
|
ibuf_close(imsgbuf->w, buf);
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
@ -326,24 +273,18 @@ int
|
|||||||
imsg_forward(struct imsgbuf *imsgbuf, struct imsg *msg)
|
imsg_forward(struct imsgbuf *imsgbuf, struct imsg *msg)
|
||||||
{
|
{
|
||||||
struct ibuf *wbuf;
|
struct ibuf *wbuf;
|
||||||
size_t len = 0;
|
size_t len;
|
||||||
|
|
||||||
if (msg->fd != -1) {
|
ibuf_rewind(msg->buf);
|
||||||
close(msg->fd);
|
ibuf_skip(msg->buf, sizeof(msg->hdr));
|
||||||
msg->fd = -1;
|
len = ibuf_size(msg->buf);
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->buf != NULL) {
|
|
||||||
ibuf_rewind(msg->buf);
|
|
||||||
len = ibuf_size(msg->buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((wbuf = imsg_create(imsgbuf, msg->hdr.type, msg->hdr.peerid,
|
if ((wbuf = imsg_create(imsgbuf, msg->hdr.type, msg->hdr.peerid,
|
||||||
msg->hdr.pid, len)) == NULL)
|
msg->hdr.pid, len)) == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
if (msg->buf != NULL) {
|
if (len != 0) {
|
||||||
if (ibuf_add_buf(wbuf, msg->buf) == -1) {
|
if (ibuf_add_ibuf(wbuf, msg->buf) == -1) {
|
||||||
ibuf_free(wbuf);
|
ibuf_free(wbuf);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
@ -361,17 +302,16 @@ imsg_create(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
|
|||||||
struct imsg_hdr hdr;
|
struct imsg_hdr hdr;
|
||||||
|
|
||||||
datalen += IMSG_HEADER_SIZE;
|
datalen += IMSG_HEADER_SIZE;
|
||||||
if (datalen > MAX_IMSGSIZE) {
|
if (datalen > imsgbuf->maxsize) {
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
hdr.type = type;
|
hdr.type = type;
|
||||||
hdr.flags = 0;
|
|
||||||
hdr.peerid = id;
|
hdr.peerid = id;
|
||||||
if ((hdr.pid = pid) == 0)
|
if ((hdr.pid = pid) == 0)
|
||||||
hdr.pid = imsgbuf->pid;
|
hdr.pid = imsgbuf->pid;
|
||||||
if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
|
if ((wbuf = ibuf_dynamic(datalen, imsgbuf->maxsize)) == NULL) {
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
|
if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
|
||||||
@ -395,15 +335,13 @@ void
|
|||||||
imsg_close(struct imsgbuf *imsgbuf, struct ibuf *msg)
|
imsg_close(struct imsgbuf *imsgbuf, struct ibuf *msg)
|
||||||
{
|
{
|
||||||
struct imsg_hdr *hdr;
|
struct imsg_hdr *hdr;
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
hdr = (struct imsg_hdr *)msg->buf;
|
len = ibuf_size(msg);
|
||||||
|
|
||||||
hdr->flags &= ~IMSGF_HASFD;
|
|
||||||
if (ibuf_fd_avail(msg))
|
if (ibuf_fd_avail(msg))
|
||||||
hdr->flags |= IMSGF_HASFD;
|
len |= IMSG_FD_MARK;
|
||||||
hdr->len = ibuf_size(msg);
|
(void)ibuf_set_h32(msg, offsetof(struct imsg_hdr, len), len);
|
||||||
|
ibuf_close(imsgbuf->w, msg);
|
||||||
ibuf_close(&imsgbuf->w, msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -412,37 +350,29 @@ imsg_free(struct imsg *imsg)
|
|||||||
ibuf_free(imsg->buf);
|
ibuf_free(imsg->buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static struct ibuf *
|
||||||
imsg_dequeue_fd(struct imsgbuf *imsgbuf)
|
imsg_parse_hdr(struct ibuf *buf, void *arg, int *fd)
|
||||||
{
|
{
|
||||||
int fd;
|
struct imsgbuf *imsgbuf = arg;
|
||||||
struct imsg_fd *ifd;
|
struct imsg_hdr hdr;
|
||||||
|
struct ibuf *b;
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
if ((ifd = TAILQ_FIRST(&imsgbuf->fds)) == NULL)
|
if (ibuf_get(buf, &hdr, sizeof(hdr)) == -1)
|
||||||
return (-1);
|
return (NULL);
|
||||||
|
|
||||||
fd = ifd->fd;
|
len = hdr.len & ~IMSG_FD_MARK;
|
||||||
TAILQ_REMOVE(&imsgbuf->fds, ifd, entry);
|
|
||||||
free(ifd);
|
|
||||||
|
|
||||||
return (fd);
|
if (len < IMSG_HEADER_SIZE || len > imsgbuf->maxsize) {
|
||||||
}
|
errno = ERANGE;
|
||||||
|
return (NULL);
|
||||||
int
|
}
|
||||||
imsg_flush(struct imsgbuf *imsgbuf)
|
if ((b = ibuf_open(len)) == NULL)
|
||||||
{
|
return (NULL);
|
||||||
while (imsgbuf->w.queued)
|
if (hdr.len & IMSG_FD_MARK) {
|
||||||
if (msgbuf_write(&imsgbuf->w) <= 0)
|
ibuf_fd_set(b, *fd);
|
||||||
return (-1);
|
*fd = -1;
|
||||||
return (0);
|
}
|
||||||
}
|
|
||||||
|
return b;
|
||||||
void
|
|
||||||
imsg_clear(struct imsgbuf *imsgbuf)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
msgbuf_clear(&imsgbuf->w);
|
|
||||||
while ((fd = imsg_dequeue_fd(imsgbuf)) != -1)
|
|
||||||
close(fd);
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: imsg.h,v 1.8 2023/12/12 15:47:41 claudio Exp $ */
|
/* $OpenBSD: imsg.h,v 1.19 2024/11/26 13:57:31 claudio Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
|
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
|
||||||
@ -38,40 +38,25 @@ struct ibuf {
|
|||||||
int fd;
|
int fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct msgbuf {
|
struct msgbuf;
|
||||||
TAILQ_HEAD(, ibuf) bufs;
|
|
||||||
uint32_t queued;
|
|
||||||
int fd;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ibuf_read {
|
|
||||||
unsigned char buf[IBUF_READ_SIZE];
|
|
||||||
unsigned char *rptr;
|
|
||||||
size_t wpos;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct imsg_fd;
|
|
||||||
struct imsgbuf {
|
struct imsgbuf {
|
||||||
TAILQ_HEAD(, imsg_fd) fds;
|
struct msgbuf *w;
|
||||||
struct ibuf_read r;
|
|
||||||
struct msgbuf w;
|
|
||||||
int fd;
|
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
uint32_t maxsize;
|
||||||
|
int fd;
|
||||||
|
int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IMSGF_HASFD 1
|
|
||||||
|
|
||||||
struct imsg_hdr {
|
struct imsg_hdr {
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
uint16_t len;
|
uint32_t len;
|
||||||
uint16_t flags;
|
|
||||||
uint32_t peerid;
|
uint32_t peerid;
|
||||||
uint32_t pid;
|
uint32_t pid;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct imsg {
|
struct imsg {
|
||||||
struct imsg_hdr hdr;
|
struct imsg_hdr hdr;
|
||||||
int fd;
|
|
||||||
void *data;
|
void *data;
|
||||||
struct ibuf *buf;
|
struct ibuf *buf;
|
||||||
};
|
};
|
||||||
@ -82,7 +67,6 @@ struct iovec;
|
|||||||
struct ibuf *ibuf_open(size_t);
|
struct ibuf *ibuf_open(size_t);
|
||||||
struct ibuf *ibuf_dynamic(size_t, size_t);
|
struct ibuf *ibuf_dynamic(size_t, size_t);
|
||||||
int ibuf_add(struct ibuf *, const void *, size_t);
|
int ibuf_add(struct ibuf *, const void *, size_t);
|
||||||
int ibuf_add_buf(struct ibuf *, const struct ibuf *);
|
|
||||||
int ibuf_add_ibuf(struct ibuf *, const struct ibuf *);
|
int ibuf_add_ibuf(struct ibuf *, const struct ibuf *);
|
||||||
int ibuf_add_zero(struct ibuf *, size_t);
|
int ibuf_add_zero(struct ibuf *, size_t);
|
||||||
int ibuf_add_n8(struct ibuf *, uint64_t);
|
int ibuf_add_n8(struct ibuf *, uint64_t);
|
||||||
@ -119,20 +103,33 @@ int ibuf_get_n64(struct ibuf *, uint64_t *);
|
|||||||
int ibuf_get_h16(struct ibuf *, uint16_t *);
|
int ibuf_get_h16(struct ibuf *, uint16_t *);
|
||||||
int ibuf_get_h32(struct ibuf *, uint32_t *);
|
int ibuf_get_h32(struct ibuf *, uint32_t *);
|
||||||
int ibuf_get_h64(struct ibuf *, uint64_t *);
|
int ibuf_get_h64(struct ibuf *, uint64_t *);
|
||||||
|
char *ibuf_get_string(struct ibuf *, size_t);
|
||||||
int ibuf_skip(struct ibuf *, size_t);
|
int ibuf_skip(struct ibuf *, size_t);
|
||||||
void ibuf_free(struct ibuf *);
|
void ibuf_free(struct ibuf *);
|
||||||
int ibuf_fd_avail(struct ibuf *);
|
int ibuf_fd_avail(struct ibuf *);
|
||||||
int ibuf_fd_get(struct ibuf *);
|
int ibuf_fd_get(struct ibuf *);
|
||||||
void ibuf_fd_set(struct ibuf *, int);
|
void ibuf_fd_set(struct ibuf *, int);
|
||||||
int ibuf_write(struct msgbuf *);
|
struct msgbuf *msgbuf_new(void);
|
||||||
void msgbuf_init(struct msgbuf *);
|
struct msgbuf *msgbuf_new_reader(size_t,
|
||||||
|
struct ibuf *(*)(struct ibuf *, void *, int *), void *);
|
||||||
|
void msgbuf_free(struct msgbuf *);
|
||||||
void msgbuf_clear(struct msgbuf *);
|
void msgbuf_clear(struct msgbuf *);
|
||||||
uint32_t msgbuf_queuelen(struct msgbuf *);
|
uint32_t msgbuf_queuelen(struct msgbuf *);
|
||||||
int msgbuf_write(struct msgbuf *);
|
int ibuf_write(int, struct msgbuf *);
|
||||||
|
int msgbuf_write(int, struct msgbuf *);
|
||||||
|
int ibuf_read(int, struct msgbuf *);
|
||||||
|
int msgbuf_read(int, struct msgbuf *);
|
||||||
|
struct ibuf *msgbuf_get(struct msgbuf *);
|
||||||
|
|
||||||
/* imsg.c */
|
/* imsg.c */
|
||||||
void imsg_init(struct imsgbuf *, int);
|
int imsgbuf_init(struct imsgbuf *, int);
|
||||||
ssize_t imsg_read(struct imsgbuf *);
|
void imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf);
|
||||||
|
int imsgbuf_set_maxsize(struct imsgbuf *, uint32_t);
|
||||||
|
int imsgbuf_read(struct imsgbuf *);
|
||||||
|
int imsgbuf_write(struct imsgbuf *);
|
||||||
|
int imsgbuf_flush(struct imsgbuf *);
|
||||||
|
void imsgbuf_clear(struct imsgbuf *);
|
||||||
|
uint32_t imsgbuf_queuelen(struct imsgbuf *);
|
||||||
ssize_t imsg_get(struct imsgbuf *, struct imsg *);
|
ssize_t imsg_get(struct imsgbuf *, struct imsg *);
|
||||||
int imsg_get_ibuf(struct imsg *, struct ibuf *);
|
int imsg_get_ibuf(struct imsg *, struct ibuf *);
|
||||||
int imsg_get_data(struct imsg *, void *, size_t);
|
int imsg_get_data(struct imsg *, void *, size_t);
|
||||||
@ -152,7 +149,5 @@ struct ibuf *imsg_create(struct imsgbuf *, uint32_t, uint32_t, pid_t, size_t);
|
|||||||
int imsg_add(struct ibuf *, const void *, size_t);
|
int imsg_add(struct ibuf *, const void *, size_t);
|
||||||
void imsg_close(struct imsgbuf *, struct ibuf *);
|
void imsg_close(struct imsgbuf *, struct ibuf *);
|
||||||
void imsg_free(struct imsg *);
|
void imsg_free(struct imsg *);
|
||||||
int imsg_flush(struct imsgbuf *);
|
|
||||||
void imsg_clear(struct imsgbuf *);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
118
compat/systemd.c
118
compat/systemd.c
@ -30,6 +30,11 @@
|
|||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
|
#ifndef SD_ID128_UUID_FORMAT_STR
|
||||||
|
#define SD_ID128_UUID_FORMAT_STR \
|
||||||
|
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
|
||||||
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
systemd_activated(void)
|
systemd_activated(void)
|
||||||
{
|
{
|
||||||
@ -70,16 +75,49 @@ fail:
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
struct systemd_job_watch {
|
||||||
systemd_move_pid_to_new_cgroup(pid_t pid, char **cause)
|
const char *path;
|
||||||
|
int done;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
job_removed_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
|
||||||
{
|
{
|
||||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
struct systemd_job_watch *watch = userdata;
|
||||||
sd_bus_message *m = NULL, *reply = NULL;
|
const char *path = NULL;
|
||||||
sd_bus *bus = NULL;
|
uint32_t id;
|
||||||
char *name, *desc, *slice;
|
int r;
|
||||||
sd_id128_t uuid;
|
|
||||||
int r;
|
/* This handler could be called during the sd_bus_call. */
|
||||||
pid_t parent_pid;
|
if (watch->path == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = sd_bus_message_read(m, "uo", &id, &path);
|
||||||
|
if (r < 0)
|
||||||
|
return (r);
|
||||||
|
|
||||||
|
if (strcmp(path, watch->path) == 0)
|
||||||
|
watch->done = 1;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
systemd_move_to_new_cgroup(char **cause)
|
||||||
|
{
|
||||||
|
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
|
sd_bus_message *m = NULL, *reply = NULL;
|
||||||
|
sd_bus *bus = NULL;
|
||||||
|
sd_bus_slot *slot = NULL;
|
||||||
|
char *name, *desc, *slice;
|
||||||
|
sd_id128_t uuid;
|
||||||
|
int r;
|
||||||
|
uint64_t elapsed_usec;
|
||||||
|
pid_t pid, parent_pid;
|
||||||
|
struct timeval start, now;
|
||||||
|
struct systemd_job_watch watch = {};
|
||||||
|
|
||||||
|
gettimeofday(&start, NULL);
|
||||||
|
|
||||||
/* Connect to the session bus. */
|
/* Connect to the session bus. */
|
||||||
r = sd_bus_default_user(&bus);
|
r = sd_bus_default_user(&bus);
|
||||||
@ -89,6 +127,20 @@ systemd_move_pid_to_new_cgroup(pid_t pid, char **cause)
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Start watching for JobRemoved events */
|
||||||
|
r = sd_bus_match_signal(bus, &slot,
|
||||||
|
"org.freedesktop.systemd1",
|
||||||
|
"/org/freedesktop/systemd1",
|
||||||
|
"org.freedesktop.systemd1.Manager",
|
||||||
|
"JobRemoved",
|
||||||
|
job_removed_handler,
|
||||||
|
&watch);
|
||||||
|
if (r < 0) {
|
||||||
|
xasprintf(cause, "failed to create match signal: %s",
|
||||||
|
strerror(-r));
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
/* Start building the method call. */
|
/* Start building the method call. */
|
||||||
r = sd_bus_message_new_method_call(bus, &m,
|
r = sd_bus_message_new_method_call(bus, &m,
|
||||||
"org.freedesktop.systemd1",
|
"org.freedesktop.systemd1",
|
||||||
@ -133,7 +185,8 @@ systemd_move_pid_to_new_cgroup(pid_t pid, char **cause)
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
parent_pid = getpid();
|
pid = getpid();
|
||||||
|
parent_pid = getppid();
|
||||||
xasprintf(&desc, "tmux child pane %ld launched by process %ld",
|
xasprintf(&desc, "tmux child pane %ld launched by process %ld",
|
||||||
(long)pid, (long)parent_pid);
|
(long)pid, (long)parent_pid);
|
||||||
r = sd_bus_message_append(m, "(sv)", "Description", "s", desc);
|
r = sd_bus_message_append(m, "(sv)", "Description", "s", desc);
|
||||||
@ -218,10 +271,55 @@ systemd_move_pid_to_new_cgroup(pid_t pid, char **cause)
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the job (object path) from the reply */
|
||||||
|
r = sd_bus_message_read(reply, "o", &watch.path);
|
||||||
|
if (r < 0) {
|
||||||
|
xasprintf(cause, "failed to parse method reply: %s",
|
||||||
|
strerror(-r));
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!watch.done) {
|
||||||
|
/* Process events including callbacks. */
|
||||||
|
r = sd_bus_process(bus, NULL);
|
||||||
|
if (r < 0) {
|
||||||
|
xasprintf(cause,
|
||||||
|
"failed waiting for cgroup allocation: %s",
|
||||||
|
strerror(-r));
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A positive return means we handled an event and should keep
|
||||||
|
* processing; zero indicates no events available, so wait.
|
||||||
|
*/
|
||||||
|
if (r > 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
elapsed_usec = (now.tv_sec - start.tv_sec) * 1000000 +
|
||||||
|
now.tv_usec - start.tv_usec;
|
||||||
|
|
||||||
|
if (elapsed_usec >= 1000000) {
|
||||||
|
xasprintf(cause,
|
||||||
|
"timeout waiting for cgroup allocation");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_bus_wait(bus, 1000000 - elapsed_usec);
|
||||||
|
if (r < 0) {
|
||||||
|
xasprintf(cause,
|
||||||
|
"failed waiting for cgroup allocation: %s",
|
||||||
|
strerror(-r));
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
sd_bus_error_free(&error);
|
sd_bus_error_free(&error);
|
||||||
sd_bus_message_unref(m);
|
sd_bus_message_unref(m);
|
||||||
sd_bus_message_unref(reply);
|
sd_bus_message_unref(reply);
|
||||||
|
sd_bus_slot_unref(slot);
|
||||||
sd_bus_unref(bus);
|
sd_bus_unref(bus);
|
||||||
|
|
||||||
return (r);
|
return (r);
|
||||||
|
11
configure.ac
11
configure.ac
@ -1,6 +1,6 @@
|
|||||||
# configure.ac
|
# configure.ac
|
||||||
|
|
||||||
AC_INIT([tmux], 3.5)
|
AC_INIT([tmux], next-3.6)
|
||||||
AC_PREREQ([2.60])
|
AC_PREREQ([2.60])
|
||||||
|
|
||||||
AC_CONFIG_AUX_DIR(etc)
|
AC_CONFIG_AUX_DIR(etc)
|
||||||
@ -219,7 +219,7 @@ AC_SEARCH_LIBS(clock_gettime, rt)
|
|||||||
# musl does not set optarg to NULL for flags without arguments (although it is
|
# musl does not set optarg to NULL for flags without arguments (although it is
|
||||||
# not required to, but it is helpful) 3) there are probably other weird
|
# not required to, but it is helpful) 3) there are probably other weird
|
||||||
# implementations.
|
# implementations.
|
||||||
AC_LIBOBJ(getopt)
|
AC_LIBOBJ(getopt_long)
|
||||||
|
|
||||||
# Look for libevent. Try libevent_core or libevent with pkg-config first then
|
# Look for libevent. Try libevent_core or libevent with pkg-config first then
|
||||||
# look for the library.
|
# look for the library.
|
||||||
@ -638,9 +638,9 @@ else
|
|||||||
AC_LIBOBJ(err)
|
AC_LIBOBJ(err)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Look for imsg_init in libutil.
|
# Look for imsg_add in libutil.
|
||||||
AC_SEARCH_LIBS(imsg_init, util, found_imsg_init=yes, found_imsg_init=no)
|
AC_SEARCH_LIBS(imsg_add, util, found_imsg_add=yes, found_imsg_add=no)
|
||||||
if test "x$found_imsg_init" = xyes; then
|
if test "x$found_imsg_add" = xyes; then
|
||||||
AC_DEFINE(HAVE_IMSG)
|
AC_DEFINE(HAVE_IMSG)
|
||||||
else
|
else
|
||||||
AC_LIBOBJ(imsg)
|
AC_LIBOBJ(imsg)
|
||||||
@ -982,6 +982,7 @@ AM_CONDITIONAL(IS_NETBSD, test "x$PLATFORM" = xnetbsd)
|
|||||||
AM_CONDITIONAL(IS_OPENBSD, test "x$PLATFORM" = xopenbsd)
|
AM_CONDITIONAL(IS_OPENBSD, test "x$PLATFORM" = xopenbsd)
|
||||||
AM_CONDITIONAL(IS_SUNOS, test "x$PLATFORM" = xsunos)
|
AM_CONDITIONAL(IS_SUNOS, test "x$PLATFORM" = xsunos)
|
||||||
AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux)
|
AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux)
|
||||||
|
AM_CONDITIONAL(IS_CYGWIN, test "x$PLATFORM" = xcygwin)
|
||||||
AM_CONDITIONAL(IS_HAIKU, test "x$PLATFORM" = xhaiku)
|
AM_CONDITIONAL(IS_HAIKU, test "x$PLATFORM" = xhaiku)
|
||||||
AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown)
|
AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown)
|
||||||
|
|
||||||
|
@ -719,7 +719,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
|||||||
int focus_start = -1, focus_end = -1;
|
int focus_start = -1, focus_end = -1;
|
||||||
int list_state = -1, fill = -1, even;
|
int list_state = -1, fill = -1, even;
|
||||||
enum style_align list_align = STYLE_ALIGN_DEFAULT;
|
enum style_align list_align = STYLE_ALIGN_DEFAULT;
|
||||||
struct grid_cell gc, current_default;
|
struct grid_cell gc, current_default, base_default;
|
||||||
struct style sy, saved_sy;
|
struct style sy, saved_sy;
|
||||||
struct utf8_data *ud = &sy.gc.data;
|
struct utf8_data *ud = &sy.gc.data;
|
||||||
const char *cp, *end;
|
const char *cp, *end;
|
||||||
@ -729,7 +729,9 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
|||||||
struct format_ranges frs;
|
struct format_ranges frs;
|
||||||
struct style_range *sr;
|
struct style_range *sr;
|
||||||
|
|
||||||
|
memcpy(&base_default, base, sizeof base_default);
|
||||||
memcpy(¤t_default, base, sizeof current_default);
|
memcpy(¤t_default, base, sizeof current_default);
|
||||||
|
base = &base_default;
|
||||||
style_set(&sy, ¤t_default);
|
style_set(&sy, ¤t_default);
|
||||||
TAILQ_INIT(&frs);
|
TAILQ_INIT(&frs);
|
||||||
log_debug("%s: %s", __func__, expanded);
|
log_debug("%s: %s", __func__, expanded);
|
||||||
@ -847,6 +849,12 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
|||||||
} else if (sy.default_type == STYLE_DEFAULT_POP) {
|
} else if (sy.default_type == STYLE_DEFAULT_POP) {
|
||||||
memcpy(¤t_default, base, sizeof current_default);
|
memcpy(¤t_default, base, sizeof current_default);
|
||||||
sy.default_type = STYLE_DEFAULT_BASE;
|
sy.default_type = STYLE_DEFAULT_BASE;
|
||||||
|
} else if (sy.default_type == STYLE_DEFAULT_SET) {
|
||||||
|
memcpy(&base_default, &saved_sy.gc,
|
||||||
|
sizeof base_default);
|
||||||
|
memcpy(¤t_default, &saved_sy.gc,
|
||||||
|
sizeof current_default);
|
||||||
|
sy.default_type = STYLE_DEFAULT_BASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the list state. */
|
/* Check the list state. */
|
||||||
|
538
format.c
538
format.c
@ -104,6 +104,9 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
|
|||||||
#define FORMAT_CHARACTER 0x10000
|
#define FORMAT_CHARACTER 0x10000
|
||||||
#define FORMAT_COLOUR 0x20000
|
#define FORMAT_COLOUR 0x20000
|
||||||
#define FORMAT_CLIENTS 0x40000
|
#define FORMAT_CLIENTS 0x40000
|
||||||
|
#define FORMAT_NOT 0x80000
|
||||||
|
#define FORMAT_NOT_NOT 0x100000
|
||||||
|
#define FORMAT_REPEAT 0x200000
|
||||||
|
|
||||||
/* Limit on recursion. */
|
/* Limit on recursion. */
|
||||||
#define FORMAT_LOOP_LIMIT 100
|
#define FORMAT_LOOP_LIMIT 100
|
||||||
@ -129,6 +132,18 @@ enum format_type {
|
|||||||
FORMAT_TYPE_PANE
|
FORMAT_TYPE_PANE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Format loop sort type. */
|
||||||
|
enum format_loop_sort_type {
|
||||||
|
FORMAT_LOOP_BY_INDEX,
|
||||||
|
FORMAT_LOOP_BY_NAME,
|
||||||
|
FORMAT_LOOP_BY_TIME,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct format_loop_sort_criteria {
|
||||||
|
u_int field;
|
||||||
|
int reversed;
|
||||||
|
} format_loop_sort_criteria;
|
||||||
|
|
||||||
struct format_tree {
|
struct format_tree {
|
||||||
enum format_type type;
|
enum format_type type;
|
||||||
|
|
||||||
@ -203,7 +218,7 @@ static const char *format_upper[] = {
|
|||||||
"window_name", /* W */
|
"window_name", /* W */
|
||||||
NULL, /* X */
|
NULL, /* X */
|
||||||
NULL, /* Y */
|
NULL, /* Y */
|
||||||
NULL /* Z */
|
NULL /* Z */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Single-character lowercase aliases. */
|
/* Single-character lowercase aliases. */
|
||||||
@ -863,7 +878,7 @@ format_cb_history_bytes(struct format_tree *ft)
|
|||||||
struct window_pane *wp = ft->wp;
|
struct window_pane *wp = ft->wp;
|
||||||
struct grid *gd;
|
struct grid *gd;
|
||||||
struct grid_line *gl;
|
struct grid_line *gl;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
u_int i;
|
u_int i;
|
||||||
char *value;
|
char *value;
|
||||||
|
|
||||||
@ -1119,6 +1134,20 @@ format_cb_cursor_character(struct format_tree *ft)
|
|||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Callback for cursor_colour. */
|
||||||
|
static void *
|
||||||
|
format_cb_cursor_colour(struct format_tree *ft)
|
||||||
|
{
|
||||||
|
struct window_pane *wp = ft->wp;
|
||||||
|
|
||||||
|
if (wp == NULL || wp->screen == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
if (wp->screen->ccolour != -1)
|
||||||
|
return (xstrdup(colour_tostring(wp->screen->ccolour)));
|
||||||
|
return (xstrdup(colour_tostring(wp->screen->default_ccolour)));
|
||||||
|
}
|
||||||
|
|
||||||
/* Callback for mouse_word. */
|
/* Callback for mouse_word. */
|
||||||
static void *
|
static void *
|
||||||
format_cb_mouse_word(struct format_tree *ft)
|
format_cb_mouse_word(struct format_tree *ft)
|
||||||
@ -1159,6 +1188,12 @@ format_cb_mouse_hyperlink(struct format_tree *ft)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
|
if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
|
if (!TAILQ_EMPTY(&wp->modes)) {
|
||||||
|
if (window_pane_mode(wp) != WINDOW_PANE_NO_MODE)
|
||||||
|
return (window_copy_get_hyperlink(wp, x, y));
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
gd = wp->base.grid;
|
gd = wp->base.grid;
|
||||||
return (format_grid_hyperlink(gd, x, gd->hsize + y, wp->screen));
|
return (format_grid_hyperlink(gd, x, gd->hsize + y, wp->screen));
|
||||||
}
|
}
|
||||||
@ -1544,6 +1579,23 @@ format_cb_client_written(struct format_tree *ft)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Callback for client_theme. */
|
||||||
|
static void *
|
||||||
|
format_cb_client_theme(struct format_tree *ft)
|
||||||
|
{
|
||||||
|
if (ft->c != NULL) {
|
||||||
|
switch (ft->c->theme) {
|
||||||
|
case THEME_DARK:
|
||||||
|
return (xstrdup("dark"));
|
||||||
|
case THEME_LIGHT:
|
||||||
|
return (xstrdup("light"));
|
||||||
|
case THEME_UNKNOWN:
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Callback for config_files. */
|
/* Callback for config_files. */
|
||||||
static void *
|
static void *
|
||||||
format_cb_config_files(__unused struct format_tree *ft)
|
format_cb_config_files(__unused struct format_tree *ft)
|
||||||
@ -1576,6 +1628,37 @@ format_cb_cursor_flag(struct format_tree *ft)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Callback for cursor_shape. */
|
||||||
|
static void *
|
||||||
|
format_cb_cursor_shape(struct format_tree *ft)
|
||||||
|
{
|
||||||
|
if (ft->wp != NULL && ft->wp->screen != NULL) {
|
||||||
|
switch (ft->wp->screen->cstyle) {
|
||||||
|
case SCREEN_CURSOR_BLOCK:
|
||||||
|
return (xstrdup("block"));
|
||||||
|
case SCREEN_CURSOR_UNDERLINE:
|
||||||
|
return (xstrdup("underline"));
|
||||||
|
case SCREEN_CURSOR_BAR:
|
||||||
|
return (xstrdup("bar"));
|
||||||
|
default:
|
||||||
|
return (xstrdup("default"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callback for cursor_very_visible. */
|
||||||
|
static void *
|
||||||
|
format_cb_cursor_very_visible(struct format_tree *ft)
|
||||||
|
{
|
||||||
|
if (ft->wp != NULL && ft->wp->screen != NULL) {
|
||||||
|
if (ft->wp->screen->mode & MODE_CURSOR_VERY_VISIBLE)
|
||||||
|
return (xstrdup("1"));
|
||||||
|
return (xstrdup("0"));
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Callback for cursor_x. */
|
/* Callback for cursor_x. */
|
||||||
static void *
|
static void *
|
||||||
format_cb_cursor_x(struct format_tree *ft)
|
format_cb_cursor_x(struct format_tree *ft)
|
||||||
@ -1594,6 +1677,18 @@ format_cb_cursor_y(struct format_tree *ft)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Callback for cursor_blinking. */
|
||||||
|
static void *
|
||||||
|
format_cb_cursor_blinking(struct format_tree *ft)
|
||||||
|
{
|
||||||
|
if (ft->wp != NULL && ft->wp->screen != NULL) {
|
||||||
|
if (ft->wp->screen->mode & MODE_CURSOR_BLINKING)
|
||||||
|
return (xstrdup("1"));
|
||||||
|
return (xstrdup("0"));
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Callback for history_limit. */
|
/* Callback for history_limit. */
|
||||||
static void *
|
static void *
|
||||||
format_cb_history_limit(struct format_tree *ft)
|
format_cb_history_limit(struct format_tree *ft)
|
||||||
@ -2320,6 +2415,17 @@ format_cb_version(__unused struct format_tree *ft)
|
|||||||
return (xstrdup(getversion()));
|
return (xstrdup(getversion()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Callback for sixel_support. */
|
||||||
|
static void *
|
||||||
|
format_cb_sixel_support(__unused struct format_tree *ft)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_SIXEL
|
||||||
|
return (xstrdup("1"));
|
||||||
|
#else
|
||||||
|
return (xstrdup("0"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* Callback for active_window_index. */
|
/* Callback for active_window_index. */
|
||||||
static void *
|
static void *
|
||||||
format_cb_active_window_index(struct format_tree *ft)
|
format_cb_active_window_index(struct format_tree *ft)
|
||||||
@ -2483,9 +2589,20 @@ format_cb_window_last_flag(struct format_tree *ft)
|
|||||||
static void *
|
static void *
|
||||||
format_cb_window_linked(struct format_tree *ft)
|
format_cb_window_linked(struct format_tree *ft)
|
||||||
{
|
{
|
||||||
|
struct winlink *wl;
|
||||||
|
struct session *s;
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
if (ft->wl != NULL) {
|
if (ft->wl != NULL) {
|
||||||
if (session_is_linked(ft->wl->session, ft->wl->window))
|
RB_FOREACH(s, sessions, &sessions) {
|
||||||
return (xstrdup("1"));
|
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||||
|
if (wl->window == ft->wl->window) {
|
||||||
|
if (found)
|
||||||
|
return (xstrdup("1"));
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return (xstrdup("0"));
|
return (xstrdup("0"));
|
||||||
}
|
}
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@ -2495,9 +2612,27 @@ format_cb_window_linked(struct format_tree *ft)
|
|||||||
static void *
|
static void *
|
||||||
format_cb_window_linked_sessions(struct format_tree *ft)
|
format_cb_window_linked_sessions(struct format_tree *ft)
|
||||||
{
|
{
|
||||||
if (ft->wl != NULL)
|
struct window *w;
|
||||||
return (format_printf("%u", ft->wl->window->references));
|
struct session_group *sg;
|
||||||
return (NULL);
|
struct session *s;
|
||||||
|
u_int n = 0;
|
||||||
|
|
||||||
|
if (ft->wl == NULL)
|
||||||
|
return (NULL);
|
||||||
|
w = ft->wl->window;
|
||||||
|
|
||||||
|
RB_FOREACH(sg, session_groups, &session_groups) {
|
||||||
|
s = TAILQ_FIRST(&sg->sessions);
|
||||||
|
if (winlink_find_by_window(&s->windows, w) != NULL)
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
RB_FOREACH(s, sessions, &sessions) {
|
||||||
|
if (session_group_contains(s) != NULL)
|
||||||
|
continue;
|
||||||
|
if (winlink_find_by_window(&s->windows, w) != NULL)
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
return (format_printf("%u", n));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Callback for window_marked_flag. */
|
/* Callback for window_marked_flag. */
|
||||||
@ -2841,6 +2976,9 @@ static const struct format_table_entry format_table[] = {
|
|||||||
{ "client_termtype", FORMAT_TABLE_STRING,
|
{ "client_termtype", FORMAT_TABLE_STRING,
|
||||||
format_cb_client_termtype
|
format_cb_client_termtype
|
||||||
},
|
},
|
||||||
|
{ "client_theme", FORMAT_TABLE_STRING,
|
||||||
|
format_cb_client_theme
|
||||||
|
},
|
||||||
{ "client_tty", FORMAT_TABLE_STRING,
|
{ "client_tty", FORMAT_TABLE_STRING,
|
||||||
format_cb_client_tty
|
format_cb_client_tty
|
||||||
},
|
},
|
||||||
@ -2862,12 +3000,24 @@ static const struct format_table_entry format_table[] = {
|
|||||||
{ "config_files", FORMAT_TABLE_STRING,
|
{ "config_files", FORMAT_TABLE_STRING,
|
||||||
format_cb_config_files
|
format_cb_config_files
|
||||||
},
|
},
|
||||||
|
{ "cursor_blinking", FORMAT_TABLE_STRING,
|
||||||
|
format_cb_cursor_blinking
|
||||||
|
},
|
||||||
{ "cursor_character", FORMAT_TABLE_STRING,
|
{ "cursor_character", FORMAT_TABLE_STRING,
|
||||||
format_cb_cursor_character
|
format_cb_cursor_character
|
||||||
},
|
},
|
||||||
|
{ "cursor_colour", FORMAT_TABLE_STRING,
|
||||||
|
format_cb_cursor_colour
|
||||||
|
},
|
||||||
{ "cursor_flag", FORMAT_TABLE_STRING,
|
{ "cursor_flag", FORMAT_TABLE_STRING,
|
||||||
format_cb_cursor_flag
|
format_cb_cursor_flag
|
||||||
},
|
},
|
||||||
|
{ "cursor_shape", FORMAT_TABLE_STRING,
|
||||||
|
format_cb_cursor_shape
|
||||||
|
},
|
||||||
|
{ "cursor_very_visible", FORMAT_TABLE_STRING,
|
||||||
|
format_cb_cursor_very_visible
|
||||||
|
},
|
||||||
{ "cursor_x", FORMAT_TABLE_STRING,
|
{ "cursor_x", FORMAT_TABLE_STRING,
|
||||||
format_cb_cursor_x
|
format_cb_cursor_x
|
||||||
},
|
},
|
||||||
@ -3147,6 +3297,9 @@ static const struct format_table_entry format_table[] = {
|
|||||||
{ "session_windows", FORMAT_TABLE_STRING,
|
{ "session_windows", FORMAT_TABLE_STRING,
|
||||||
format_cb_session_windows
|
format_cb_session_windows
|
||||||
},
|
},
|
||||||
|
{ "sixel_support", FORMAT_TABLE_STRING,
|
||||||
|
format_cb_sixel_support
|
||||||
|
},
|
||||||
{ "socket_path", FORMAT_TABLE_STRING,
|
{ "socket_path", FORMAT_TABLE_STRING,
|
||||||
format_cb_socket_path
|
format_cb_socket_path
|
||||||
},
|
},
|
||||||
@ -3532,7 +3685,7 @@ format_quote_style(const char *s)
|
|||||||
char *
|
char *
|
||||||
format_pretty_time(time_t t, int seconds)
|
format_pretty_time(time_t t, int seconds)
|
||||||
{
|
{
|
||||||
struct tm now_tm, tm;
|
struct tm now_tm, tm;
|
||||||
time_t now, age;
|
time_t now, age;
|
||||||
char s[9];
|
char s[9];
|
||||||
|
|
||||||
@ -3710,7 +3863,7 @@ format_unescape(const char *s)
|
|||||||
*s == '#' &&
|
*s == '#' &&
|
||||||
strchr(",#{}:", s[1]) != NULL) {
|
strchr(",#{}:", s[1]) != NULL) {
|
||||||
*cp++ = *++s;
|
*cp++ = *++s;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (*s == '}')
|
if (*s == '}')
|
||||||
brackets--;
|
brackets--;
|
||||||
@ -3852,10 +4005,10 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Modifiers are a ; separated list of the forms:
|
* Modifiers are a ; separated list of the forms:
|
||||||
* l,m,C,a,b,c,d,n,t,w,q,E,T,S,W,P,<,>
|
* l,m,C,a,b,c,d,n,t,w,q,E,T,S,W,P,R,<,>
|
||||||
* =a
|
* =a
|
||||||
* =/a
|
* =/a
|
||||||
* =/a/
|
* =/a/
|
||||||
* s/a/b/
|
* s/a/b/
|
||||||
* s/a/b
|
* s/a/b
|
||||||
* ||,&&,!=,==,<=,>=
|
* ||,&&,!=,==,<=,>=
|
||||||
@ -3869,7 +4022,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
|||||||
cp++;
|
cp++;
|
||||||
|
|
||||||
/* Check single character modifiers with no arguments. */
|
/* Check single character modifiers with no arguments. */
|
||||||
if (strchr("labcdnwETSWPL<>", cp[0]) != NULL &&
|
if (strchr("labcdnwETSWPL!<>", cp[0]) != NULL &&
|
||||||
format_is_end(cp[1])) {
|
format_is_end(cp[1])) {
|
||||||
format_add_modifier(&list, count, cp, 1, NULL, 0);
|
format_add_modifier(&list, count, cp, 1, NULL, 0);
|
||||||
cp++;
|
cp++;
|
||||||
@ -3879,6 +4032,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
|||||||
/* Then try double character with no arguments. */
|
/* Then try double character with no arguments. */
|
||||||
if ((memcmp("||", cp, 2) == 0 ||
|
if ((memcmp("||", cp, 2) == 0 ||
|
||||||
memcmp("&&", cp, 2) == 0 ||
|
memcmp("&&", cp, 2) == 0 ||
|
||||||
|
memcmp("!!", cp, 2) == 0 ||
|
||||||
memcmp("!=", cp, 2) == 0 ||
|
memcmp("!=", cp, 2) == 0 ||
|
||||||
memcmp("==", cp, 2) == 0 ||
|
memcmp("==", cp, 2) == 0 ||
|
||||||
memcmp("<=", cp, 2) == 0 ||
|
memcmp("<=", cp, 2) == 0 ||
|
||||||
@ -3890,7 +4044,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now try single character with arguments. */
|
/* Now try single character with arguments. */
|
||||||
if (strchr("mCNst=peq", cp[0]) == NULL)
|
if (strchr("mCNSst=pReq", cp[0]) == NULL)
|
||||||
break;
|
break;
|
||||||
c = cp[0];
|
c = cp[0];
|
||||||
|
|
||||||
@ -4014,6 +4168,60 @@ format_search(struct format_modifier *fm, struct window_pane *wp, const char *s)
|
|||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle unary boolean operators, "!" and "!!". */
|
||||||
|
static char *
|
||||||
|
format_bool_op_1(struct format_expand_state *es, const char *fmt, int not)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
char *expanded;
|
||||||
|
|
||||||
|
expanded = format_expand1(es, fmt);
|
||||||
|
result = format_true(expanded);
|
||||||
|
if (not)
|
||||||
|
result = !result;
|
||||||
|
free(expanded);
|
||||||
|
|
||||||
|
return (xstrdup(result ? "1" : "0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle n-ary boolean operators, "&&" and "||". */
|
||||||
|
static char *
|
||||||
|
format_bool_op_n(struct format_expand_state *es, const char *fmt, int and)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
const char *cp1, *cp2;
|
||||||
|
char *raw, *expanded;
|
||||||
|
|
||||||
|
result = and ? 1 : 0;
|
||||||
|
cp1 = fmt;
|
||||||
|
|
||||||
|
while (and ? result : !result) {
|
||||||
|
cp2 = format_skip(cp1, ",");
|
||||||
|
|
||||||
|
if (cp2 == NULL)
|
||||||
|
raw = xstrdup(cp1);
|
||||||
|
else
|
||||||
|
raw = xstrndup(cp1, cp2 - cp1);
|
||||||
|
expanded = format_expand1(es, raw);
|
||||||
|
free(raw);
|
||||||
|
format_log(es, "operator %s has operand: %s",
|
||||||
|
and ? "&&" : "||", expanded);
|
||||||
|
|
||||||
|
if (and)
|
||||||
|
result = result && format_true(expanded);
|
||||||
|
else
|
||||||
|
result = result || format_true(expanded);
|
||||||
|
free(expanded);
|
||||||
|
|
||||||
|
if (cp2 == NULL)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
cp1 = cp2 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (xstrdup(result ? "1" : "0"));
|
||||||
|
}
|
||||||
|
|
||||||
/* Does session name exist? */
|
/* Does session name exist? */
|
||||||
static char *
|
static char *
|
||||||
format_session_name(struct format_expand_state *es, const char *fmt)
|
format_session_name(struct format_expand_state *es, const char *fmt)
|
||||||
@ -4032,29 +4240,86 @@ format_session_name(struct format_expand_state *es, const char *fmt)
|
|||||||
return (xstrdup("0"));
|
return (xstrdup("0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
format_cmp_session(const void *a0, const void *b0)
|
||||||
|
{
|
||||||
|
const struct session *const *a = a0;
|
||||||
|
const struct session *const *b = b0;
|
||||||
|
const struct session *sa = *a;
|
||||||
|
const struct session *sb = *b;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
switch (format_loop_sort_criteria.field) {
|
||||||
|
case FORMAT_LOOP_BY_INDEX:
|
||||||
|
result = sa->id - sb->id;
|
||||||
|
break;
|
||||||
|
case FORMAT_LOOP_BY_TIME:
|
||||||
|
if (timercmp(&sa->activity_time, &sb->activity_time, >)) {
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (timercmp(&sa->activity_time, &sb->activity_time, <)) {
|
||||||
|
result = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case FORMAT_LOOP_BY_NAME:
|
||||||
|
result = strcmp(sa->name, sb->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format_loop_sort_criteria.reversed)
|
||||||
|
result = -result;
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
/* Loop over sessions. */
|
/* Loop over sessions. */
|
||||||
static char *
|
static char *
|
||||||
format_loop_sessions(struct format_expand_state *es, const char *fmt)
|
format_loop_sessions(struct format_expand_state *es, const char *fmt)
|
||||||
{
|
{
|
||||||
struct format_tree *ft = es->ft;
|
struct format_tree *ft = es->ft;
|
||||||
struct client *c = ft->client;
|
struct client *c = ft->client;
|
||||||
struct cmdq_item *item = ft->item;
|
struct cmdq_item *item = ft->item;
|
||||||
struct format_tree *nft;
|
struct format_tree *nft;
|
||||||
struct format_expand_state next;
|
struct format_expand_state next;
|
||||||
char *expanded, *value;
|
char *all, *active, *use, *expanded, *value;
|
||||||
size_t valuelen;
|
size_t valuelen;
|
||||||
struct session *s;
|
struct session *s;
|
||||||
|
int i, n;
|
||||||
|
static struct session **l = NULL;
|
||||||
|
static int lsz = 0;
|
||||||
|
|
||||||
|
if (format_choose(es, fmt, &all, &active, 0) != 0) {
|
||||||
|
all = xstrdup(fmt);
|
||||||
|
active = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
RB_FOREACH(s, sessions, &sessions) {
|
||||||
|
if (lsz <= n) {
|
||||||
|
lsz += 100;
|
||||||
|
l = xreallocarray(l, lsz, sizeof *l);
|
||||||
|
}
|
||||||
|
l[n++] = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(l, n, sizeof *l, format_cmp_session);
|
||||||
|
|
||||||
value = xcalloc(1, 1);
|
value = xcalloc(1, 1);
|
||||||
valuelen = 1;
|
valuelen = 1;
|
||||||
|
|
||||||
RB_FOREACH(s, sessions, &sessions) {
|
for (i = 0; i < n; i++) {
|
||||||
|
s = l[i];
|
||||||
format_log(es, "session loop: $%u", s->id);
|
format_log(es, "session loop: $%u", s->id);
|
||||||
|
if (active != NULL && s->id == ft->c->session->id)
|
||||||
|
use = active;
|
||||||
|
else
|
||||||
|
use = all;
|
||||||
nft = format_create(c, item, FORMAT_NONE, ft->flags);
|
nft = format_create(c, item, FORMAT_NONE, ft->flags);
|
||||||
format_defaults(nft, ft->c, s, NULL, NULL);
|
format_defaults(nft, ft->c, s, NULL, NULL);
|
||||||
format_copy_state(&next, es, 0);
|
format_copy_state(&next, es, 0);
|
||||||
next.ft = nft;
|
next.ft = nft;
|
||||||
expanded = format_expand1(&next, fmt);
|
expanded = format_expand1(&next, use);
|
||||||
format_free(next.ft);
|
format_free(next.ft);
|
||||||
|
|
||||||
valuelen += strlen(expanded);
|
valuelen += strlen(expanded);
|
||||||
@ -4380,7 +4645,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
{
|
{
|
||||||
struct format_tree *ft = es->ft;
|
struct format_tree *ft = es->ft;
|
||||||
struct window_pane *wp = ft->wp;
|
struct window_pane *wp = ft->wp;
|
||||||
const char *errstr, *copy, *cp, *marker = NULL;
|
const char *errstr, *copy, *cp, *cp2;
|
||||||
|
const char *marker = NULL;
|
||||||
const char *time_format = NULL;
|
const char *time_format = NULL;
|
||||||
char *copy0, *condition, *found, *new;
|
char *copy0, *condition, *found, *new;
|
||||||
char *value, *left, *right;
|
char *value, *left, *right;
|
||||||
@ -4389,8 +4655,10 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
int j, c;
|
int j, c;
|
||||||
struct format_modifier *list, *cmp = NULL, *search = NULL;
|
struct format_modifier *list, *cmp = NULL, *search = NULL;
|
||||||
struct format_modifier **sub = NULL, *mexp = NULL, *fm;
|
struct format_modifier **sub = NULL, *mexp = NULL, *fm;
|
||||||
u_int i, count, nsub = 0;
|
struct format_modifier *bool_op_n = NULL;
|
||||||
|
u_int i, count, nsub = 0, nrep;
|
||||||
struct format_expand_state next;
|
struct format_expand_state next;
|
||||||
|
struct format_loop_sort_criteria *sc = &format_loop_sort_criteria;
|
||||||
|
|
||||||
/* Make a copy of the key. */
|
/* Make a copy of the key. */
|
||||||
copy = copy0 = xstrndup(key, keylen);
|
copy = copy0 = xstrndup(key, keylen);
|
||||||
@ -4413,6 +4681,9 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
case '>':
|
case '>':
|
||||||
cmp = fm;
|
cmp = fm;
|
||||||
break;
|
break;
|
||||||
|
case '!':
|
||||||
|
modifiers |= FORMAT_NOT;
|
||||||
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
search = fm;
|
search = fm;
|
||||||
break;
|
break;
|
||||||
@ -4498,6 +4769,19 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
break;
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
modifiers |= FORMAT_SESSIONS;
|
modifiers |= FORMAT_SESSIONS;
|
||||||
|
if (fm->argc < 1)
|
||||||
|
break;
|
||||||
|
if (strchr(fm->argv[0], 'i') != NULL)
|
||||||
|
sc->field = FORMAT_LOOP_BY_INDEX;
|
||||||
|
else if (strchr(fm->argv[0], 'n') != NULL)
|
||||||
|
sc->field = FORMAT_LOOP_BY_NAME;
|
||||||
|
else if (strchr(fm->argv[0], 't') != NULL)
|
||||||
|
sc->field = FORMAT_LOOP_BY_TIME;
|
||||||
|
else sc->field = FORMAT_LOOP_BY_INDEX;
|
||||||
|
if (strchr(fm->argv[0], 'r') != NULL)
|
||||||
|
sc->reversed = 1;
|
||||||
|
else
|
||||||
|
sc->reversed = 0;
|
||||||
break;
|
break;
|
||||||
case 'W':
|
case 'W':
|
||||||
modifiers |= FORMAT_WINDOWS;
|
modifiers |= FORMAT_WINDOWS;
|
||||||
@ -4508,11 +4792,17 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
case 'L':
|
case 'L':
|
||||||
modifiers |= FORMAT_CLIENTS;
|
modifiers |= FORMAT_CLIENTS;
|
||||||
break;
|
break;
|
||||||
|
case 'R':
|
||||||
|
modifiers |= FORMAT_REPEAT;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if (fm->size == 2) {
|
} else if (fm->size == 2) {
|
||||||
if (strcmp(fm->modifier, "||") == 0 ||
|
if (strcmp(fm->modifier, "||") == 0 ||
|
||||||
strcmp(fm->modifier, "&&") == 0 ||
|
strcmp(fm->modifier, "&&") == 0)
|
||||||
strcmp(fm->modifier, "==") == 0 ||
|
bool_op_n = fm;
|
||||||
|
else if (strcmp(fm->modifier, "!!") == 0)
|
||||||
|
modifiers |= FORMAT_NOT_NOT;
|
||||||
|
else if (strcmp(fm->modifier, "==") == 0 ||
|
||||||
strcmp(fm->modifier, "!=") == 0 ||
|
strcmp(fm->modifier, "!=") == 0 ||
|
||||||
strcmp(fm->modifier, ">=") == 0 ||
|
strcmp(fm->modifier, ">=") == 0 ||
|
||||||
strcmp(fm->modifier, "<=") == 0)
|
strcmp(fm->modifier, "<=") == 0)
|
||||||
@ -4551,7 +4841,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is this a loop, comparison or condition? */
|
/* Is this a loop, operator, comparison or condition? */
|
||||||
if (modifiers & FORMAT_SESSIONS) {
|
if (modifiers & FORMAT_SESSIONS) {
|
||||||
value = format_loop_sessions(es, copy);
|
value = format_loop_sessions(es, copy);
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
@ -4587,6 +4877,35 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
value = format_search(search, wp, new);
|
value = format_search(search, wp, new);
|
||||||
}
|
}
|
||||||
free(new);
|
free(new);
|
||||||
|
} else if (modifiers & FORMAT_REPEAT) {
|
||||||
|
/* Repeat multiple times. */
|
||||||
|
if (format_choose(es, copy, &left, &right, 1) != 0) {
|
||||||
|
format_log(es, "repeat syntax error: %s", copy);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
nrep = strtonum(right, 1, 10000, &errstr);
|
||||||
|
if (errstr != NULL)
|
||||||
|
value = xstrdup("");
|
||||||
|
else {
|
||||||
|
value = xstrdup("");
|
||||||
|
for (i = 0; i < nrep; i++) {
|
||||||
|
xasprintf(&new, "%s%s", value, left);
|
||||||
|
free(value);
|
||||||
|
value = new;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(right);
|
||||||
|
free(left);
|
||||||
|
} else if (modifiers & FORMAT_NOT) {
|
||||||
|
value = format_bool_op_1(es, copy, 1);
|
||||||
|
} else if (modifiers & FORMAT_NOT_NOT) {
|
||||||
|
value = format_bool_op_1(es, copy, 0);
|
||||||
|
} else if (bool_op_n != NULL) {
|
||||||
|
/* n-ary boolean operator. */
|
||||||
|
if (strcmp(bool_op_n->modifier, "||") == 0)
|
||||||
|
value = format_bool_op_n(es, copy, 0);
|
||||||
|
else if (strcmp(bool_op_n->modifier, "&&") == 0)
|
||||||
|
value = format_bool_op_n(es, copy, 1);
|
||||||
} else if (cmp != NULL) {
|
} else if (cmp != NULL) {
|
||||||
/* Comparison of left and right. */
|
/* Comparison of left and right. */
|
||||||
if (format_choose(es, copy, &left, &right, 1) != 0) {
|
if (format_choose(es, copy, &left, &right, 1) != 0) {
|
||||||
@ -4597,17 +4916,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
format_log(es, "compare %s left is: %s", cmp->modifier, left);
|
format_log(es, "compare %s left is: %s", cmp->modifier, left);
|
||||||
format_log(es, "compare %s right is: %s", cmp->modifier, right);
|
format_log(es, "compare %s right is: %s", cmp->modifier, right);
|
||||||
|
|
||||||
if (strcmp(cmp->modifier, "||") == 0) {
|
if (strcmp(cmp->modifier, "==") == 0) {
|
||||||
if (format_true(left) || format_true(right))
|
|
||||||
value = xstrdup("1");
|
|
||||||
else
|
|
||||||
value = xstrdup("0");
|
|
||||||
} else if (strcmp(cmp->modifier, "&&") == 0) {
|
|
||||||
if (format_true(left) && format_true(right))
|
|
||||||
value = xstrdup("1");
|
|
||||||
else
|
|
||||||
value = xstrdup("0");
|
|
||||||
} else if (strcmp(cmp->modifier, "==") == 0) {
|
|
||||||
if (strcmp(left, right) == 0)
|
if (strcmp(left, right) == 0)
|
||||||
value = xstrdup("1");
|
value = xstrdup("1");
|
||||||
else
|
else
|
||||||
@ -4643,53 +4952,81 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
free(right);
|
free(right);
|
||||||
free(left);
|
free(left);
|
||||||
} else if (*copy == '?') {
|
} else if (*copy == '?') {
|
||||||
/* Conditional: check first and choose second or third. */
|
/*
|
||||||
cp = format_skip(copy + 1, ",");
|
* Conditional: For each pair of (condition, value), check the
|
||||||
if (cp == NULL) {
|
* condition and return the value if true. If no condition
|
||||||
format_log(es, "condition syntax error: %s", copy + 1);
|
* matches, return the last unpaired arg if there is one, or the
|
||||||
goto fail;
|
* empty string if not.
|
||||||
}
|
*/
|
||||||
condition = xstrndup(copy + 1, cp - (copy + 1));
|
cp = copy + 1;
|
||||||
format_log(es, "condition is: %s", condition);
|
while (1) {
|
||||||
|
cp2 = format_skip(cp, ",");
|
||||||
found = format_find(ft, condition, modifiers, time_format);
|
if (cp2 == NULL) {
|
||||||
if (found == NULL) {
|
|
||||||
/*
|
|
||||||
* If the condition not found, try to expand it. If
|
|
||||||
* the expansion doesn't have any effect, then assume
|
|
||||||
* false.
|
|
||||||
*/
|
|
||||||
found = format_expand1(es, condition);
|
|
||||||
if (strcmp(found, condition) == 0) {
|
|
||||||
free(found);
|
|
||||||
found = xstrdup("");
|
|
||||||
format_log(es,
|
format_log(es,
|
||||||
"condition '%s' not found; assuming false",
|
"no condition matched in '%s'; using last "
|
||||||
|
"arg", copy + 1);
|
||||||
|
value = format_expand1(es, cp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
condition = xstrndup(cp, cp2 - cp);
|
||||||
|
format_log(es, "condition is: %s", condition);
|
||||||
|
|
||||||
|
found = format_find(ft, condition, modifiers,
|
||||||
|
time_format);
|
||||||
|
if (found == NULL) {
|
||||||
|
/*
|
||||||
|
* If the condition not found, try to expand it.
|
||||||
|
* If the expansion doesn't have any effect,
|
||||||
|
* then assume false.
|
||||||
|
*/
|
||||||
|
found = format_expand1(es, condition);
|
||||||
|
if (strcmp(found, condition) == 0) {
|
||||||
|
free(found);
|
||||||
|
found = xstrdup("");
|
||||||
|
format_log(es,
|
||||||
|
"condition '%s' not found; "
|
||||||
|
"assuming false",
|
||||||
|
condition);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
format_log(es, "condition '%s' found: %s",
|
||||||
|
condition, found);
|
||||||
|
}
|
||||||
|
|
||||||
|
cp = cp2 + 1;
|
||||||
|
cp2 = format_skip(cp, ",");
|
||||||
|
if (format_true(found)) {
|
||||||
|
format_log(es, "condition '%s' is true",
|
||||||
|
condition);
|
||||||
|
if (cp2 == NULL)
|
||||||
|
value = format_expand1(es, cp);
|
||||||
|
else {
|
||||||
|
right = xstrndup(cp, cp2 - cp);
|
||||||
|
value = format_expand1(es, right);
|
||||||
|
free(right);
|
||||||
|
}
|
||||||
|
free(condition);
|
||||||
|
free(found);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
format_log(es, "condition '%s' is false",
|
||||||
condition);
|
condition);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
format_log(es, "condition '%s' found: %s", condition,
|
|
||||||
found);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (format_choose(es, cp + 1, &left, &right, 0) != 0) {
|
free(condition);
|
||||||
format_log(es, "condition '%s' syntax error: %s",
|
|
||||||
condition, cp + 1);
|
|
||||||
free(found);
|
free(found);
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (format_true(found)) {
|
|
||||||
format_log(es, "condition '%s' is true", condition);
|
|
||||||
value = format_expand1(es, left);
|
|
||||||
} else {
|
|
||||||
format_log(es, "condition '%s' is false", condition);
|
|
||||||
value = format_expand1(es, right);
|
|
||||||
}
|
|
||||||
free(right);
|
|
||||||
free(left);
|
|
||||||
|
|
||||||
free(condition);
|
if (cp2 == NULL) {
|
||||||
free(found);
|
format_log(es,
|
||||||
|
"no condition matched in '%s'; using empty "
|
||||||
|
"string", copy + 1);
|
||||||
|
value = xstrdup("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cp = cp2 + 1;
|
||||||
|
}
|
||||||
} else if (mexp != NULL) {
|
} else if (mexp != NULL) {
|
||||||
value = format_replace_expression(mexp, es, copy);
|
value = format_replace_expression(mexp, es, copy);
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
@ -4819,7 +5156,7 @@ format_expand1(struct format_expand_state *es, const char *fmt)
|
|||||||
char *buf, *out, *name;
|
char *buf, *out, *name;
|
||||||
const char *ptr, *s, *style_end = NULL;
|
const char *ptr, *s, *style_end = NULL;
|
||||||
size_t off, len, n, outlen;
|
size_t off, len, n, outlen;
|
||||||
int ch, brackets;
|
int ch, brackets;
|
||||||
char expanded[8192];
|
char expanded[8192];
|
||||||
|
|
||||||
if (fmt == NULL || *fmt == '\0')
|
if (fmt == NULL || *fmt == '\0')
|
||||||
@ -5178,6 +5515,16 @@ format_defaults_paste_buffer(struct format_tree *ft, struct paste_buffer *pb)
|
|||||||
ft->pb = pb;
|
ft->pb = pb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
format_is_word_separator(const char *ws, const struct grid_cell *gc)
|
||||||
|
{
|
||||||
|
if (utf8_cstrhas(ws, &gc->data))
|
||||||
|
return (1);
|
||||||
|
if (gc->flags & GRID_FLAG_TAB)
|
||||||
|
return (1);
|
||||||
|
return gc->data.size == 1 && *gc->data.data == ' ';
|
||||||
|
}
|
||||||
|
|
||||||
/* Return word at given coordinates. Caller frees. */
|
/* Return word at given coordinates. Caller frees. */
|
||||||
char *
|
char *
|
||||||
format_grid_word(struct grid *gd, u_int x, u_int y)
|
format_grid_word(struct grid *gd, u_int x, u_int y)
|
||||||
@ -5195,10 +5542,8 @@ format_grid_word(struct grid *gd, u_int x, u_int y)
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
grid_get_cell(gd, x, y, &gc);
|
grid_get_cell(gd, x, y, &gc);
|
||||||
if (gc.flags & GRID_FLAG_PADDING)
|
if ((~gc.flags & GRID_FLAG_PADDING) &&
|
||||||
break;
|
format_is_word_separator(ws, &gc)) {
|
||||||
if (utf8_cstrhas(ws, &gc.data) ||
|
|
||||||
(gc.data.size == 1 && *gc.data.data == ' ')) {
|
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -5234,9 +5579,8 @@ format_grid_word(struct grid *gd, u_int x, u_int y)
|
|||||||
|
|
||||||
grid_get_cell(gd, x, y, &gc);
|
grid_get_cell(gd, x, y, &gc);
|
||||||
if (gc.flags & GRID_FLAG_PADDING)
|
if (gc.flags & GRID_FLAG_PADDING)
|
||||||
break;
|
continue;
|
||||||
if (utf8_cstrhas(ws, &gc.data) ||
|
if (format_is_word_separator(ws, &gc))
|
||||||
(gc.data.size == 1 && *gc.data.data == ' '))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
ud = xreallocarray(ud, size + 2, sizeof *ud);
|
ud = xreallocarray(ud, size + 2, sizeof *ud);
|
||||||
@ -5263,10 +5607,13 @@ format_grid_line(struct grid *gd, u_int y)
|
|||||||
for (x = 0; x < grid_line_length(gd, y); x++) {
|
for (x = 0; x < grid_line_length(gd, y); x++) {
|
||||||
grid_get_cell(gd, x, y, &gc);
|
grid_get_cell(gd, x, y, &gc);
|
||||||
if (gc.flags & GRID_FLAG_PADDING)
|
if (gc.flags & GRID_FLAG_PADDING)
|
||||||
break;
|
continue;
|
||||||
|
|
||||||
ud = xreallocarray(ud, size + 2, sizeof *ud);
|
ud = xreallocarray(ud, size + 2, sizeof *ud);
|
||||||
memcpy(&ud[size++], &gc.data, sizeof *ud);
|
if (gc.flags & GRID_FLAG_TAB)
|
||||||
|
utf8_set(&ud[size++], '\t');
|
||||||
|
else
|
||||||
|
memcpy(&ud[size++], &gc.data, sizeof *ud);
|
||||||
}
|
}
|
||||||
if (size != 0) {
|
if (size != 0) {
|
||||||
ud[size].size = 0;
|
ud[size].size = 0;
|
||||||
@ -5283,9 +5630,14 @@ format_grid_hyperlink(struct grid *gd, u_int x, u_int y, struct screen* s)
|
|||||||
const char *uri;
|
const char *uri;
|
||||||
struct grid_cell gc;
|
struct grid_cell gc;
|
||||||
|
|
||||||
grid_get_cell(gd, x, y, &gc);
|
for (;;) {
|
||||||
if (gc.flags & GRID_FLAG_PADDING)
|
grid_get_cell(gd, x, y, &gc);
|
||||||
return (NULL);
|
if (~gc.flags & GRID_FLAG_PADDING)
|
||||||
|
break;
|
||||||
|
if (x == 0)
|
||||||
|
return (NULL);
|
||||||
|
x--;
|
||||||
|
}
|
||||||
if (s->hyperlinks == NULL || gc.link == 0)
|
if (s->hyperlinks == NULL || gc.link == 0)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
if (!hyperlinks_get(s->hyperlinks, gc.link, &uri, NULL, NULL))
|
if (!hyperlinks_get(s->hyperlinks, gc.link, &uri, NULL, NULL))
|
||||||
|
@ -180,19 +180,14 @@ grid_reader_handle_wrap(struct grid_reader *gr, u_int *xx, u_int *yy)
|
|||||||
int
|
int
|
||||||
grid_reader_in_set(struct grid_reader *gr, const char *set)
|
grid_reader_in_set(struct grid_reader *gr, const char *set)
|
||||||
{
|
{
|
||||||
struct grid_cell gc;
|
return (grid_in_set(gr->gd, gr->cx, gr->cy, set));
|
||||||
|
|
||||||
grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
|
|
||||||
if (gc.flags & GRID_FLAG_PADDING)
|
|
||||||
return (0);
|
|
||||||
return (utf8_cstrhas(set, &gc.data));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move cursor to the start of the next word. */
|
/* Move cursor to the start of the next word. */
|
||||||
void
|
void
|
||||||
grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
|
grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
|
||||||
{
|
{
|
||||||
u_int xx, yy;
|
u_int xx, yy, width;
|
||||||
|
|
||||||
/* Do not break up wrapped words. */
|
/* Do not break up wrapped words. */
|
||||||
if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
|
if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
|
||||||
@ -229,8 +224,8 @@ grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (grid_reader_handle_wrap(gr, &xx, &yy) &&
|
while (grid_reader_handle_wrap(gr, &xx, &yy) &&
|
||||||
grid_reader_in_set(gr, WHITESPACE))
|
(width = grid_reader_in_set(gr, WHITESPACE)))
|
||||||
gr->cx++;
|
gr->cx += width;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move cursor to the end of the next word. */
|
/* Move cursor to the end of the next word. */
|
||||||
@ -338,6 +333,20 @@ grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators,
|
|||||||
gr->cy = oldy;
|
gr->cy = oldy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compare grid cell to UTF-8 data. Return 1 if equal, 0 if not. */
|
||||||
|
static int
|
||||||
|
grid_reader_cell_equals_data(const struct grid_cell *gc,
|
||||||
|
const struct utf8_data *ud)
|
||||||
|
{
|
||||||
|
if (gc->flags & GRID_FLAG_PADDING)
|
||||||
|
return (0);
|
||||||
|
if (gc->flags & GRID_FLAG_TAB && ud->size == 1 && *ud->data == '\t')
|
||||||
|
return (1);
|
||||||
|
if (gc->data.size != ud->size)
|
||||||
|
return (0);
|
||||||
|
return (memcmp(gc->data.data, ud->data, gc->data.size) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Jump forward to character. */
|
/* Jump forward to character. */
|
||||||
int
|
int
|
||||||
grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
|
grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
|
||||||
@ -352,9 +361,7 @@ grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
|
|||||||
xx = grid_line_length(gr->gd, py);
|
xx = grid_line_length(gr->gd, py);
|
||||||
while (px < xx) {
|
while (px < xx) {
|
||||||
grid_get_cell(gr->gd, px, py, &gc);
|
grid_get_cell(gr->gd, px, py, &gc);
|
||||||
if (!(gc.flags & GRID_FLAG_PADDING) &&
|
if (grid_reader_cell_equals_data(&gc, jc)) {
|
||||||
gc.data.size == jc->size &&
|
|
||||||
memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
|
|
||||||
gr->cx = px;
|
gr->cx = px;
|
||||||
gr->cy = py;
|
gr->cy = py;
|
||||||
return (1);
|
return (1);
|
||||||
@ -382,9 +389,7 @@ grid_reader_cursor_jump_back(struct grid_reader *gr, const struct utf8_data *jc)
|
|||||||
for (py = gr->cy + 1; py > 0; py--) {
|
for (py = gr->cy + 1; py > 0; py--) {
|
||||||
for (px = xx; px > 0; px--) {
|
for (px = xx; px > 0; px--) {
|
||||||
grid_get_cell(gr->gd, px - 1, py - 1, &gc);
|
grid_get_cell(gr->gd, px - 1, py - 1, &gc);
|
||||||
if (!(gc.flags & GRID_FLAG_PADDING) &&
|
if (grid_reader_cell_equals_data(&gc, jc)) {
|
||||||
gc.data.size == jc->size &&
|
|
||||||
memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
|
|
||||||
gr->cx = px - 1;
|
gr->cx = px - 1;
|
||||||
gr->cy = py - 1;
|
gr->cy = py - 1;
|
||||||
return (1);
|
return (1);
|
||||||
@ -415,7 +420,9 @@ grid_reader_cursor_back_to_indentation(struct grid_reader *gr)
|
|||||||
xx = grid_line_length(gr->gd, py);
|
xx = grid_line_length(gr->gd, py);
|
||||||
for (px = 0; px < xx; px++) {
|
for (px = 0; px < xx; px++) {
|
||||||
grid_get_cell(gr->gd, px, py, &gc);
|
grid_get_cell(gr->gd, px, py, &gc);
|
||||||
if (gc.data.size != 1 || *gc.data.data != ' ') {
|
if ((gc.data.size != 1 || *gc.data.data != ' ') &&
|
||||||
|
~gc.flags & GRID_FLAG_TAB &&
|
||||||
|
~gc.flags & GRID_FLAG_PADDING) {
|
||||||
gr->cx = px;
|
gr->cx = px;
|
||||||
gr->cy = py;
|
gr->cy = py;
|
||||||
return;
|
return;
|
||||||
|
74
grid.c
74
grid.c
@ -84,7 +84,7 @@ grid_need_extended_cell(const struct grid_cell_entry *gce,
|
|||||||
return (1);
|
return (1);
|
||||||
if (gc->attr > 0xff)
|
if (gc->attr > 0xff)
|
||||||
return (1);
|
return (1);
|
||||||
if (gc->data.size != 1 || gc->data.width != 1)
|
if (gc->data.size > 1 || gc->data.width > 1)
|
||||||
return (1);
|
return (1);
|
||||||
if ((gc->fg & COLOUR_FLAG_RGB) || (gc->bg & COLOUR_FLAG_RGB))
|
if ((gc->fg & COLOUR_FLAG_RGB) || (gc->bg & COLOUR_FLAG_RGB))
|
||||||
return (1);
|
return (1);
|
||||||
@ -92,6 +92,8 @@ grid_need_extended_cell(const struct grid_cell_entry *gce,
|
|||||||
return (1);
|
return (1);
|
||||||
if (gc->link != 0)
|
if (gc->link != 0)
|
||||||
return (1);
|
return (1);
|
||||||
|
if (gc->flags & GRID_FLAG_TAB)
|
||||||
|
return (1);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +126,10 @@ grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
|
|||||||
fatalx("offset too big");
|
fatalx("offset too big");
|
||||||
gl->flags |= GRID_LINE_EXTENDED;
|
gl->flags |= GRID_LINE_EXTENDED;
|
||||||
|
|
||||||
utf8_from_data(&gc->data, &uc);
|
if (gc->flags & GRID_FLAG_TAB)
|
||||||
|
uc = gc->data.width;
|
||||||
|
else
|
||||||
|
utf8_from_data(&gc->data, &uc);
|
||||||
|
|
||||||
gee = &gl->extddata[gce->offset];
|
gee = &gl->extddata[gce->offset];
|
||||||
gee->data = uc;
|
gee->data = uc;
|
||||||
@ -230,9 +235,13 @@ grid_check_y(struct grid *gd, const char *from, u_int py)
|
|||||||
int
|
int
|
||||||
grid_cells_look_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
|
grid_cells_look_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
|
||||||
{
|
{
|
||||||
|
int flags1 = gc1->flags, flags2 = gc2->flags;;
|
||||||
|
|
||||||
if (gc1->fg != gc2->fg || gc1->bg != gc2->bg)
|
if (gc1->fg != gc2->fg || gc1->bg != gc2->bg)
|
||||||
return (0);
|
return (0);
|
||||||
if (gc1->attr != gc2->attr || gc1->flags != gc2->flags)
|
if (gc1->attr != gc2->attr)
|
||||||
|
return (0);
|
||||||
|
if ((flags1 & ~GRID_FLAG_CLEARED) != (flags2 & ~GRID_FLAG_CLEARED))
|
||||||
return (0);
|
return (0);
|
||||||
if (gc1->link != gc2->link)
|
if (gc1->link != gc2->link)
|
||||||
return (0);
|
return (0);
|
||||||
@ -252,6 +261,16 @@ grid_cells_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
|
|||||||
return (memcmp(gc1->data.data, gc2->data.data, gc1->data.size) == 0);
|
return (memcmp(gc1->data.data, gc2->data.data, gc1->data.size) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set grid cell to a tab. */
|
||||||
|
void
|
||||||
|
grid_set_tab(struct grid_cell *gc, u_int width)
|
||||||
|
{
|
||||||
|
memset(gc->data.data, 0, sizeof gc->data.data);
|
||||||
|
gc->flags |= GRID_FLAG_TAB;
|
||||||
|
gc->data.width = gc->data.size = gc->data.have = width;
|
||||||
|
memset(gc->data.data, ' ', gc->data.size);
|
||||||
|
}
|
||||||
|
|
||||||
/* Free one line. */
|
/* Free one line. */
|
||||||
static void
|
static void
|
||||||
grid_free_line(struct grid *gd, u_int py)
|
grid_free_line(struct grid *gd, u_int py)
|
||||||
@ -515,7 +534,11 @@ grid_get_cell1(struct grid_line *gl, u_int px, struct grid_cell *gc)
|
|||||||
gc->bg = gee->bg;
|
gc->bg = gee->bg;
|
||||||
gc->us = gee->us;
|
gc->us = gee->us;
|
||||||
gc->link = gee->link;
|
gc->link = gee->link;
|
||||||
utf8_to_data(gee->data, &gc->data);
|
|
||||||
|
if (gc->flags & GRID_FLAG_TAB)
|
||||||
|
grid_set_tab(gc, gee->data);
|
||||||
|
else
|
||||||
|
utf8_to_data(gee->data, &gc->data);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1077,13 +1100,18 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
|
|||||||
} else
|
} else
|
||||||
codelen = 0;
|
codelen = 0;
|
||||||
|
|
||||||
data = gc.data.data;
|
if (gc.flags & GRID_FLAG_TAB) {
|
||||||
size = gc.data.size;
|
data = "\t";
|
||||||
if ((flags & GRID_STRING_ESCAPE_SEQUENCES) &&
|
size = 1;
|
||||||
size == 1 &&
|
} else {
|
||||||
*data == '\\') {
|
data = gc.data.data;
|
||||||
data = "\\\\";
|
size = gc.data.size;
|
||||||
size = 2;
|
if ((flags & GRID_STRING_ESCAPE_SEQUENCES) &&
|
||||||
|
size == 1 &&
|
||||||
|
*data == '\\') {
|
||||||
|
data = "\\\\";
|
||||||
|
size = 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (len < off + size + codelen + 1) {
|
while (len < off + size + codelen + 1) {
|
||||||
@ -1533,3 +1561,27 @@ grid_line_length(struct grid *gd, u_int py)
|
|||||||
}
|
}
|
||||||
return (px);
|
return (px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if character is in set. */
|
||||||
|
int
|
||||||
|
grid_in_set(struct grid *gd, u_int px, u_int py, const char *set)
|
||||||
|
{
|
||||||
|
struct grid_cell gc, tmp_gc;
|
||||||
|
u_int pxx;
|
||||||
|
|
||||||
|
grid_get_cell(gd, px, py, &gc);
|
||||||
|
if (strchr(set, '\t')) {
|
||||||
|
if (gc.flags & GRID_FLAG_PADDING) {
|
||||||
|
pxx = px;
|
||||||
|
do
|
||||||
|
grid_get_cell(gd, --pxx, py, &tmp_gc);
|
||||||
|
while (pxx > 0 && tmp_gc.flags & GRID_FLAG_PADDING);
|
||||||
|
if (tmp_gc.flags & GRID_FLAG_TAB)
|
||||||
|
return (tmp_gc.data.width - (px - pxx));
|
||||||
|
} else if (gc.flags & GRID_FLAG_TAB)
|
||||||
|
return (gc.data.width);
|
||||||
|
}
|
||||||
|
if (gc.flags & GRID_FLAG_PADDING)
|
||||||
|
return (0);
|
||||||
|
return (utf8_cstrhas(set, &gc.data));
|
||||||
|
}
|
||||||
|
168
image-sixel.c
168
image-sixel.c
@ -37,8 +37,13 @@ struct sixel_image {
|
|||||||
u_int xpixel;
|
u_int xpixel;
|
||||||
u_int ypixel;
|
u_int ypixel;
|
||||||
|
|
||||||
|
u_int set_ra;
|
||||||
|
u_int ra_x;
|
||||||
|
u_int ra_y;
|
||||||
|
|
||||||
u_int *colours;
|
u_int *colours;
|
||||||
u_int ncolours;
|
u_int ncolours;
|
||||||
|
u_int p2;
|
||||||
|
|
||||||
u_int dx;
|
u_int dx;
|
||||||
u_int dy;
|
u_int dy;
|
||||||
@ -47,6 +52,19 @@ struct sixel_image {
|
|||||||
struct sixel_line *lines;
|
struct sixel_line *lines;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sixel_chunk {
|
||||||
|
u_int next_x;
|
||||||
|
u_int next_y;
|
||||||
|
|
||||||
|
u_int count;
|
||||||
|
char pattern;
|
||||||
|
char next_pattern;
|
||||||
|
|
||||||
|
size_t len;
|
||||||
|
size_t used;
|
||||||
|
char *data;
|
||||||
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sixel_parse_expand_lines(struct sixel_image *si, u_int y)
|
sixel_parse_expand_lines(struct sixel_image *si, u_int y)
|
||||||
{
|
{
|
||||||
@ -166,6 +184,10 @@ sixel_parse_attributes(struct sixel_image *si, const char *cp, const char *end)
|
|||||||
si->x = x;
|
si->x = x;
|
||||||
sixel_parse_expand_lines(si, y);
|
sixel_parse_expand_lines(si, y);
|
||||||
|
|
||||||
|
si->set_ra = 1;
|
||||||
|
si->ra_x = x;
|
||||||
|
si->ra_y = y;
|
||||||
|
|
||||||
return (last);
|
return (last);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +290,7 @@ sixel_parse_repeat(struct sixel_image *si, const char *cp, const char *end)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct sixel_image *
|
struct sixel_image *
|
||||||
sixel_parse(const char *buf, size_t len, u_int xpixel, u_int ypixel)
|
sixel_parse(const char *buf, size_t len, u_int p2, u_int xpixel, u_int ypixel)
|
||||||
{
|
{
|
||||||
struct sixel_image *si;
|
struct sixel_image *si;
|
||||||
const char *cp = buf, *end = buf + len;
|
const char *cp = buf, *end = buf + len;
|
||||||
@ -282,6 +304,7 @@ sixel_parse(const char *buf, size_t len, u_int xpixel, u_int ypixel)
|
|||||||
si = xcalloc (1, sizeof *si);
|
si = xcalloc (1, sizeof *si);
|
||||||
si->xpixel = xpixel;
|
si->xpixel = xpixel;
|
||||||
si->ypixel = ypixel;
|
si->ypixel = ypixel;
|
||||||
|
si->p2 = p2;
|
||||||
|
|
||||||
while (cp != end) {
|
while (cp != end) {
|
||||||
ch = *cp++;
|
ch = *cp++;
|
||||||
@ -423,6 +446,18 @@ sixel_scale(struct sixel_image *si, u_int xpixel, u_int ypixel, u_int ox,
|
|||||||
new = xcalloc (1, sizeof *si);
|
new = xcalloc (1, sizeof *si);
|
||||||
new->xpixel = xpixel;
|
new->xpixel = xpixel;
|
||||||
new->ypixel = ypixel;
|
new->ypixel = ypixel;
|
||||||
|
new->p2 = si->p2;
|
||||||
|
|
||||||
|
new->set_ra = si->set_ra;
|
||||||
|
/* clamp to slice end */
|
||||||
|
new->ra_x = si->ra_x < psx ? si->ra_x : psx;
|
||||||
|
new->ra_y = si->ra_y < psy ? si->ra_y : psy;
|
||||||
|
/* subtract slice origin */
|
||||||
|
new->ra_x = new->ra_x > pox ? new->ra_x - pox : 0;
|
||||||
|
new->ra_y = new->ra_y > poy ? new->ra_y - poy : 0;
|
||||||
|
/* resize */
|
||||||
|
new->ra_x = new->ra_x * xpixel / si->xpixel;
|
||||||
|
new->ra_y = new->ra_y * ypixel / si->ypixel;
|
||||||
|
|
||||||
for (y = 0; y < tsy; y++) {
|
for (y = 0; y < tsy; y++) {
|
||||||
py = poy + ((double)y * psy / tsy);
|
py = poy + ((double)y * psy / tsy);
|
||||||
@ -474,13 +509,65 @@ sixel_print_repeat(char **buf, size_t *len, size_t *used, u_int count, char ch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sixel_print_compress_colors(struct sixel_image *si, struct sixel_chunk *chunks,
|
||||||
|
u_int y, u_int *active, u_int *nactive)
|
||||||
|
{
|
||||||
|
u_int i, x, c, dx, colors[6];
|
||||||
|
struct sixel_chunk *chunk = NULL;
|
||||||
|
struct sixel_line *sl;
|
||||||
|
|
||||||
|
for (x = 0; x < si->x; x++) {
|
||||||
|
for (i = 0; i < 6; i++) {
|
||||||
|
colors[i] = 0;
|
||||||
|
if (y + i < si->y) {
|
||||||
|
sl = &si->lines[y + i];
|
||||||
|
if (x < sl->x && sl->data[x] != 0) {
|
||||||
|
colors[i] = sl->data[x];
|
||||||
|
c = sl->data[x] - 1;
|
||||||
|
chunks[c].next_pattern |= 1 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 6; i++) {
|
||||||
|
if (colors[i] == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
c = colors[i] - 1;
|
||||||
|
chunk = &chunks[c];
|
||||||
|
if (chunk->next_x == x + 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (chunk->next_y < y + 1) {
|
||||||
|
chunk->next_y = y + 1;
|
||||||
|
active[(*nactive)++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
dx = x - chunk->next_x;
|
||||||
|
if (chunk->pattern != chunk->next_pattern || dx != 0) {
|
||||||
|
sixel_print_repeat(&chunk->data, &chunk->len,
|
||||||
|
&chunk->used, chunk->count,
|
||||||
|
chunk->pattern + 0x3f);
|
||||||
|
sixel_print_repeat(&chunk->data, &chunk->len,
|
||||||
|
&chunk->used, dx, '?');
|
||||||
|
chunk->pattern = chunk->next_pattern;
|
||||||
|
chunk->count = 0;
|
||||||
|
}
|
||||||
|
chunk->count++;
|
||||||
|
chunk->next_pattern = 0;
|
||||||
|
chunk->next_x = x + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size)
|
sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size)
|
||||||
{
|
{
|
||||||
char *buf, tmp[64], *contains, data, last = 0;
|
char *buf, tmp[64];
|
||||||
size_t len, used = 0, tmplen;
|
size_t len, used = 0, tmplen;
|
||||||
u_int *colours, ncolours, i, c, x, y, count;
|
u_int *colours, ncolours, i, c, y, *active, nactive;
|
||||||
struct sixel_line *sl;
|
struct sixel_chunk *chunks, *chunk;
|
||||||
|
|
||||||
if (map != NULL) {
|
if (map != NULL) {
|
||||||
colours = map->colours;
|
colours = map->colours;
|
||||||
@ -492,70 +579,55 @@ sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size)
|
|||||||
|
|
||||||
if (ncolours == 0)
|
if (ncolours == 0)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
contains = xcalloc(1, ncolours);
|
|
||||||
|
|
||||||
len = 8192;
|
len = 8192;
|
||||||
buf = xmalloc(len);
|
buf = xmalloc(len);
|
||||||
|
|
||||||
sixel_print_add(&buf, &len, &used, "\033Pq", 3);
|
tmplen = xsnprintf(tmp, sizeof tmp, "\033P0;%uq", si->p2);
|
||||||
|
|
||||||
tmplen = xsnprintf(tmp, sizeof tmp, "\"1;1;%u;%u", si->x, si->y);
|
|
||||||
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
||||||
|
|
||||||
|
if (si->set_ra) {
|
||||||
|
tmplen = xsnprintf(tmp, sizeof tmp, "\"1;1;%u;%u", si->ra_x,
|
||||||
|
si->ra_y);
|
||||||
|
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
||||||
|
}
|
||||||
|
|
||||||
|
chunks = xcalloc(ncolours, sizeof *chunks);
|
||||||
|
active = xcalloc(ncolours, sizeof *active);
|
||||||
|
|
||||||
for (i = 0; i < ncolours; i++) {
|
for (i = 0; i < ncolours; i++) {
|
||||||
c = colours[i];
|
c = colours[i];
|
||||||
tmplen = xsnprintf(tmp, sizeof tmp, "#%u;%u;%u;%u;%u",
|
tmplen = xsnprintf(tmp, sizeof tmp, "#%u;%u;%u;%u;%u",
|
||||||
i, c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
|
i, c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
|
||||||
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
||||||
|
|
||||||
|
chunk = &chunks[i];
|
||||||
|
chunk->len = 8;
|
||||||
|
chunk->data = xmalloc(chunk->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (y = 0; y < si->y; y += 6) {
|
for (y = 0; y < si->y; y += 6) {
|
||||||
memset(contains, 0, ncolours);
|
nactive = 0;
|
||||||
for (x = 0; x < si->x; x++) {
|
sixel_print_compress_colors(si, chunks, y, active, &nactive);
|
||||||
for (i = 0; i < 6; i++) {
|
|
||||||
if (y + i >= si->y)
|
|
||||||
break;
|
|
||||||
sl = &si->lines[y + i];
|
|
||||||
if (x < sl->x && sl->data[x] != 0)
|
|
||||||
contains[sl->data[x] - 1] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (c = 0; c < ncolours; c++) {
|
for (i = 0; i < nactive; i++) {
|
||||||
if (!contains[c])
|
c = active[i];
|
||||||
continue;
|
chunk = &chunks[c];
|
||||||
tmplen = xsnprintf(tmp, sizeof tmp, "#%u", c);
|
tmplen = xsnprintf(tmp, sizeof tmp, "#%u", c);
|
||||||
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
||||||
|
sixel_print_add(&buf, &len, &used, chunk->data,
|
||||||
count = 0;
|
chunk->used);
|
||||||
for (x = 0; x < si->x; x++) {
|
sixel_print_repeat(&buf, &len, &used, chunk->count,
|
||||||
data = 0;
|
chunk->pattern + 0x3f);
|
||||||
for (i = 0; i < 6; i++) {
|
|
||||||
if (y + i >= si->y)
|
|
||||||
break;
|
|
||||||
sl = &si->lines[y + i];
|
|
||||||
if (x < sl->x && sl->data[x] == c + 1)
|
|
||||||
data |= (1 << i);
|
|
||||||
}
|
|
||||||
data += 0x3f;
|
|
||||||
if (data != last) {
|
|
||||||
sixel_print_repeat(&buf, &len, &used,
|
|
||||||
count, last);
|
|
||||||
last = data;
|
|
||||||
count = 1;
|
|
||||||
} else
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
sixel_print_repeat(&buf, &len, &used, count, data);
|
|
||||||
sixel_print_add(&buf, &len, &used, "$", 1);
|
sixel_print_add(&buf, &len, &used, "$", 1);
|
||||||
|
chunk->used = chunk->next_x = chunk->count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf[used - 1] == '$')
|
if (buf[used - 1] == '$')
|
||||||
used--;
|
used--;
|
||||||
if (buf[used - 1] != '-')
|
sixel_print_add(&buf, &len, &used, "-", 1);
|
||||||
sixel_print_add(&buf, &len, &used, "-", 1);
|
|
||||||
}
|
}
|
||||||
if (buf[used - 1] == '$' || buf[used - 1] == '-')
|
if (buf[used - 1] == '-')
|
||||||
used--;
|
used--;
|
||||||
|
|
||||||
sixel_print_add(&buf, &len, &used, "\033\\", 2);
|
sixel_print_add(&buf, &len, &used, "\033\\", 2);
|
||||||
@ -564,7 +636,11 @@ sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size)
|
|||||||
if (size != NULL)
|
if (size != NULL)
|
||||||
*size = used;
|
*size = used;
|
||||||
|
|
||||||
free(contains);
|
for (i = 0; i < ncolours; i++)
|
||||||
|
free(chunks[i].data);
|
||||||
|
free(active);
|
||||||
|
free(chunks);
|
||||||
|
|
||||||
return (buf);
|
return (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
58
input-keys.c
58
input-keys.c
@ -53,9 +53,15 @@ static struct input_key_entry input_key_defaults[] = {
|
|||||||
{ .key = KEYC_PASTE_START,
|
{ .key = KEYC_PASTE_START,
|
||||||
.data = "\033[200~"
|
.data = "\033[200~"
|
||||||
},
|
},
|
||||||
|
{ .key = KEYC_PASTE_START|KEYC_IMPLIED_META,
|
||||||
|
.data = "\033[200~"
|
||||||
|
},
|
||||||
{ .key = KEYC_PASTE_END,
|
{ .key = KEYC_PASTE_END,
|
||||||
.data = "\033[201~"
|
.data = "\033[201~"
|
||||||
},
|
},
|
||||||
|
{ .key = KEYC_PASTE_END|KEYC_IMPLIED_META,
|
||||||
|
.data = "\033[201~"
|
||||||
|
},
|
||||||
|
|
||||||
/* Function keys. */
|
/* Function keys. */
|
||||||
{ .key = KEYC_F1,
|
{ .key = KEYC_F1,
|
||||||
@ -307,6 +313,12 @@ static struct input_key_entry input_key_defaults[] = {
|
|||||||
{ .key = KEYC_DC|KEYC_BUILD_MODIFIERS,
|
{ .key = KEYC_DC|KEYC_BUILD_MODIFIERS,
|
||||||
.data = "\033[3;_~"
|
.data = "\033[3;_~"
|
||||||
},
|
},
|
||||||
|
{ .key = KEYC_REPORT_DARK_THEME,
|
||||||
|
.data = "\033[?997;1n"
|
||||||
|
},
|
||||||
|
{ .key = KEYC_REPORT_LIGHT_THEME,
|
||||||
|
.data = "\033[?997;2n"
|
||||||
|
},
|
||||||
};
|
};
|
||||||
static const key_code input_key_modifiers[] = {
|
static const key_code input_key_modifiers[] = {
|
||||||
0,
|
0,
|
||||||
@ -498,9 +510,12 @@ input_key_vt10x(struct bufferevent *bev, key_code key)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prevent TAB and RET from being swallowed by C0 remapping logic. */
|
/*
|
||||||
|
* Prevent TAB, CR and LF from being swallowed by the C0 remapping
|
||||||
|
* logic.
|
||||||
|
*/
|
||||||
onlykey = key & KEYC_MASK_KEY;
|
onlykey = key & KEYC_MASK_KEY;
|
||||||
if (onlykey == '\r' || onlykey == '\t')
|
if (onlykey == '\r' || onlykey == '\n' || onlykey == '\t')
|
||||||
key &= ~KEYC_CTRL;
|
key &= ~KEYC_CTRL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -539,12 +554,16 @@ input_key_mode1(struct bufferevent *bev, key_code key)
|
|||||||
|
|
||||||
log_debug("%s: key in %llx", __func__, key);
|
log_debug("%s: key in %llx", __func__, key);
|
||||||
|
|
||||||
|
/* A regular or shifted key + Meta. */
|
||||||
|
if ((key & (KEYC_CTRL | KEYC_META)) == KEYC_META)
|
||||||
|
return (input_key_vt10x(bev, key));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As per
|
* As per
|
||||||
* https://invisible-island.net/xterm/modified-keys-us-pc105.html.
|
* https://invisible-island.net/xterm/modified-keys-us-pc105.html.
|
||||||
*/
|
*/
|
||||||
onlykey = key & KEYC_MASK_KEY;
|
onlykey = key & KEYC_MASK_KEY;
|
||||||
if ((key & (KEYC_META | KEYC_CTRL)) == KEYC_CTRL &&
|
if ((key & KEYC_CTRL) &&
|
||||||
(onlykey == ' ' ||
|
(onlykey == ' ' ||
|
||||||
onlykey == '/' ||
|
onlykey == '/' ||
|
||||||
onlykey == '@' ||
|
onlykey == '@' ||
|
||||||
@ -553,13 +572,6 @@ input_key_mode1(struct bufferevent *bev, key_code key)
|
|||||||
(onlykey >= '@' && onlykey <= '~')))
|
(onlykey >= '@' && onlykey <= '~')))
|
||||||
return (input_key_vt10x(bev, key));
|
return (input_key_vt10x(bev, key));
|
||||||
|
|
||||||
/*
|
|
||||||
* A regular key + Meta. In the absence of a standard to back this, we
|
|
||||||
* mimic what iTerm 2 does.
|
|
||||||
*/
|
|
||||||
if ((key & (KEYC_CTRL | KEYC_META)) == KEYC_META)
|
|
||||||
return (input_key_vt10x(bev, key));
|
|
||||||
|
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,14 +597,29 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
|
|||||||
/* Is this backspace? */
|
/* Is this backspace? */
|
||||||
if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) {
|
if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) {
|
||||||
newkey = options_get_number(global_options, "backspace");
|
newkey = options_get_number(global_options, "backspace");
|
||||||
if (newkey >= 0x7f)
|
log_debug("%s: key 0x%llx is backspace -> 0x%llx", __func__,
|
||||||
newkey = '\177';
|
key, newkey);
|
||||||
key = newkey|(key & (KEYC_MASK_MODIFIERS|KEYC_MASK_FLAGS));
|
if ((key & KEYC_MASK_MODIFIERS) == 0) {
|
||||||
|
ud.data[0] = 255;
|
||||||
|
if ((newkey & KEYC_MASK_MODIFIERS) == 0)
|
||||||
|
ud.data[0] = newkey;
|
||||||
|
else if ((newkey & KEYC_MASK_MODIFIERS) == KEYC_CTRL) {
|
||||||
|
newkey &= KEYC_MASK_KEY;
|
||||||
|
if (newkey >= 'A' && newkey <= 'Z')
|
||||||
|
ud.data[0] = newkey - 0x40;
|
||||||
|
else if (newkey >= 'a' && newkey <= 'z')
|
||||||
|
ud.data[0] = newkey - 0x60;
|
||||||
|
}
|
||||||
|
if (ud.data[0] != 255)
|
||||||
|
input_key_write(__func__, bev, &ud.data[0], 1);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
key = newkey|(key & (KEYC_MASK_FLAGS|KEYC_MASK_MODIFIERS));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is this backtab? */
|
/* Is this backtab? */
|
||||||
if ((key & KEYC_MASK_KEY) == KEYC_BTAB) {
|
if ((key & KEYC_MASK_KEY) == KEYC_BTAB) {
|
||||||
if ((s->mode & EXTENDED_KEY_MODES) != 0) {
|
if (s->mode & MODE_KEYS_EXTENDED_2) {
|
||||||
/* When in xterm extended mode, remap into S-Tab. */
|
/* When in xterm extended mode, remap into S-Tab. */
|
||||||
key = '\011' | (key & ~KEYC_MASK_KEY) | KEYC_SHIFT;
|
key = '\011' | (key & ~KEYC_MASK_KEY) | KEYC_SHIFT;
|
||||||
} else {
|
} else {
|
||||||
@ -641,8 +668,7 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
|
|||||||
if (ike != NULL) {
|
if (ike != NULL) {
|
||||||
log_debug("%s: found key 0x%llx: \"%s\"", __func__, key,
|
log_debug("%s: found key 0x%llx: \"%s\"", __func__, key,
|
||||||
ike->data);
|
ike->data);
|
||||||
if ((key == KEYC_PASTE_START || key == KEYC_PASTE_END) &&
|
if (KEYC_IS_PASTE(key) && (~s->mode & MODE_BRACKETPASTE))
|
||||||
(~s->mode & MODE_BRACKETPASTE))
|
|
||||||
return (0);
|
return (0);
|
||||||
if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META))
|
if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META))
|
||||||
input_key_write(__func__, bev, "\033", 1);
|
input_key_write(__func__, bev, "\033", 1);
|
||||||
|
198
input.c
198
input.c
@ -93,7 +93,6 @@ struct input_ctx {
|
|||||||
size_t param_len;
|
size_t param_len;
|
||||||
|
|
||||||
#define INPUT_BUF_START 32
|
#define INPUT_BUF_START 32
|
||||||
#define INPUT_BUF_LIMIT 1048576
|
|
||||||
u_char *input_buf;
|
u_char *input_buf;
|
||||||
size_t input_len;
|
size_t input_len;
|
||||||
size_t input_space;
|
size_t input_space;
|
||||||
@ -134,7 +133,7 @@ static void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...);
|
|||||||
static void input_set_state(struct input_ctx *,
|
static void input_set_state(struct input_ctx *,
|
||||||
const struct input_transition *);
|
const struct input_transition *);
|
||||||
static void input_reset_cell(struct input_ctx *);
|
static void input_reset_cell(struct input_ctx *);
|
||||||
|
static void input_report_current_theme(struct input_ctx *);
|
||||||
static void input_osc_4(struct input_ctx *, const char *);
|
static void input_osc_4(struct input_ctx *, const char *);
|
||||||
static void input_osc_8(struct input_ctx *, const char *);
|
static void input_osc_8(struct input_ctx *, const char *);
|
||||||
static void input_osc_10(struct input_ctx *, const char *);
|
static void input_osc_10(struct input_ctx *, const char *);
|
||||||
@ -244,6 +243,7 @@ enum input_csi_type {
|
|||||||
INPUT_CSI_DECSTBM,
|
INPUT_CSI_DECSTBM,
|
||||||
INPUT_CSI_DL,
|
INPUT_CSI_DL,
|
||||||
INPUT_CSI_DSR,
|
INPUT_CSI_DSR,
|
||||||
|
INPUT_CSI_DSR_PRIVATE,
|
||||||
INPUT_CSI_ECH,
|
INPUT_CSI_ECH,
|
||||||
INPUT_CSI_ED,
|
INPUT_CSI_ED,
|
||||||
INPUT_CSI_EL,
|
INPUT_CSI_EL,
|
||||||
@ -252,6 +252,7 @@ enum input_csi_type {
|
|||||||
INPUT_CSI_IL,
|
INPUT_CSI_IL,
|
||||||
INPUT_CSI_MODOFF,
|
INPUT_CSI_MODOFF,
|
||||||
INPUT_CSI_MODSET,
|
INPUT_CSI_MODSET,
|
||||||
|
INPUT_CSI_QUERY_PRIVATE,
|
||||||
INPUT_CSI_RCP,
|
INPUT_CSI_RCP,
|
||||||
INPUT_CSI_REP,
|
INPUT_CSI_REP,
|
||||||
INPUT_CSI_RM,
|
INPUT_CSI_RM,
|
||||||
@ -260,8 +261,8 @@ enum input_csi_type {
|
|||||||
INPUT_CSI_SD,
|
INPUT_CSI_SD,
|
||||||
INPUT_CSI_SGR,
|
INPUT_CSI_SGR,
|
||||||
INPUT_CSI_SM,
|
INPUT_CSI_SM,
|
||||||
INPUT_CSI_SM_PRIVATE,
|
|
||||||
INPUT_CSI_SM_GRAPHICS,
|
INPUT_CSI_SM_GRAPHICS,
|
||||||
|
INPUT_CSI_SM_PRIVATE,
|
||||||
INPUT_CSI_SU,
|
INPUT_CSI_SU,
|
||||||
INPUT_CSI_TBC,
|
INPUT_CSI_TBC,
|
||||||
INPUT_CSI_VPA,
|
INPUT_CSI_VPA,
|
||||||
@ -305,6 +306,8 @@ static const struct input_table_entry input_csi_table[] = {
|
|||||||
{ 'm', ">", INPUT_CSI_MODSET },
|
{ 'm', ">", INPUT_CSI_MODSET },
|
||||||
{ 'n', "", INPUT_CSI_DSR },
|
{ 'n', "", INPUT_CSI_DSR },
|
||||||
{ 'n', ">", INPUT_CSI_MODOFF },
|
{ 'n', ">", INPUT_CSI_MODOFF },
|
||||||
|
{ 'n', "?", INPUT_CSI_DSR_PRIVATE },
|
||||||
|
{ 'p', "?$", INPUT_CSI_QUERY_PRIVATE },
|
||||||
{ 'q', " ", INPUT_CSI_DECSCUSR },
|
{ 'q', " ", INPUT_CSI_DECSCUSR },
|
||||||
{ 'q', ">", INPUT_CSI_XDA },
|
{ 'q', ">", INPUT_CSI_XDA },
|
||||||
{ 'r', "", INPUT_CSI_DECSTBM },
|
{ 'r', "", INPUT_CSI_DECSTBM },
|
||||||
@ -729,6 +732,9 @@ static const struct input_transition input_state_consume_st_table[] = {
|
|||||||
{ -1, -1, NULL, NULL }
|
{ -1, -1, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Maximum of bytes allowed to read in a single input. */
|
||||||
|
static size_t input_buffer_size = INPUT_BUF_DEFAULT_SIZE;
|
||||||
|
|
||||||
/* Input table compare. */
|
/* Input table compare. */
|
||||||
static int
|
static int
|
||||||
input_table_compare(const void *key, const void *value)
|
input_table_compare(const void *key, const void *value)
|
||||||
@ -1145,7 +1151,6 @@ input_print(struct input_ctx *ictx)
|
|||||||
ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
|
ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
|
||||||
else
|
else
|
||||||
ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
|
ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
|
||||||
|
|
||||||
utf8_set(&ictx->cell.cell.data, ictx->ch);
|
utf8_set(&ictx->cell.cell.data, ictx->ch);
|
||||||
screen_write_collect_add(sctx, &ictx->cell.cell);
|
screen_write_collect_add(sctx, &ictx->cell.cell);
|
||||||
|
|
||||||
@ -1194,7 +1199,7 @@ input_input(struct input_ctx *ictx)
|
|||||||
available = ictx->input_space;
|
available = ictx->input_space;
|
||||||
while (ictx->input_len + 1 >= available) {
|
while (ictx->input_len + 1 >= available) {
|
||||||
available *= 2;
|
available *= 2;
|
||||||
if (available > INPUT_BUF_LIMIT) {
|
if (available > input_buffer_size) {
|
||||||
ictx->flags |= INPUT_DISCARD;
|
ictx->flags |= INPUT_DISCARD;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -1214,6 +1219,10 @@ input_c0_dispatch(struct input_ctx *ictx)
|
|||||||
struct screen_write_ctx *sctx = &ictx->ctx;
|
struct screen_write_ctx *sctx = &ictx->ctx;
|
||||||
struct window_pane *wp = ictx->wp;
|
struct window_pane *wp = ictx->wp;
|
||||||
struct screen *s = sctx->s;
|
struct screen *s = sctx->s;
|
||||||
|
struct grid_cell gc, first_gc;
|
||||||
|
u_int cx = s->cx, line = s->cy + s->grid->hsize;
|
||||||
|
u_int width;
|
||||||
|
int has_content = 0;
|
||||||
|
|
||||||
ictx->utf8started = 0; /* can't be valid UTF-8 */
|
ictx->utf8started = 0; /* can't be valid UTF-8 */
|
||||||
|
|
||||||
@ -1235,11 +1244,28 @@ input_c0_dispatch(struct input_ctx *ictx)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* Find the next tab point, or use the last column if none. */
|
/* Find the next tab point, or use the last column if none. */
|
||||||
|
grid_get_cell(s->grid, s->cx, line, &first_gc);
|
||||||
do {
|
do {
|
||||||
s->cx++;
|
if (!has_content) {
|
||||||
if (bit_test(s->tabs, s->cx))
|
grid_get_cell(s->grid, cx, line, &gc);
|
||||||
|
if (gc.data.size != 1 ||
|
||||||
|
*gc.data.data != ' ' ||
|
||||||
|
!grid_cells_look_equal(&gc, &first_gc))
|
||||||
|
has_content = 1;
|
||||||
|
}
|
||||||
|
cx++;
|
||||||
|
if (bit_test(s->tabs, cx))
|
||||||
break;
|
break;
|
||||||
} while (s->cx < screen_size_x(s) - 1);
|
} while (cx < screen_size_x(s) - 1);
|
||||||
|
|
||||||
|
width = cx - s->cx;
|
||||||
|
if (has_content || width > sizeof gc.data.data)
|
||||||
|
s->cx = cx;
|
||||||
|
else {
|
||||||
|
grid_get_cell(s->grid, s->cx, line, &gc);
|
||||||
|
grid_set_tab(&gc, width);
|
||||||
|
screen_write_collect_add(sctx, &gc);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case '\012': /* LF */
|
case '\012': /* LF */
|
||||||
case '\013': /* VT */
|
case '\013': /* VT */
|
||||||
@ -1349,7 +1375,7 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
struct screen_write_ctx *sctx = &ictx->ctx;
|
struct screen_write_ctx *sctx = &ictx->ctx;
|
||||||
struct screen *s = sctx->s;
|
struct screen *s = sctx->s;
|
||||||
struct input_table_entry *entry;
|
struct input_table_entry *entry;
|
||||||
int i, n, m, ek;
|
int i, n, m, ek, set;
|
||||||
u_int cx, bg = ictx->cell.cell.bg;
|
u_int cx, bg = ictx->cell.cell.bg;
|
||||||
|
|
||||||
if (ictx->flags & INPUT_DISCARD)
|
if (ictx->flags & INPUT_DISCARD)
|
||||||
@ -1509,6 +1535,20 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
if (n != -1)
|
if (n != -1)
|
||||||
screen_write_deleteline(sctx, n, bg);
|
screen_write_deleteline(sctx, n, bg);
|
||||||
break;
|
break;
|
||||||
|
case INPUT_CSI_DSR_PRIVATE:
|
||||||
|
switch (input_get(ictx, 0, 0, 0)) {
|
||||||
|
case 996:
|
||||||
|
input_report_current_theme(ictx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INPUT_CSI_QUERY_PRIVATE:
|
||||||
|
switch (input_get(ictx, 0, 0, 0)) {
|
||||||
|
case 2031:
|
||||||
|
input_reply(ictx, "\033[?2031;2$y");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case INPUT_CSI_DSR:
|
case INPUT_CSI_DSR:
|
||||||
switch (input_get(ictx, 0, 0, 0)) {
|
switch (input_get(ictx, 0, 0, 0)) {
|
||||||
case -1:
|
case -1:
|
||||||
@ -1596,6 +1636,11 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
if (~ictx->flags & INPUT_LAST)
|
if (~ictx->flags & INPUT_LAST)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set;
|
||||||
|
if (set == 1)
|
||||||
|
ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
|
||||||
|
else
|
||||||
|
ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
|
||||||
utf8_copy(&ictx->cell.cell.data, &ictx->last);
|
utf8_copy(&ictx->cell.cell.data, &ictx->last);
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
screen_write_collect_add(sctx, &ictx->cell.cell);
|
screen_write_collect_add(sctx, &ictx->cell.cell);
|
||||||
@ -1754,6 +1799,9 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
|
|||||||
case 2004:
|
case 2004:
|
||||||
screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
|
screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
|
||||||
break;
|
break;
|
||||||
|
case 2031:
|
||||||
|
screen_write_mode_clear(sctx, MODE_THEME_UPDATES);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
@ -1849,6 +1897,9 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
|
|||||||
case 2004:
|
case 2004:
|
||||||
screen_write_mode_set(sctx, MODE_BRACKETPASTE);
|
screen_write_mode_set(sctx, MODE_BRACKETPASTE);
|
||||||
break;
|
break;
|
||||||
|
case 2031:
|
||||||
|
screen_write_mode_set(sctx, MODE_THEME_UPDATES);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
@ -2320,6 +2371,7 @@ input_dcs_dispatch(struct input_ctx *ictx)
|
|||||||
#ifdef ENABLE_SIXEL
|
#ifdef ENABLE_SIXEL
|
||||||
struct window *w;
|
struct window *w;
|
||||||
struct sixel_image *si;
|
struct sixel_image *si;
|
||||||
|
int p2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (wp == NULL)
|
if (wp == NULL)
|
||||||
@ -2332,8 +2384,13 @@ input_dcs_dispatch(struct input_ctx *ictx)
|
|||||||
|
|
||||||
#ifdef ENABLE_SIXEL
|
#ifdef ENABLE_SIXEL
|
||||||
w = wp->window;
|
w = wp->window;
|
||||||
if (buf[0] == 'q') {
|
if (buf[0] == 'q' && ictx->interm_len == 0) {
|
||||||
si = sixel_parse(buf, len, w->xpixel, w->ypixel);
|
if (input_split(ictx) != 0)
|
||||||
|
return (0);
|
||||||
|
p2 = input_get(ictx, 1, 0, 0);
|
||||||
|
if (p2 == -1)
|
||||||
|
p2 = 0;
|
||||||
|
si = sixel_parse(buf, len, p2, w->xpixel, w->ypixel);
|
||||||
if (si != NULL)
|
if (si != NULL)
|
||||||
screen_write_sixelimage(sctx, si, ictx->cell.cell.bg);
|
screen_write_sixelimage(sctx, si, ictx->cell.cell.bg);
|
||||||
}
|
}
|
||||||
@ -2664,84 +2721,6 @@ bad:
|
|||||||
free(id);
|
free(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Get a client with a foreground for the pane. There isn't much to choose
|
|
||||||
* between them so just use the first.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
input_get_fg_client(struct window_pane *wp)
|
|
||||||
{
|
|
||||||
struct window *w = wp->window;
|
|
||||||
struct client *loop;
|
|
||||||
|
|
||||||
TAILQ_FOREACH(loop, &clients, entry) {
|
|
||||||
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
|
|
||||||
continue;
|
|
||||||
if (loop->session == NULL || !session_has(loop->session, w))
|
|
||||||
continue;
|
|
||||||
if (loop->tty.fg == -1)
|
|
||||||
continue;
|
|
||||||
return (loop->tty.fg);
|
|
||||||
}
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get a client with a background for the pane. */
|
|
||||||
static int
|
|
||||||
input_get_bg_client(struct window_pane *wp)
|
|
||||||
{
|
|
||||||
struct window *w = wp->window;
|
|
||||||
struct client *loop;
|
|
||||||
|
|
||||||
TAILQ_FOREACH(loop, &clients, entry) {
|
|
||||||
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
|
|
||||||
continue;
|
|
||||||
if (loop->session == NULL || !session_has(loop->session, w))
|
|
||||||
continue;
|
|
||||||
if (loop->tty.bg == -1)
|
|
||||||
continue;
|
|
||||||
return (loop->tty.bg);
|
|
||||||
}
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If any control mode client exists that has provided a bg color, return it.
|
|
||||||
* Otherwise, return -1.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
input_get_bg_control_client(struct window_pane *wp)
|
|
||||||
{
|
|
||||||
struct client *c;
|
|
||||||
|
|
||||||
if (wp->control_bg == -1)
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
TAILQ_FOREACH(c, &clients, entry) {
|
|
||||||
if (c->flags & CLIENT_CONTROL)
|
|
||||||
return (wp->control_bg);
|
|
||||||
}
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If any control mode client exists that has provided a fg color, return it.
|
|
||||||
* Otherwise, return -1.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
input_get_fg_control_client(struct window_pane *wp)
|
|
||||||
{
|
|
||||||
struct client *c;
|
|
||||||
|
|
||||||
if (wp->control_fg == -1)
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
TAILQ_FOREACH(c, &clients, entry) {
|
|
||||||
if (c->flags & CLIENT_CONTROL)
|
|
||||||
return (wp->control_fg);
|
|
||||||
}
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle the OSC 10 sequence for setting and querying foreground colour. */
|
/* Handle the OSC 10 sequence for setting and querying foreground colour. */
|
||||||
static void
|
static void
|
||||||
@ -2754,11 +2733,11 @@ input_osc_10(struct input_ctx *ictx, const char *p)
|
|||||||
if (strcmp(p, "?") == 0) {
|
if (strcmp(p, "?") == 0) {
|
||||||
if (wp == NULL)
|
if (wp == NULL)
|
||||||
return;
|
return;
|
||||||
c = input_get_fg_control_client(wp);
|
c = window_pane_get_fg_control_client(wp);
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
tty_default_colours(&defaults, wp);
|
tty_default_colours(&defaults, wp);
|
||||||
if (COLOUR_DEFAULT(defaults.fg))
|
if (COLOUR_DEFAULT(defaults.fg))
|
||||||
c = input_get_fg_client(wp);
|
c = window_pane_get_fg(wp);
|
||||||
else
|
else
|
||||||
c = defaults.fg;
|
c = defaults.fg;
|
||||||
}
|
}
|
||||||
@ -2799,20 +2778,12 @@ static void
|
|||||||
input_osc_11(struct input_ctx *ictx, const char *p)
|
input_osc_11(struct input_ctx *ictx, const char *p)
|
||||||
{
|
{
|
||||||
struct window_pane *wp = ictx->wp;
|
struct window_pane *wp = ictx->wp;
|
||||||
struct grid_cell defaults;
|
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
if (strcmp(p, "?") == 0) {
|
if (strcmp(p, "?") == 0) {
|
||||||
if (wp == NULL)
|
if (wp == NULL)
|
||||||
return;
|
return;
|
||||||
c = input_get_bg_control_client(wp);
|
c = window_pane_get_bg(wp);
|
||||||
if (c == -1) {
|
|
||||||
tty_default_colours(&defaults, wp);
|
|
||||||
if (COLOUR_DEFAULT(defaults.bg))
|
|
||||||
c = input_get_bg_client(wp);
|
|
||||||
else
|
|
||||||
c = defaults.bg;
|
|
||||||
}
|
|
||||||
input_osc_colour_reply(ictx, 11, c);
|
input_osc_colour_reply(ictx, 11, c);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2824,7 +2795,7 @@ input_osc_11(struct input_ctx *ictx, const char *p)
|
|||||||
if (ictx->palette != NULL) {
|
if (ictx->palette != NULL) {
|
||||||
ictx->palette->bg = c;
|
ictx->palette->bg = c;
|
||||||
if (wp != NULL)
|
if (wp != NULL)
|
||||||
wp->flags |= PANE_STYLECHANGED;
|
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||||
screen_write_fullredraw(&ictx->ctx);
|
screen_write_fullredraw(&ictx->ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2840,7 +2811,7 @@ input_osc_111(struct input_ctx *ictx, const char *p)
|
|||||||
if (ictx->palette != NULL) {
|
if (ictx->palette != NULL) {
|
||||||
ictx->palette->bg = 8;
|
ictx->palette->bg = 8;
|
||||||
if (wp != NULL)
|
if (wp != NULL)
|
||||||
wp->flags |= PANE_STYLECHANGED;
|
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||||
screen_write_fullredraw(&ictx->ctx);
|
screen_write_fullredraw(&ictx->ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3023,3 +2994,26 @@ input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len,
|
|||||||
bufferevent_write(bev, end, strlen(end));
|
bufferevent_write(bev, end, strlen(end));
|
||||||
free(out);
|
free(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set input buffer size. */
|
||||||
|
void
|
||||||
|
input_set_buffer_size(size_t buffer_size)
|
||||||
|
{
|
||||||
|
log_debug("%s: %lu -> %lu", __func__, input_buffer_size, buffer_size);
|
||||||
|
input_buffer_size = buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
input_report_current_theme(struct input_ctx *ictx)
|
||||||
|
{
|
||||||
|
switch (window_pane_get_theme(ictx->wp)) {
|
||||||
|
case THEME_DARK:
|
||||||
|
input_reply(ictx, "\033[?997;1n");
|
||||||
|
break;
|
||||||
|
case THEME_LIGHT:
|
||||||
|
input_reply(ictx, "\033[?997;2n");
|
||||||
|
break;
|
||||||
|
case THEME_UNKNOWN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
58
job.c
58
job.c
@ -69,18 +69,20 @@ static LIST_HEAD(joblist, job) all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
|
|||||||
|
|
||||||
/* Start a job running. */
|
/* Start a job running. */
|
||||||
struct job *
|
struct job *
|
||||||
job_run(const char *cmd, int argc, char **argv, struct environ *e, struct session *s,
|
job_run(const char *cmd, int argc, char **argv, struct environ *e,
|
||||||
const char *cwd, job_update_cb updatecb, job_complete_cb completecb,
|
struct session *s, const char *cwd, job_update_cb updatecb,
|
||||||
job_free_cb freecb, void *data, int flags, int sx, int sy)
|
job_complete_cb completecb, job_free_cb freecb, void *data, int flags,
|
||||||
|
int sx, int sy)
|
||||||
{
|
{
|
||||||
struct job *job;
|
struct job *job;
|
||||||
struct environ *env;
|
struct environ *env;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int nullfd, out[2], master;
|
int nullfd, out[2], master, do_close = 1;
|
||||||
const char *home, *shell;
|
const char *home, *shell;
|
||||||
sigset_t set, oldset;
|
sigset_t set, oldset;
|
||||||
struct winsize ws;
|
struct winsize ws;
|
||||||
char **argvp, tty[TTY_NAME_MAX], *argv0;
|
char **argvp, tty[TTY_NAME_MAX], *argv0;
|
||||||
|
struct options *oo;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do not set TERM during .tmux.conf (second argument here), it is nice
|
* Do not set TERM during .tmux.conf (second argument here), it is nice
|
||||||
@ -91,12 +93,17 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio
|
|||||||
if (e != NULL)
|
if (e != NULL)
|
||||||
environ_copy(e, env);
|
environ_copy(e, env);
|
||||||
|
|
||||||
if (s != NULL)
|
if (~flags & JOB_DEFAULTSHELL)
|
||||||
shell = options_get_string(s->options, "default-shell");
|
|
||||||
else
|
|
||||||
shell = options_get_string(global_s_options, "default-shell");
|
|
||||||
if (!checkshell(shell))
|
|
||||||
shell = _PATH_BSHELL;
|
shell = _PATH_BSHELL;
|
||||||
|
else {
|
||||||
|
if (s != NULL)
|
||||||
|
oo = s->options;
|
||||||
|
else
|
||||||
|
oo = global_s_options;
|
||||||
|
shell = options_get_string(oo, "default-shell");
|
||||||
|
if (!checkshell(shell))
|
||||||
|
shell = _PATH_BSHELL;
|
||||||
|
}
|
||||||
argv0 = shell_argv0(shell, 0);
|
argv0 = shell_argv0(shell, 0);
|
||||||
|
|
||||||
sigfillset(&set);
|
sigfillset(&set);
|
||||||
@ -143,24 +150,32 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio
|
|||||||
if (~flags & JOB_PTY) {
|
if (~flags & JOB_PTY) {
|
||||||
if (dup2(out[1], STDIN_FILENO) == -1)
|
if (dup2(out[1], STDIN_FILENO) == -1)
|
||||||
fatal("dup2 failed");
|
fatal("dup2 failed");
|
||||||
|
do_close = do_close && out[1] != STDIN_FILENO;
|
||||||
if (dup2(out[1], STDOUT_FILENO) == -1)
|
if (dup2(out[1], STDOUT_FILENO) == -1)
|
||||||
fatal("dup2 failed");
|
fatal("dup2 failed");
|
||||||
if (out[1] != STDIN_FILENO && out[1] != STDOUT_FILENO)
|
do_close = do_close && out[1] != STDOUT_FILENO;
|
||||||
|
if (flags & JOB_SHOWSTDERR) {
|
||||||
|
if (dup2(out[1], STDERR_FILENO) == -1)
|
||||||
|
fatal("dup2 failed");
|
||||||
|
do_close = do_close && out[1] != STDERR_FILENO;
|
||||||
|
} else {
|
||||||
|
nullfd = open(_PATH_DEVNULL, O_RDWR);
|
||||||
|
if (nullfd == -1)
|
||||||
|
fatal("open failed");
|
||||||
|
if (dup2(nullfd, STDERR_FILENO) == -1)
|
||||||
|
fatal("dup2 failed");
|
||||||
|
if (nullfd != STDERR_FILENO)
|
||||||
|
close(nullfd);
|
||||||
|
}
|
||||||
|
if (do_close)
|
||||||
close(out[1]);
|
close(out[1]);
|
||||||
close(out[0]);
|
close(out[0]);
|
||||||
|
|
||||||
nullfd = open(_PATH_DEVNULL, O_RDWR);
|
|
||||||
if (nullfd == -1)
|
|
||||||
fatal("open failed");
|
|
||||||
if (dup2(nullfd, STDERR_FILENO) == -1)
|
|
||||||
fatal("dup2 failed");
|
|
||||||
if (nullfd != STDERR_FILENO)
|
|
||||||
close(nullfd);
|
|
||||||
}
|
}
|
||||||
closefrom(STDERR_FILENO + 1);
|
closefrom(STDERR_FILENO + 1);
|
||||||
|
|
||||||
if (cmd != NULL) {
|
if (cmd != NULL) {
|
||||||
setenv("SHELL", shell, 1);
|
if (flags & JOB_DEFAULTSHELL)
|
||||||
|
setenv("SHELL", shell, 1);
|
||||||
execl(shell, argv0, "-c", cmd, (char *)NULL);
|
execl(shell, argv0, "-c", cmd, (char *)NULL);
|
||||||
fatal("execl failed");
|
fatal("execl failed");
|
||||||
} else {
|
} else {
|
||||||
@ -174,7 +189,7 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio
|
|||||||
environ_free(env);
|
environ_free(env);
|
||||||
free(argv0);
|
free(argv0);
|
||||||
|
|
||||||
job = xmalloc(sizeof *job);
|
job = xcalloc(1, sizeof *job);
|
||||||
job->state = JOB_RUNNING;
|
job->state = JOB_RUNNING;
|
||||||
job->flags = flags;
|
job->flags = flags;
|
||||||
|
|
||||||
@ -183,7 +198,8 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio
|
|||||||
else
|
else
|
||||||
job->cmd = cmd_stringify_argv(argc, argv);
|
job->cmd = cmd_stringify_argv(argc, argv);
|
||||||
job->pid = pid;
|
job->pid = pid;
|
||||||
strlcpy(job->tty, tty, sizeof job->tty);
|
if (flags & JOB_PTY)
|
||||||
|
strlcpy(job->tty, tty, sizeof job->tty);
|
||||||
job->status = 0;
|
job->status = 0;
|
||||||
|
|
||||||
LIST_INSERT_HEAD(&all_jobs, job, entry);
|
LIST_INSERT_HEAD(&all_jobs, job, entry);
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
" '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}' '<' {send -X history-top}" \
|
" '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}' '<' {send -X history-top}" \
|
||||||
" '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}' '>' {send -X history-bottom}" \
|
" '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}' '>' {send -X history-bottom}" \
|
||||||
" ''" \
|
" ''" \
|
||||||
" '#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}' 'C-r' {if -F '#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}' 'copy-mode -t='; send -Xt= search-backward \"#{q:mouse_word}\"}" \
|
" '#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}' 'C-r' {if -F '#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}' 'copy-mode -t='; send -Xt= search-backward -- \"#{q:mouse_word}\"}" \
|
||||||
" '#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}' 'C-y' {copy-mode -q; send-keys -l -- \"#{q:mouse_word}\"}" \
|
" '#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}' 'C-y' {copy-mode -q; send-keys -l -- \"#{q:mouse_word}\"}" \
|
||||||
" '#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}' 'c' {copy-mode -q; set-buffer -- \"#{q:mouse_word}\"}" \
|
" '#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}' 'c' {copy-mode -q; set-buffer -- \"#{q:mouse_word}\"}" \
|
||||||
" '#{?mouse_line,Copy Line,}' 'l' {copy-mode -q; set-buffer -- \"#{q:mouse_line}\"}" \
|
" '#{?mouse_line,Copy Line,}' 'l' {copy-mode -q; set-buffer -- \"#{q:mouse_line}\"}" \
|
||||||
@ -197,11 +197,12 @@ key_bindings_add(const char *name, key_code key, const char *note, int repeat,
|
|||||||
bd = key_bindings_get(table, key & ~KEYC_MASK_FLAGS);
|
bd = key_bindings_get(table, key & ~KEYC_MASK_FLAGS);
|
||||||
if (cmdlist == NULL) {
|
if (cmdlist == NULL) {
|
||||||
if (bd != NULL) {
|
if (bd != NULL) {
|
||||||
free((void *)bd->note);
|
if (note != NULL) {
|
||||||
if (note != NULL)
|
free((void *)bd->note);
|
||||||
bd->note = xstrdup(note);
|
bd->note = xstrdup(note);
|
||||||
else
|
}
|
||||||
bd->note = NULL;
|
if (repeat)
|
||||||
|
bd->flags |= KEY_BINDING_REPEAT;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -433,8 +434,9 @@ key_bindings_init(void)
|
|||||||
"bind -N 'Resize the pane right' -r C-Right { resize-pane -R }",
|
"bind -N 'Resize the pane right' -r C-Right { resize-pane -R }",
|
||||||
|
|
||||||
/* Menu keys */
|
/* Menu keys */
|
||||||
"bind < { display-menu -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU " }",
|
"bind -N 'Display window menu' < { display-menu -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU " }",
|
||||||
"bind > { display-menu -xP -yP -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }",
|
"bind -N 'Display pane menu' > { display-menu -xP -yP -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }",
|
||||||
|
|
||||||
|
|
||||||
/* Mouse button 1 down on pane. */
|
/* Mouse button 1 down on pane. */
|
||||||
"bind -n MouseDown1Pane { select-pane -t=; send -M }",
|
"bind -n MouseDown1Pane { select-pane -t=; send -M }",
|
||||||
@ -478,6 +480,11 @@ key_bindings_init(void)
|
|||||||
"bind -n MouseDown3Pane { if -Ft= '#{||:#{mouse_any_flag},#{&&:#{pane_in_mode},#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}}}' { select-pane -t=; send -M } { display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " } }",
|
"bind -n MouseDown3Pane { if -Ft= '#{||:#{mouse_any_flag},#{&&:#{pane_in_mode},#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}}}' { select-pane -t=; send -M } { display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " } }",
|
||||||
"bind -n M-MouseDown3Pane { display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }",
|
"bind -n M-MouseDown3Pane { display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }",
|
||||||
|
|
||||||
|
/* Mouse on scrollbar. */
|
||||||
|
"bind -n MouseDown1ScrollbarUp { copy-mode -u }",
|
||||||
|
"bind -n MouseDown1ScrollbarDown { copy-mode -d }",
|
||||||
|
"bind -n MouseDrag1ScrollbarSlider { copy-mode -S }",
|
||||||
|
|
||||||
/* Copy mode (emacs) keys. */
|
/* Copy mode (emacs) keys. */
|
||||||
"bind -Tcopy-mode C-Space { send -X begin-selection }",
|
"bind -Tcopy-mode C-Space { send -X begin-selection }",
|
||||||
"bind -Tcopy-mode C-a { send -X start-of-line }",
|
"bind -Tcopy-mode C-a { send -X start-of-line }",
|
||||||
@ -489,26 +496,26 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode C-k { send -X copy-pipe-end-of-line-and-cancel }",
|
"bind -Tcopy-mode C-k { send -X copy-pipe-end-of-line-and-cancel }",
|
||||||
"bind -Tcopy-mode C-n { send -X cursor-down }",
|
"bind -Tcopy-mode C-n { send -X cursor-down }",
|
||||||
"bind -Tcopy-mode C-p { send -X cursor-up }",
|
"bind -Tcopy-mode C-p { send -X cursor-up }",
|
||||||
"bind -Tcopy-mode C-r { command-prompt -T search -ip'(search up)' -I'#{pane_search_string}' { send -X search-backward-incremental '%%' } }",
|
"bind -Tcopy-mode C-r { command-prompt -T search -ip'(search up)' -I'#{pane_search_string}' { send -X search-backward-incremental -- '%%' } }",
|
||||||
"bind -Tcopy-mode C-s { command-prompt -T search -ip'(search down)' -I'#{pane_search_string}' { send -X search-forward-incremental '%%' } }",
|
"bind -Tcopy-mode C-s { command-prompt -T search -ip'(search down)' -I'#{pane_search_string}' { send -X search-forward-incremental -- '%%' } }",
|
||||||
"bind -Tcopy-mode C-v { send -X page-down }",
|
"bind -Tcopy-mode C-v { send -X page-down }",
|
||||||
"bind -Tcopy-mode C-w { send -X copy-pipe-and-cancel }",
|
"bind -Tcopy-mode C-w { send -X copy-pipe-and-cancel }",
|
||||||
"bind -Tcopy-mode Escape { send -X cancel }",
|
"bind -Tcopy-mode Escape { send -X cancel }",
|
||||||
"bind -Tcopy-mode Space { send -X page-down }",
|
"bind -Tcopy-mode Space { send -X page-down }",
|
||||||
"bind -Tcopy-mode , { send -X jump-reverse }",
|
"bind -Tcopy-mode , { send -X jump-reverse }",
|
||||||
"bind -Tcopy-mode \\; { send -X jump-again }",
|
"bind -Tcopy-mode \\; { send -X jump-again }",
|
||||||
"bind -Tcopy-mode F { command-prompt -1p'(jump backward)' { send -X jump-backward '%%' } }",
|
"bind -Tcopy-mode F { command-prompt -1p'(jump backward)' { send -X jump-backward -- '%%' } }",
|
||||||
"bind -Tcopy-mode N { send -X search-reverse }",
|
"bind -Tcopy-mode N { send -X search-reverse }",
|
||||||
"bind -Tcopy-mode P { send -X toggle-position }",
|
"bind -Tcopy-mode P { send -X toggle-position }",
|
||||||
"bind -Tcopy-mode R { send -X rectangle-toggle }",
|
"bind -Tcopy-mode R { send -X rectangle-toggle }",
|
||||||
"bind -Tcopy-mode T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward '%%' } }",
|
"bind -Tcopy-mode T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward -- '%%' } }",
|
||||||
"bind -Tcopy-mode X { send -X set-mark }",
|
"bind -Tcopy-mode X { send -X set-mark }",
|
||||||
"bind -Tcopy-mode f { command-prompt -1p'(jump forward)' { send -X jump-forward '%%' } }",
|
"bind -Tcopy-mode f { command-prompt -1p'(jump forward)' { send -X jump-forward -- '%%' } }",
|
||||||
"bind -Tcopy-mode g { command-prompt -p'(goto line)' { send -X goto-line '%%' } }",
|
"bind -Tcopy-mode g { command-prompt -p'(goto line)' { send -X goto-line -- '%%' } }",
|
||||||
"bind -Tcopy-mode n { send -X search-again }",
|
"bind -Tcopy-mode n { send -X search-again }",
|
||||||
"bind -Tcopy-mode q { send -X cancel }",
|
"bind -Tcopy-mode q { send -X cancel }",
|
||||||
"bind -Tcopy-mode r { send -X refresh-from-pane }",
|
"bind -Tcopy-mode r { send -X refresh-from-pane }",
|
||||||
"bind -Tcopy-mode t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward '%%' } }",
|
"bind -Tcopy-mode t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }",
|
||||||
"bind -Tcopy-mode Home { send -X start-of-line }",
|
"bind -Tcopy-mode Home { send -X start-of-line }",
|
||||||
"bind -Tcopy-mode End { send -X end-of-line }",
|
"bind -Tcopy-mode End { send -X end-of-line }",
|
||||||
"bind -Tcopy-mode MouseDown1Pane select-pane",
|
"bind -Tcopy-mode MouseDown1Pane select-pane",
|
||||||
@ -553,8 +560,8 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode C-Down { send -X scroll-down }",
|
"bind -Tcopy-mode C-Down { send -X scroll-down }",
|
||||||
|
|
||||||
/* Copy mode (vi) keys. */
|
/* Copy mode (vi) keys. */
|
||||||
"bind -Tcopy-mode-vi '#' { send -FX search-backward '#{copy_cursor_word}' }",
|
"bind -Tcopy-mode-vi '#' { send -FX search-backward -- '#{copy_cursor_word}' }",
|
||||||
"bind -Tcopy-mode-vi * { send -FX search-forward '#{copy_cursor_word}' }",
|
"bind -Tcopy-mode-vi * { send -FX search-forward -- '#{copy_cursor_word}' }",
|
||||||
"bind -Tcopy-mode-vi C-c { send -X cancel }",
|
"bind -Tcopy-mode-vi C-c { send -X cancel }",
|
||||||
"bind -Tcopy-mode-vi C-d { send -X halfpage-down }",
|
"bind -Tcopy-mode-vi C-d { send -X halfpage-down }",
|
||||||
"bind -Tcopy-mode-vi C-e { send -X scroll-down }",
|
"bind -Tcopy-mode-vi C-e { send -X scroll-down }",
|
||||||
@ -570,7 +577,7 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode-vi Space { send -X begin-selection }",
|
"bind -Tcopy-mode-vi Space { send -X begin-selection }",
|
||||||
"bind -Tcopy-mode-vi '$' { send -X end-of-line }",
|
"bind -Tcopy-mode-vi '$' { send -X end-of-line }",
|
||||||
"bind -Tcopy-mode-vi , { send -X jump-reverse }",
|
"bind -Tcopy-mode-vi , { send -X jump-reverse }",
|
||||||
"bind -Tcopy-mode-vi / { command-prompt -T search -p'(search down)' { send -X search-forward '%%' } }",
|
"bind -Tcopy-mode-vi / { command-prompt -T search -p'(search down)' { send -X search-forward -- '%%' } }",
|
||||||
"bind -Tcopy-mode-vi 0 { send -X start-of-line }",
|
"bind -Tcopy-mode-vi 0 { send -X start-of-line }",
|
||||||
"bind -Tcopy-mode-vi 1 { command-prompt -Np'(repeat)' -I1 { send -N '%%' } }",
|
"bind -Tcopy-mode-vi 1 { command-prompt -Np'(repeat)' -I1 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode-vi 2 { command-prompt -Np'(repeat)' -I2 { send -N '%%' } }",
|
"bind -Tcopy-mode-vi 2 { command-prompt -Np'(repeat)' -I2 { send -N '%%' } }",
|
||||||
@ -581,14 +588,14 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode-vi 7 { command-prompt -Np'(repeat)' -I7 { send -N '%%' } }",
|
"bind -Tcopy-mode-vi 7 { command-prompt -Np'(repeat)' -I7 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode-vi 8 { command-prompt -Np'(repeat)' -I8 { send -N '%%' } }",
|
"bind -Tcopy-mode-vi 8 { command-prompt -Np'(repeat)' -I8 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode-vi 9 { command-prompt -Np'(repeat)' -I9 { send -N '%%' } }",
|
"bind -Tcopy-mode-vi 9 { command-prompt -Np'(repeat)' -I9 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode-vi : { command-prompt -p'(goto line)' { send -X goto-line '%%' } }",
|
"bind -Tcopy-mode-vi : { command-prompt -p'(goto line)' { send -X goto-line -- '%%' } }",
|
||||||
"bind -Tcopy-mode-vi \\; { send -X jump-again }",
|
"bind -Tcopy-mode-vi \\; { send -X jump-again }",
|
||||||
"bind -Tcopy-mode-vi ? { command-prompt -T search -p'(search up)' { send -X search-backward '%%' } }",
|
"bind -Tcopy-mode-vi ? { command-prompt -T search -p'(search up)' { send -X search-backward -- '%%' } }",
|
||||||
"bind -Tcopy-mode-vi A { send -X append-selection-and-cancel }",
|
"bind -Tcopy-mode-vi A { send -X append-selection-and-cancel }",
|
||||||
"bind -Tcopy-mode-vi B { send -X previous-space }",
|
"bind -Tcopy-mode-vi B { send -X previous-space }",
|
||||||
"bind -Tcopy-mode-vi D { send -X copy-pipe-end-of-line-and-cancel }",
|
"bind -Tcopy-mode-vi D { send -X copy-pipe-end-of-line-and-cancel }",
|
||||||
"bind -Tcopy-mode-vi E { send -X next-space-end }",
|
"bind -Tcopy-mode-vi E { send -X next-space-end }",
|
||||||
"bind -Tcopy-mode-vi F { command-prompt -1p'(jump backward)' { send -X jump-backward '%%' } }",
|
"bind -Tcopy-mode-vi F { command-prompt -1p'(jump backward)' { send -X jump-backward -- '%%' } }",
|
||||||
"bind -Tcopy-mode-vi G { send -X history-bottom }",
|
"bind -Tcopy-mode-vi G { send -X history-bottom }",
|
||||||
"bind -Tcopy-mode-vi H { send -X top-line }",
|
"bind -Tcopy-mode-vi H { send -X top-line }",
|
||||||
"bind -Tcopy-mode-vi J { send -X scroll-down }",
|
"bind -Tcopy-mode-vi J { send -X scroll-down }",
|
||||||
@ -597,14 +604,14 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode-vi M { send -X middle-line }",
|
"bind -Tcopy-mode-vi M { send -X middle-line }",
|
||||||
"bind -Tcopy-mode-vi N { send -X search-reverse }",
|
"bind -Tcopy-mode-vi N { send -X search-reverse }",
|
||||||
"bind -Tcopy-mode-vi P { send -X toggle-position }",
|
"bind -Tcopy-mode-vi P { send -X toggle-position }",
|
||||||
"bind -Tcopy-mode-vi T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward '%%' } }",
|
"bind -Tcopy-mode-vi T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward -- '%%' } }",
|
||||||
"bind -Tcopy-mode-vi V { send -X select-line }",
|
"bind -Tcopy-mode-vi V { send -X select-line }",
|
||||||
"bind -Tcopy-mode-vi W { send -X next-space }",
|
"bind -Tcopy-mode-vi W { send -X next-space }",
|
||||||
"bind -Tcopy-mode-vi X { send -X set-mark }",
|
"bind -Tcopy-mode-vi X { send -X set-mark }",
|
||||||
"bind -Tcopy-mode-vi ^ { send -X back-to-indentation }",
|
"bind -Tcopy-mode-vi ^ { send -X back-to-indentation }",
|
||||||
"bind -Tcopy-mode-vi b { send -X previous-word }",
|
"bind -Tcopy-mode-vi b { send -X previous-word }",
|
||||||
"bind -Tcopy-mode-vi e { send -X next-word-end }",
|
"bind -Tcopy-mode-vi e { send -X next-word-end }",
|
||||||
"bind -Tcopy-mode-vi f { command-prompt -1p'(jump forward)' { send -X jump-forward '%%' } }",
|
"bind -Tcopy-mode-vi f { command-prompt -1p'(jump forward)' { send -X jump-forward -- '%%' } }",
|
||||||
"bind -Tcopy-mode-vi g { send -X history-top }",
|
"bind -Tcopy-mode-vi g { send -X history-top }",
|
||||||
"bind -Tcopy-mode-vi h { send -X cursor-left }",
|
"bind -Tcopy-mode-vi h { send -X cursor-left }",
|
||||||
"bind -Tcopy-mode-vi j { send -X cursor-down }",
|
"bind -Tcopy-mode-vi j { send -X cursor-down }",
|
||||||
@ -615,7 +622,7 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode-vi o { send -X other-end }",
|
"bind -Tcopy-mode-vi o { send -X other-end }",
|
||||||
"bind -Tcopy-mode-vi q { send -X cancel }",
|
"bind -Tcopy-mode-vi q { send -X cancel }",
|
||||||
"bind -Tcopy-mode-vi r { send -X refresh-from-pane }",
|
"bind -Tcopy-mode-vi r { send -X refresh-from-pane }",
|
||||||
"bind -Tcopy-mode-vi t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward '%%' } }",
|
"bind -Tcopy-mode-vi t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }",
|
||||||
"bind -Tcopy-mode-vi v { send -X rectangle-toggle }",
|
"bind -Tcopy-mode-vi v { send -X rectangle-toggle }",
|
||||||
"bind -Tcopy-mode-vi w { send -X next-word }",
|
"bind -Tcopy-mode-vi w { send -X next-word }",
|
||||||
"bind -Tcopy-mode-vi '{' { send -X previous-paragraph }",
|
"bind -Tcopy-mode-vi '{' { send -X previous-paragraph }",
|
||||||
|
110
layout.c
110
layout.c
@ -275,7 +275,8 @@ layout_cell_is_bottom(struct window *w, struct layout_cell *lc)
|
|||||||
* the case for the most upper or lower panes only.
|
* the case for the most upper or lower panes only.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
layout_add_border(struct window *w, struct layout_cell *lc, int status)
|
layout_add_horizontal_border(struct window *w, struct layout_cell *lc,
|
||||||
|
int status)
|
||||||
{
|
{
|
||||||
if (status == PANE_STATUS_TOP)
|
if (status == PANE_STATUS_TOP)
|
||||||
return (layout_cell_is_top(w, lc));
|
return (layout_cell_is_top(w, lc));
|
||||||
@ -290,22 +291,53 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
|
|||||||
{
|
{
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
struct layout_cell *lc;
|
struct layout_cell *lc;
|
||||||
int status;
|
int status, scrollbars, sb_pos, sb_w, sb_pad;
|
||||||
|
u_int sx, sy;
|
||||||
|
|
||||||
status = options_get_number(w->options, "pane-border-status");
|
status = options_get_number(w->options, "pane-border-status");
|
||||||
|
scrollbars = options_get_number(w->options, "pane-scrollbars");
|
||||||
|
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
|
||||||
|
|
||||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||||
if ((lc = wp->layout_cell) == NULL || wp == skip)
|
if ((lc = wp->layout_cell) == NULL || wp == skip)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
wp->xoff = lc->xoff;
|
wp->xoff = lc->xoff;
|
||||||
wp->yoff = lc->yoff;
|
wp->yoff = lc->yoff;
|
||||||
|
sx = lc->sx;
|
||||||
|
sy = lc->sy;
|
||||||
|
|
||||||
if (layout_add_border(w, lc, status)) {
|
if (layout_add_horizontal_border(w, lc, status)) {
|
||||||
if (status == PANE_STATUS_TOP)
|
if (status == PANE_STATUS_TOP)
|
||||||
wp->yoff++;
|
wp->yoff++;
|
||||||
window_pane_resize(wp, lc->sx, lc->sy - 1);
|
sy--;
|
||||||
} else
|
}
|
||||||
window_pane_resize(wp, lc->sx, lc->sy);
|
|
||||||
|
if (window_pane_show_scrollbar(wp, scrollbars)) {
|
||||||
|
sb_w = wp->scrollbar_style.width;
|
||||||
|
sb_pad = wp->scrollbar_style.pad;
|
||||||
|
if (sb_w < 1)
|
||||||
|
sb_w = 1;
|
||||||
|
if (sb_pad < 0)
|
||||||
|
sb_pad = 0;
|
||||||
|
if (sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||||
|
if ((int)sx - sb_w < PANE_MINIMUM) {
|
||||||
|
wp->xoff = wp->xoff +
|
||||||
|
(int)sx - PANE_MINIMUM;
|
||||||
|
sx = PANE_MINIMUM;
|
||||||
|
} else {
|
||||||
|
sx = sx - sb_w - sb_pad;
|
||||||
|
wp->xoff = wp->xoff + sb_w + sb_pad;
|
||||||
|
}
|
||||||
|
} else /* sb_pos == PANE_SCROLLBARS_RIGHT */
|
||||||
|
if ((int)sx - sb_w - sb_pad < PANE_MINIMUM)
|
||||||
|
sx = PANE_MINIMUM;
|
||||||
|
else
|
||||||
|
sx = sx - sb_w - sb_pad;
|
||||||
|
wp->flags |= PANE_REDRAWSCROLLBAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
window_pane_resize(wp, sx, sy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,18 +368,25 @@ layout_resize_check(struct window *w, struct layout_cell *lc,
|
|||||||
enum layout_type type)
|
enum layout_type type)
|
||||||
{
|
{
|
||||||
struct layout_cell *lcchild;
|
struct layout_cell *lcchild;
|
||||||
|
struct style *sb_style = &w->active->scrollbar_style;
|
||||||
u_int available, minimum;
|
u_int available, minimum;
|
||||||
int status;
|
int status, scrollbars;
|
||||||
|
|
||||||
status = options_get_number(w->options, "pane-border-status");
|
status = options_get_number(w->options, "pane-border-status");
|
||||||
|
scrollbars = options_get_number(w->options, "pane-scrollbars");
|
||||||
|
|
||||||
if (lc->type == LAYOUT_WINDOWPANE) {
|
if (lc->type == LAYOUT_WINDOWPANE) {
|
||||||
/* Space available in this cell only. */
|
/* Space available in this cell only. */
|
||||||
if (type == LAYOUT_LEFTRIGHT) {
|
if (type == LAYOUT_LEFTRIGHT) {
|
||||||
available = lc->sx;
|
available = lc->sx;
|
||||||
minimum = PANE_MINIMUM;
|
if (scrollbars)
|
||||||
|
minimum = PANE_MINIMUM + sb_style->width +
|
||||||
|
sb_style->pad;
|
||||||
|
else
|
||||||
|
minimum = PANE_MINIMUM;
|
||||||
} else {
|
} else {
|
||||||
available = lc->sy;
|
available = lc->sy;
|
||||||
if (layout_add_border(w, lc, status))
|
if (layout_add_horizontal_border(w, lc, status))
|
||||||
minimum = PANE_MINIMUM + 1;
|
minimum = PANE_MINIMUM + 1;
|
||||||
else
|
else
|
||||||
minimum = PANE_MINIMUM;
|
minimum = PANE_MINIMUM;
|
||||||
@ -869,10 +908,12 @@ struct layout_cell *
|
|||||||
layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
|
struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
|
||||||
u_int sx, sy, xoff, yoff, size1, size2, minimum;
|
struct style *sb_style = &wp->scrollbar_style;
|
||||||
u_int new_size, saved_size, resize_first = 0;
|
u_int sx, sy, xoff, yoff, size1, size2, minimum;
|
||||||
int full_size = (flags & SPAWN_FULLSIZE), status;
|
u_int new_size, saved_size, resize_first = 0;
|
||||||
|
int full_size = (flags & SPAWN_FULLSIZE), status;
|
||||||
|
int scrollbars;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If full_size is specified, add a new cell at the top of the window
|
* If full_size is specified, add a new cell at the top of the window
|
||||||
@ -883,6 +924,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
|||||||
else
|
else
|
||||||
lc = wp->layout_cell;
|
lc = wp->layout_cell;
|
||||||
status = options_get_number(wp->window->options, "pane-border-status");
|
status = options_get_number(wp->window->options, "pane-border-status");
|
||||||
|
scrollbars = options_get_number(wp->window->options, "pane-scrollbars");
|
||||||
|
|
||||||
/* Copy the old cell size. */
|
/* Copy the old cell size. */
|
||||||
sx = lc->sx;
|
sx = lc->sx;
|
||||||
@ -893,11 +935,16 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
|||||||
/* Check there is enough space for the two new panes. */
|
/* Check there is enough space for the two new panes. */
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case LAYOUT_LEFTRIGHT:
|
case LAYOUT_LEFTRIGHT:
|
||||||
if (sx < PANE_MINIMUM * 2 + 1)
|
if (scrollbars) {
|
||||||
|
minimum = PANE_MINIMUM * 2 + sb_style->width +
|
||||||
|
sb_style->pad;
|
||||||
|
} else
|
||||||
|
minimum = PANE_MINIMUM * 2 + 1;
|
||||||
|
if (sx < minimum)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
break;
|
break;
|
||||||
case LAYOUT_TOPBOTTOM:
|
case LAYOUT_TOPBOTTOM:
|
||||||
if (layout_add_border(wp->window, lc, status))
|
if (layout_add_horizontal_border(wp->window, lc, status))
|
||||||
minimum = PANE_MINIMUM * 2 + 2;
|
minimum = PANE_MINIMUM * 2 + 2;
|
||||||
else
|
else
|
||||||
minimum = PANE_MINIMUM * 2 + 1;
|
minimum = PANE_MINIMUM * 2 + 1;
|
||||||
@ -1053,8 +1100,9 @@ int
|
|||||||
layout_spread_cell(struct window *w, struct layout_cell *parent)
|
layout_spread_cell(struct window *w, struct layout_cell *parent)
|
||||||
{
|
{
|
||||||
struct layout_cell *lc;
|
struct layout_cell *lc;
|
||||||
u_int number, each, size, this;
|
struct style *sb_style = &w->active->scrollbar_style;
|
||||||
int change, changed, status;
|
u_int number, each, size, this, remainder;
|
||||||
|
int change, changed, status, scrollbars;
|
||||||
|
|
||||||
number = 0;
|
number = 0;
|
||||||
TAILQ_FOREACH (lc, &parent->cells, entry)
|
TAILQ_FOREACH (lc, &parent->cells, entry)
|
||||||
@ -1062,11 +1110,16 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
|
|||||||
if (number <= 1)
|
if (number <= 1)
|
||||||
return (0);
|
return (0);
|
||||||
status = options_get_number(w->options, "pane-border-status");
|
status = options_get_number(w->options, "pane-border-status");
|
||||||
|
scrollbars = options_get_number(w->options, "pane-scrollbars");
|
||||||
|
|
||||||
if (parent->type == LAYOUT_LEFTRIGHT)
|
if (parent->type == LAYOUT_LEFTRIGHT) {
|
||||||
size = parent->sx;
|
if (scrollbars)
|
||||||
|
size = parent->sx - sb_style->width + sb_style->pad;
|
||||||
|
else
|
||||||
|
size = parent->sx;
|
||||||
|
}
|
||||||
else if (parent->type == LAYOUT_TOPBOTTOM) {
|
else if (parent->type == LAYOUT_TOPBOTTOM) {
|
||||||
if (layout_add_border(w, parent, status))
|
if (layout_add_horizontal_border(w, parent, status))
|
||||||
size = parent->sy - 1;
|
size = parent->sy - 1;
|
||||||
else
|
else
|
||||||
size = parent->sy;
|
size = parent->sy;
|
||||||
@ -1077,20 +1130,31 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
|
|||||||
each = (size - (number - 1)) / number;
|
each = (size - (number - 1)) / number;
|
||||||
if (each == 0)
|
if (each == 0)
|
||||||
return (0);
|
return (0);
|
||||||
|
/*
|
||||||
|
* Remaining space after assigning that which can be evenly
|
||||||
|
* distributed.
|
||||||
|
*/
|
||||||
|
remainder = size - (number * (each + 1)) + 1;
|
||||||
|
|
||||||
changed = 0;
|
changed = 0;
|
||||||
TAILQ_FOREACH (lc, &parent->cells, entry) {
|
TAILQ_FOREACH (lc, &parent->cells, entry) {
|
||||||
if (TAILQ_NEXT(lc, entry) == NULL)
|
|
||||||
each = size - ((each + 1) * (number - 1));
|
|
||||||
change = 0;
|
change = 0;
|
||||||
if (parent->type == LAYOUT_LEFTRIGHT) {
|
if (parent->type == LAYOUT_LEFTRIGHT) {
|
||||||
change = each - (int)lc->sx;
|
change = each - (int)lc->sx;
|
||||||
|
if (remainder > 0) {
|
||||||
|
change++;
|
||||||
|
remainder--;
|
||||||
|
}
|
||||||
layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, change);
|
layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, change);
|
||||||
} else if (parent->type == LAYOUT_TOPBOTTOM) {
|
} else if (parent->type == LAYOUT_TOPBOTTOM) {
|
||||||
if (layout_add_border(w, lc, status))
|
if (layout_add_horizontal_border(w, lc, status))
|
||||||
this = each + 1;
|
this = each + 1;
|
||||||
else
|
else
|
||||||
this = each;
|
this = each;
|
||||||
|
if (remainder > 0) {
|
||||||
|
this++;
|
||||||
|
remainder--;
|
||||||
|
}
|
||||||
change = this - (int)lc->sy;
|
change = this - (int)lc->sy;
|
||||||
layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, change);
|
layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, change);
|
||||||
}
|
}
|
||||||
|
1
menu.c
1
menu.c
@ -453,7 +453,6 @@ menu_set_style(struct client *c, struct grid_cell *gc, const char *style,
|
|||||||
gc->bg = sytmp.gc.bg;
|
gc->bg = sytmp.gc.bg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gc->attr = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct menu_data *
|
struct menu_data *
|
||||||
|
148
mode-tree.c
148
mode-tree.c
@ -30,6 +30,12 @@ enum mode_tree_search_dir {
|
|||||||
MODE_TREE_SEARCH_BACKWARD
|
MODE_TREE_SEARCH_BACKWARD
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum mode_tree_preview {
|
||||||
|
MODE_TREE_PREVIEW_OFF,
|
||||||
|
MODE_TREE_PREVIEW_NORMAL,
|
||||||
|
MODE_TREE_PREVIEW_BIG
|
||||||
|
};
|
||||||
|
|
||||||
struct mode_tree_item;
|
struct mode_tree_item;
|
||||||
TAILQ_HEAD(mode_tree_list, mode_tree_item);
|
TAILQ_HEAD(mode_tree_list, mode_tree_item);
|
||||||
|
|
||||||
@ -52,6 +58,7 @@ struct mode_tree_data {
|
|||||||
mode_tree_menu_cb menucb;
|
mode_tree_menu_cb menucb;
|
||||||
mode_tree_height_cb heightcb;
|
mode_tree_height_cb heightcb;
|
||||||
mode_tree_key_cb keycb;
|
mode_tree_key_cb keycb;
|
||||||
|
mode_tree_swap_cb swapcb;
|
||||||
|
|
||||||
struct mode_tree_list children;
|
struct mode_tree_list children;
|
||||||
struct mode_tree_list saved;
|
struct mode_tree_list saved;
|
||||||
@ -60,6 +67,7 @@ struct mode_tree_data {
|
|||||||
u_int line_size;
|
u_int line_size;
|
||||||
|
|
||||||
u_int depth;
|
u_int depth;
|
||||||
|
u_int maxdepth;
|
||||||
|
|
||||||
u_int width;
|
u_int width;
|
||||||
u_int height;
|
u_int height;
|
||||||
@ -94,6 +102,7 @@ struct mode_tree_item {
|
|||||||
|
|
||||||
int draw_as_parent;
|
int draw_as_parent;
|
||||||
int no_tag;
|
int no_tag;
|
||||||
|
int align;
|
||||||
|
|
||||||
struct mode_tree_list children;
|
struct mode_tree_list children;
|
||||||
TAILQ_ENTRY(mode_tree_item) entry;
|
TAILQ_ENTRY(mode_tree_item) entry;
|
||||||
@ -190,6 +199,8 @@ mode_tree_build_lines(struct mode_tree_data *mtd,
|
|||||||
int flat = 1;
|
int flat = 1;
|
||||||
|
|
||||||
mtd->depth = depth;
|
mtd->depth = depth;
|
||||||
|
if (depth > mtd->maxdepth)
|
||||||
|
mtd->maxdepth = depth;
|
||||||
TAILQ_FOREACH(mti, mtl, entry) {
|
TAILQ_FOREACH(mti, mtl, entry) {
|
||||||
mtd->line_list = xreallocarray(mtd->line_list,
|
mtd->line_list = xreallocarray(mtd->line_list,
|
||||||
mtd->line_size + 1, sizeof *mtd->line_list);
|
mtd->line_size + 1, sizeof *mtd->line_list);
|
||||||
@ -278,6 +289,35 @@ mode_tree_down(struct mode_tree_data *mtd, int wrap)
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mode_tree_swap(struct mode_tree_data *mtd, int direction)
|
||||||
|
{
|
||||||
|
u_int current_depth = mtd->line_list[mtd->current].depth;
|
||||||
|
u_int swap_with, swap_with_depth;
|
||||||
|
|
||||||
|
if (mtd->swapcb == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Find the next line at the same depth with the same parent . */
|
||||||
|
swap_with = mtd->current;
|
||||||
|
do {
|
||||||
|
if (direction < 0 && swap_with < (u_int)-direction)
|
||||||
|
return;
|
||||||
|
if (direction > 0 && swap_with + direction >= mtd->line_size)
|
||||||
|
return;
|
||||||
|
swap_with += direction;
|
||||||
|
swap_with_depth = mtd->line_list[swap_with].depth;
|
||||||
|
} while (swap_with_depth > current_depth);
|
||||||
|
if (swap_with_depth != current_depth)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mtd->swapcb(mtd->line_list[mtd->current].item->itemdata,
|
||||||
|
mtd->line_list[swap_with].item->itemdata)) {
|
||||||
|
mtd->current = swap_with;
|
||||||
|
mode_tree_build(mtd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
mode_tree_get_current(struct mode_tree_data *mtd)
|
mode_tree_get_current(struct mode_tree_data *mtd)
|
||||||
{
|
{
|
||||||
@ -350,8 +390,13 @@ mode_tree_set_current(struct mode_tree_data *mtd, uint64_t tag)
|
|||||||
mtd->offset = 0;
|
mtd->offset = 0;
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
mtd->current = 0;
|
if (mtd->current >= mtd->line_size) {
|
||||||
mtd->offset = 0;
|
mtd->current = mtd->line_size - 1;
|
||||||
|
if (mtd->current > mtd->height - 1)
|
||||||
|
mtd->offset = mtd->current - mtd->height + 1;
|
||||||
|
else
|
||||||
|
mtd->offset = 0;
|
||||||
|
}
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,9 +441,9 @@ struct mode_tree_data *
|
|||||||
mode_tree_start(struct window_pane *wp, struct args *args,
|
mode_tree_start(struct window_pane *wp, struct args *args,
|
||||||
mode_tree_build_cb buildcb, mode_tree_draw_cb drawcb,
|
mode_tree_build_cb buildcb, mode_tree_draw_cb drawcb,
|
||||||
mode_tree_search_cb searchcb, mode_tree_menu_cb menucb,
|
mode_tree_search_cb searchcb, mode_tree_menu_cb menucb,
|
||||||
mode_tree_height_cb heightcb, mode_tree_key_cb keycb, void *modedata,
|
mode_tree_height_cb heightcb, mode_tree_key_cb keycb,
|
||||||
const struct menu_item *menu, const char **sort_list, u_int sort_size,
|
mode_tree_swap_cb swapcb, void *modedata, const struct menu_item *menu,
|
||||||
struct screen **s)
|
const char **sort_list, u_int sort_size, struct screen **s)
|
||||||
{
|
{
|
||||||
struct mode_tree_data *mtd;
|
struct mode_tree_data *mtd;
|
||||||
const char *sort;
|
const char *sort;
|
||||||
@ -414,7 +459,12 @@ mode_tree_start(struct window_pane *wp, struct args *args,
|
|||||||
mtd->sort_list = sort_list;
|
mtd->sort_list = sort_list;
|
||||||
mtd->sort_size = sort_size;
|
mtd->sort_size = sort_size;
|
||||||
|
|
||||||
mtd->preview = !args_has(args, 'N');
|
if (args_has(args, 'N') > 1)
|
||||||
|
mtd->preview = MODE_TREE_PREVIEW_BIG;
|
||||||
|
else if (args_has(args, 'N'))
|
||||||
|
mtd->preview = MODE_TREE_PREVIEW_OFF;
|
||||||
|
else
|
||||||
|
mtd->preview = MODE_TREE_PREVIEW_NORMAL;
|
||||||
|
|
||||||
sort = args_get(args, 'O');
|
sort = args_get(args, 'O');
|
||||||
if (sort != NULL) {
|
if (sort != NULL) {
|
||||||
@ -436,6 +486,7 @@ mode_tree_start(struct window_pane *wp, struct args *args,
|
|||||||
mtd->menucb = menucb;
|
mtd->menucb = menucb;
|
||||||
mtd->heightcb = heightcb;
|
mtd->heightcb = heightcb;
|
||||||
mtd->keycb = keycb;
|
mtd->keycb = keycb;
|
||||||
|
mtd->swapcb = swapcb;
|
||||||
|
|
||||||
TAILQ_INIT(&mtd->children);
|
TAILQ_INIT(&mtd->children);
|
||||||
|
|
||||||
@ -470,12 +521,21 @@ mode_tree_set_height(struct mode_tree_data *mtd)
|
|||||||
if (height < screen_size_y(s))
|
if (height < screen_size_y(s))
|
||||||
mtd->height = screen_size_y(s) - height;
|
mtd->height = screen_size_y(s) - height;
|
||||||
} else {
|
} else {
|
||||||
mtd->height = (screen_size_y(s) / 3) * 2;
|
if (mtd->preview == MODE_TREE_PREVIEW_NORMAL) {
|
||||||
if (mtd->height > mtd->line_size)
|
mtd->height = (screen_size_y(s) / 3) * 2;
|
||||||
mtd->height = screen_size_y(s) / 2;
|
if (mtd->height > mtd->line_size)
|
||||||
|
mtd->height = screen_size_y(s) / 2;
|
||||||
|
if (mtd->height < 10)
|
||||||
|
mtd->height = screen_size_y(s);
|
||||||
|
} else if (mtd->preview == MODE_TREE_PREVIEW_BIG) {
|
||||||
|
mtd->height = screen_size_y(s) / 4;
|
||||||
|
if (mtd->height > mtd->line_size)
|
||||||
|
mtd->height = mtd->line_size;
|
||||||
|
if (mtd->height < 2)
|
||||||
|
mtd->height = 2;
|
||||||
|
} else
|
||||||
|
mtd->height = screen_size_y(s);
|
||||||
}
|
}
|
||||||
if (mtd->height < 10)
|
|
||||||
mtd->height = screen_size_y(s);
|
|
||||||
if (screen_size_y(s) - mtd->height < 2)
|
if (screen_size_y(s) - mtd->height < 2)
|
||||||
mtd->height = screen_size_y(s);
|
mtd->height = screen_size_y(s);
|
||||||
}
|
}
|
||||||
@ -503,6 +563,7 @@ mode_tree_build(struct mode_tree_data *mtd)
|
|||||||
TAILQ_INIT(&mtd->saved);
|
TAILQ_INIT(&mtd->saved);
|
||||||
|
|
||||||
mode_tree_clear_lines(mtd);
|
mode_tree_clear_lines(mtd);
|
||||||
|
mtd->maxdepth = 0;
|
||||||
mode_tree_build_lines(mtd, &mtd->children, 0);
|
mode_tree_build_lines(mtd, &mtd->children, 0);
|
||||||
|
|
||||||
if (mtd->line_list != NULL && tag == UINT64_MAX)
|
if (mtd->line_list != NULL && tag == UINT64_MAX)
|
||||||
@ -510,7 +571,7 @@ mode_tree_build(struct mode_tree_data *mtd)
|
|||||||
mode_tree_set_current(mtd, tag);
|
mode_tree_set_current(mtd, tag);
|
||||||
|
|
||||||
mtd->width = screen_size_x(s);
|
mtd->width = screen_size_x(s);
|
||||||
if (mtd->preview)
|
if (mtd->preview != MODE_TREE_PREVIEW_OFF)
|
||||||
mode_tree_set_height(mtd);
|
mode_tree_set_height(mtd);
|
||||||
else
|
else
|
||||||
mtd->height = screen_size_y(s);
|
mtd->height = screen_size_y(s);
|
||||||
@ -607,6 +668,16 @@ mode_tree_no_tag(struct mode_tree_item *mti)
|
|||||||
mti->no_tag = 1;
|
mti->no_tag = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the alignment of mti->name: -1 to align left, 0 (default) to not align,
|
||||||
|
* or 1 to align right.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
mode_tree_align(struct mode_tree_item *mti, int align)
|
||||||
|
{
|
||||||
|
mti->align = align;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mode_tree_remove(struct mode_tree_data *mtd, struct mode_tree_item *mti)
|
mode_tree_remove(struct mode_tree_data *mtd, struct mode_tree_item *mti)
|
||||||
{
|
{
|
||||||
@ -633,7 +704,7 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
|||||||
char *text, *start, *key;
|
char *text, *start, *key;
|
||||||
const char *tag, *symbol;
|
const char *tag, *symbol;
|
||||||
size_t size, n;
|
size_t size, n;
|
||||||
int keylen, pad;
|
int keylen, pad, alignlen[mtd->maxdepth + 1];
|
||||||
|
|
||||||
if (mtd->line_size == 0)
|
if (mtd->line_size == 0)
|
||||||
return;
|
return;
|
||||||
@ -657,6 +728,16 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
|||||||
keylen = mti->keylen + 3;
|
keylen = mti->keylen + 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < mtd->maxdepth + 1; i++)
|
||||||
|
alignlen[i] = 0;
|
||||||
|
for (i = 0; i < mtd->line_size; i++) {
|
||||||
|
line = &mtd->line_list[i];
|
||||||
|
mti = line->item;
|
||||||
|
if (mti->align &&
|
||||||
|
(int)strlen(mti->name) > alignlen[line->depth])
|
||||||
|
alignlen[line->depth] = strlen(mti->name);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < mtd->line_size; i++) {
|
for (i = 0; i < mtd->line_size; i++) {
|
||||||
if (i < mtd->offset)
|
if (i < mtd->offset)
|
||||||
continue;
|
continue;
|
||||||
@ -706,8 +787,9 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
|||||||
tag = "*";
|
tag = "*";
|
||||||
else
|
else
|
||||||
tag = "";
|
tag = "";
|
||||||
xasprintf(&text, "%-*s%s%s%s%s", keylen, key, start, mti->name,
|
xasprintf(&text, "%-*s%s%*s%s%s", keylen, key, start,
|
||||||
tag, (mti->text != NULL) ? ": " : "" );
|
mti->align * alignlen[line->depth], mti->name, tag,
|
||||||
|
(mti->text != NULL) ? ": " : "" );
|
||||||
width = utf8_cstrwidth(text);
|
width = utf8_cstrwidth(text);
|
||||||
if (width > w)
|
if (width > w)
|
||||||
width = w;
|
width = w;
|
||||||
@ -742,8 +824,11 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mtd->preview == MODE_TREE_PREVIEW_OFF)
|
||||||
|
goto done;
|
||||||
|
|
||||||
sy = screen_size_y(s);
|
sy = screen_size_y(s);
|
||||||
if (!mtd->preview || sy <= 4 || h <= 4 || sy - h <= 4 || w <= 4)
|
if (sy <= 4 || h < 2 || sy - h <= 4 || w <= 4)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
line = &mtd->line_list[mtd->current];
|
line = &mtd->line_list[mtd->current];
|
||||||
@ -1016,8 +1101,11 @@ mode_tree_display_menu(struct mode_tree_data *mtd, struct client *c, u_int x,
|
|||||||
else
|
else
|
||||||
x = 0;
|
x = 0;
|
||||||
if (menu_display(menu, 0, 0, NULL, x, y, c, BOX_LINES_DEFAULT, NULL,
|
if (menu_display(menu, 0, 0, NULL, x, y, c, BOX_LINES_DEFAULT, NULL,
|
||||||
NULL, NULL, NULL, mode_tree_menu_callback, mtm) != 0)
|
NULL, NULL, NULL, mode_tree_menu_callback, mtm) != 0) {
|
||||||
|
mode_tree_remove_ref(mtd);
|
||||||
|
free(mtm);
|
||||||
menu_free(menu);
|
menu_free(menu);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -1041,7 +1129,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
|||||||
if (x > mtd->width || y > mtd->height) {
|
if (x > mtd->width || y > mtd->height) {
|
||||||
if (*key == KEYC_MOUSEDOWN3_PANE)
|
if (*key == KEYC_MOUSEDOWN3_PANE)
|
||||||
mode_tree_display_menu(mtd, c, x, y, 1);
|
mode_tree_display_menu(mtd, c, x, y, 1);
|
||||||
if (!mtd->preview)
|
if (mtd->preview == MODE_TREE_PREVIEW_OFF)
|
||||||
*key = KEYC_NONE;
|
*key = KEYC_NONE;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -1102,6 +1190,14 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
|||||||
case 'n'|KEYC_CTRL:
|
case 'n'|KEYC_CTRL:
|
||||||
mode_tree_down(mtd, 1);
|
mode_tree_down(mtd, 1);
|
||||||
break;
|
break;
|
||||||
|
case KEYC_UP|KEYC_SHIFT:
|
||||||
|
case 'K':
|
||||||
|
mode_tree_swap(mtd, -1);
|
||||||
|
break;
|
||||||
|
case KEYC_DOWN|KEYC_SHIFT:
|
||||||
|
case 'J':
|
||||||
|
mode_tree_swap(mtd, 1);
|
||||||
|
break;
|
||||||
case KEYC_PPAGE:
|
case KEYC_PPAGE:
|
||||||
case 'b'|KEYC_CTRL:
|
case 'b'|KEYC_CTRL:
|
||||||
for (i = 0; i < mtd->height; i++) {
|
for (i = 0; i < mtd->height; i++) {
|
||||||
@ -1232,9 +1328,19 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
|||||||
PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);
|
PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
mtd->preview = !mtd->preview;
|
switch (mtd->preview) {
|
||||||
|
case MODE_TREE_PREVIEW_OFF:
|
||||||
|
mtd->preview = MODE_TREE_PREVIEW_BIG;
|
||||||
|
break;
|
||||||
|
case MODE_TREE_PREVIEW_NORMAL:
|
||||||
|
mtd->preview = MODE_TREE_PREVIEW_OFF;
|
||||||
|
break;
|
||||||
|
case MODE_TREE_PREVIEW_BIG:
|
||||||
|
mtd->preview = MODE_TREE_PREVIEW_NORMAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
mode_tree_build(mtd);
|
mode_tree_build(mtd);
|
||||||
if (mtd->preview)
|
if (mtd->preview != MODE_TREE_PREVIEW_OFF)
|
||||||
mode_tree_check_selected(mtd);
|
mode_tree_check_selected(mtd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1256,7 +1362,7 @@ mode_tree_run_command(struct client *c, struct cmd_find_state *fs,
|
|||||||
if (status == CMD_PARSE_ERROR) {
|
if (status == CMD_PARSE_ERROR) {
|
||||||
if (c != NULL) {
|
if (c != NULL) {
|
||||||
*error = toupper((u_char)*error);
|
*error = toupper((u_char)*error);
|
||||||
status_message_set(c, -1, 1, 0, "%s", error);
|
status_message_set(c, -1, 1, 0, 0, "%s", error);
|
||||||
}
|
}
|
||||||
free(error);
|
free(error);
|
||||||
}
|
}
|
||||||
|
142
options-table.c
142
options-table.c
@ -63,6 +63,12 @@ static const char *options_table_cursor_style_list[] = {
|
|||||||
"default", "blinking-block", "block", "blinking-underline", "underline",
|
"default", "blinking-block", "block", "blinking-underline", "underline",
|
||||||
"blinking-bar", "bar", NULL
|
"blinking-bar", "bar", NULL
|
||||||
};
|
};
|
||||||
|
static const char *options_table_pane_scrollbars_list[] = {
|
||||||
|
"off", "modal", "on", NULL
|
||||||
|
};
|
||||||
|
static const char *options_table_pane_scrollbars_position_list[] = {
|
||||||
|
"right", "left", NULL
|
||||||
|
};
|
||||||
static const char *options_table_pane_status_list[] = {
|
static const char *options_table_pane_status_list[] = {
|
||||||
"off", "top", "bottom", NULL
|
"off", "top", "bottom", NULL
|
||||||
};
|
};
|
||||||
@ -207,6 +213,7 @@ const struct options_name_map options_other_names[] = {
|
|||||||
{ "display-panes-active-color", "display-panes-active-colour" },
|
{ "display-panes-active-color", "display-panes-active-colour" },
|
||||||
{ "clock-mode-color", "clock-mode-colour" },
|
{ "clock-mode-color", "clock-mode-colour" },
|
||||||
{ "cursor-color", "cursor-colour" },
|
{ "cursor-color", "cursor-colour" },
|
||||||
|
{ "prompt-cursor-color", "prompt-cursor-colour" },
|
||||||
{ "pane-colors", "pane-colours" },
|
{ "pane-colors", "pane-colours" },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
@ -246,6 +253,15 @@ const struct options_table_entry options_table[] = {
|
|||||||
"Each entry is an alias and a command separated by '='."
|
"Each entry is an alias and a command separated by '='."
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{ .name = "codepoint-widths",
|
||||||
|
.type = OPTIONS_TABLE_STRING,
|
||||||
|
.scope = OPTIONS_TABLE_SERVER,
|
||||||
|
.flags = OPTIONS_TABLE_IS_ARRAY,
|
||||||
|
.default_str = "",
|
||||||
|
.separator = ",",
|
||||||
|
.text = "Array of override widths for Unicode codepoints."
|
||||||
|
},
|
||||||
|
|
||||||
{ .name = "copy-command",
|
{ .name = "copy-command",
|
||||||
.type = OPTIONS_TABLE_STRING,
|
.type = OPTIONS_TABLE_STRING,
|
||||||
.scope = OPTIONS_TABLE_SERVER,
|
.scope = OPTIONS_TABLE_SERVER,
|
||||||
@ -269,6 +285,13 @@ const struct options_table_entry options_table[] = {
|
|||||||
.text = "Style of the cursor."
|
.text = "Style of the cursor."
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{ .name = "default-client-command",
|
||||||
|
.type = OPTIONS_TABLE_COMMAND,
|
||||||
|
.scope = OPTIONS_TABLE_SERVER,
|
||||||
|
.default_str = "new-session",
|
||||||
|
.text = "Default command to run when tmux is run without a command."
|
||||||
|
},
|
||||||
|
|
||||||
{ .name = "default-terminal",
|
{ .name = "default-terminal",
|
||||||
.type = OPTIONS_TABLE_STRING,
|
.type = OPTIONS_TABLE_STRING,
|
||||||
.scope = OPTIONS_TABLE_SERVER,
|
.scope = OPTIONS_TABLE_SERVER,
|
||||||
@ -340,6 +363,15 @@ const struct options_table_entry options_table[] = {
|
|||||||
"Empty does not write a history file."
|
"Empty does not write a history file."
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{ .name = "input-buffer-size",
|
||||||
|
.type = OPTIONS_TABLE_NUMBER,
|
||||||
|
.scope = OPTIONS_TABLE_SERVER,
|
||||||
|
.minimum = INPUT_BUF_DEFAULT_SIZE,
|
||||||
|
.maximum = UINT_MAX,
|
||||||
|
.default_num = INPUT_BUF_DEFAULT_SIZE,
|
||||||
|
.text = "Number of bytes accepted in a single input before dropping."
|
||||||
|
},
|
||||||
|
|
||||||
{ .name = "menu-style",
|
{ .name = "menu-style",
|
||||||
.type = OPTIONS_TABLE_STRING,
|
.type = OPTIONS_TABLE_STRING,
|
||||||
.scope = OPTIONS_TABLE_WINDOW,
|
.scope = OPTIONS_TABLE_WINDOW,
|
||||||
@ -373,7 +405,7 @@ const struct options_table_entry options_table[] = {
|
|||||||
.choices = options_table_popup_border_lines_list,
|
.choices = options_table_popup_border_lines_list,
|
||||||
.default_num = BOX_LINES_SINGLE,
|
.default_num = BOX_LINES_SINGLE,
|
||||||
.text = "Type of characters used to draw menu border lines. Some of "
|
.text = "Type of characters used to draw menu border lines. Some of "
|
||||||
"these are only supported on terminals with UTF-8 support."
|
"these are only supported on terminals with UTF-8 support."
|
||||||
},
|
},
|
||||||
|
|
||||||
{ .name = "message-limit",
|
{ .name = "message-limit",
|
||||||
@ -393,7 +425,7 @@ const struct options_table_entry options_table[] = {
|
|||||||
.default_num = 0,
|
.default_num = 0,
|
||||||
.unit = "milliseconds",
|
.unit = "milliseconds",
|
||||||
.text = "The timeout for the prefix key if no subsequent key is "
|
.text = "The timeout for the prefix key if no subsequent key is "
|
||||||
"pressed. Zero means disabled."
|
"pressed. Zero means disabled."
|
||||||
},
|
},
|
||||||
|
|
||||||
{ .name = "prompt-history-limit",
|
{ .name = "prompt-history-limit",
|
||||||
@ -430,7 +462,7 @@ const struct options_table_entry options_table[] = {
|
|||||||
.flags = OPTIONS_TABLE_IS_ARRAY,
|
.flags = OPTIONS_TABLE_IS_ARRAY,
|
||||||
.default_str = "xterm*:clipboard:ccolour:cstyle:focus:title,"
|
.default_str = "xterm*:clipboard:ccolour:cstyle:focus:title,"
|
||||||
"screen*:title,"
|
"screen*:title,"
|
||||||
"rxvt*:ignorefkeys",
|
"rxvt*:ignorefkeys",
|
||||||
.separator = ",",
|
.separator = ",",
|
||||||
.text = "List of terminal features, used if they cannot be "
|
.text = "List of terminal features, used if they cannot be "
|
||||||
"automatically detected."
|
"automatically detected."
|
||||||
@ -447,6 +479,14 @@ const struct options_table_entry options_table[] = {
|
|||||||
"'User0', 'User1' and so on."
|
"'User0', 'User1' and so on."
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{ .name = "variation-selector-always-wide",
|
||||||
|
.type = OPTIONS_TABLE_FLAG,
|
||||||
|
.scope = OPTIONS_TABLE_SERVER,
|
||||||
|
.default_num = 1,
|
||||||
|
.text = "If the Unicode VS16 codepoint should always be treated as a "
|
||||||
|
"wide character."
|
||||||
|
},
|
||||||
|
|
||||||
/* Session options. */
|
/* Session options. */
|
||||||
{ .name = "activity-action",
|
{ .name = "activity-action",
|
||||||
.type = OPTIONS_TABLE_CHOICE,
|
.type = OPTIONS_TABLE_CHOICE,
|
||||||
@ -571,6 +611,18 @@ const struct options_table_entry options_table[] = {
|
|||||||
"If changed, the new value applies only to new panes."
|
"If changed, the new value applies only to new panes."
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{ .name = "initial-repeat-time",
|
||||||
|
.type = OPTIONS_TABLE_NUMBER,
|
||||||
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
|
.minimum = 0,
|
||||||
|
.maximum = 2000000,
|
||||||
|
.default_num = 0,
|
||||||
|
.unit = "milliseconds",
|
||||||
|
.text = "Time to wait for a key binding to repeat the first time the "
|
||||||
|
"key is pressed, if it is bound with the '-r' flag. "
|
||||||
|
"Subsequent presses use the 'repeat-time' option."
|
||||||
|
},
|
||||||
|
|
||||||
{ .name = "key-table",
|
{ .name = "key-table",
|
||||||
.type = OPTIONS_TABLE_STRING,
|
.type = OPTIONS_TABLE_STRING,
|
||||||
.scope = OPTIONS_TABLE_SESSION,
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
@ -658,7 +710,7 @@ const struct options_table_entry options_table[] = {
|
|||||||
.type = OPTIONS_TABLE_NUMBER,
|
.type = OPTIONS_TABLE_NUMBER,
|
||||||
.scope = OPTIONS_TABLE_SESSION,
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
.minimum = 0,
|
.minimum = 0,
|
||||||
.maximum = SHRT_MAX,
|
.maximum = 2000000,
|
||||||
.default_num = 500,
|
.default_num = 500,
|
||||||
.unit = "milliseconds",
|
.unit = "milliseconds",
|
||||||
.text = "Time to wait for a key binding to repeat, if it is bound "
|
.text = "Time to wait for a key binding to repeat, if it is bound "
|
||||||
@ -819,11 +871,26 @@ const struct options_table_entry options_table[] = {
|
|||||||
.text = "Style of the status line."
|
.text = "Style of the status line."
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{ .name = "prompt-cursor-colour",
|
||||||
|
.type = OPTIONS_TABLE_COLOUR,
|
||||||
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
|
.default_num = 6,
|
||||||
|
.text = "Colour of the cursor when in the command prompt."
|
||||||
|
},
|
||||||
|
|
||||||
|
{ .name = "prompt-cursor-style",
|
||||||
|
.type = OPTIONS_TABLE_CHOICE,
|
||||||
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
|
.choices = options_table_cursor_style_list,
|
||||||
|
.default_num = 0,
|
||||||
|
.text = "Style of the cursor when in the command prompt."
|
||||||
|
},
|
||||||
|
|
||||||
{ .name = "update-environment",
|
{ .name = "update-environment",
|
||||||
.type = OPTIONS_TABLE_STRING,
|
.type = OPTIONS_TABLE_STRING,
|
||||||
.scope = OPTIONS_TABLE_SESSION,
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
.flags = OPTIONS_TABLE_IS_ARRAY,
|
.flags = OPTIONS_TABLE_IS_ARRAY,
|
||||||
.default_str = "DISPLAY KRB5CCNAME SSH_ASKPASS SSH_AUTH_SOCK "
|
.default_str = "DISPLAY KRB5CCNAME MSYSTEM SSH_ASKPASS SSH_AUTH_SOCK "
|
||||||
"SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY",
|
"SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY",
|
||||||
.text = "List of environment variables to update in the session "
|
.text = "List of environment variables to update in the session "
|
||||||
"environment when a client is attached."
|
"environment when a client is attached."
|
||||||
@ -970,6 +1037,36 @@ const struct options_table_entry options_table[] = {
|
|||||||
.text = "Style of the marked line in copy mode."
|
.text = "Style of the marked line in copy mode."
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{ .name = "copy-mode-position-format",
|
||||||
|
.type = OPTIONS_TABLE_STRING,
|
||||||
|
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||||
|
.default_str = "#[align=right]"
|
||||||
|
"#{t/p:top_line_time}#{?#{e|>:#{top_line_time},0}, ,}"
|
||||||
|
"[#{scroll_position}/#{history_size}]"
|
||||||
|
"#{?search_timed_out, (timed out),"
|
||||||
|
"#{?search_count, (#{search_count}"
|
||||||
|
"#{?search_count_partial,+,} results),}}",
|
||||||
|
.text = "Format of the position indicator in copy mode."
|
||||||
|
},
|
||||||
|
|
||||||
|
{ .name = "copy-mode-position-style",
|
||||||
|
.type = OPTIONS_TABLE_STRING,
|
||||||
|
.scope = OPTIONS_TABLE_WINDOW,
|
||||||
|
.default_str = "#{E:mode-style}",
|
||||||
|
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||||
|
.separator = ",",
|
||||||
|
.text = "Style of position indicator in copy mode."
|
||||||
|
},
|
||||||
|
|
||||||
|
{ .name = "copy-mode-selection-style",
|
||||||
|
.type = OPTIONS_TABLE_STRING,
|
||||||
|
.scope = OPTIONS_TABLE_WINDOW,
|
||||||
|
.default_str = "#{E:mode-style}",
|
||||||
|
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||||
|
.separator = ",",
|
||||||
|
.text = "Style of selection in copy mode."
|
||||||
|
},
|
||||||
|
|
||||||
{ .name = "fill-character",
|
{ .name = "fill-character",
|
||||||
.type = OPTIONS_TABLE_STRING,
|
.type = OPTIONS_TABLE_STRING,
|
||||||
.scope = OPTIONS_TABLE_WINDOW,
|
.scope = OPTIONS_TABLE_WINDOW,
|
||||||
@ -1005,7 +1102,7 @@ const struct options_table_entry options_table[] = {
|
|||||||
.type = OPTIONS_TABLE_STRING,
|
.type = OPTIONS_TABLE_STRING,
|
||||||
.scope = OPTIONS_TABLE_WINDOW,
|
.scope = OPTIONS_TABLE_WINDOW,
|
||||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||||
.default_str = "bg=yellow,fg=black",
|
.default_str = "noattr,bg=yellow,fg=black",
|
||||||
.separator = ",",
|
.separator = ",",
|
||||||
.text = "Style of indicators and highlighting in modes."
|
.text = "Style of indicators and highlighting in modes."
|
||||||
},
|
},
|
||||||
@ -1120,6 +1217,31 @@ const struct options_table_entry options_table[] = {
|
|||||||
.text = "The default colour palette for colours zero to 255."
|
.text = "The default colour palette for colours zero to 255."
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{ .name = "pane-scrollbars",
|
||||||
|
.type = OPTIONS_TABLE_CHOICE,
|
||||||
|
.scope = OPTIONS_TABLE_WINDOW,
|
||||||
|
.choices = options_table_pane_scrollbars_list,
|
||||||
|
.default_num = PANE_SCROLLBARS_OFF,
|
||||||
|
.text = "Pane scrollbar state."
|
||||||
|
},
|
||||||
|
|
||||||
|
{ .name = "pane-scrollbars-style",
|
||||||
|
.type = OPTIONS_TABLE_STRING,
|
||||||
|
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||||
|
.default_str = "bg=black,fg=white,width=1,pad=0",
|
||||||
|
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||||
|
.separator = ",",
|
||||||
|
.text = "Style of the pane scrollbar."
|
||||||
|
},
|
||||||
|
|
||||||
|
{ .name = "pane-scrollbars-position",
|
||||||
|
.type = OPTIONS_TABLE_CHOICE,
|
||||||
|
.scope = OPTIONS_TABLE_WINDOW,
|
||||||
|
.choices = options_table_pane_scrollbars_position_list,
|
||||||
|
.default_num = PANE_SCROLLBARS_RIGHT,
|
||||||
|
.text = "Pane scrollbar position."
|
||||||
|
},
|
||||||
|
|
||||||
{ .name = "popup-style",
|
{ .name = "popup-style",
|
||||||
.type = OPTIONS_TABLE_STRING,
|
.type = OPTIONS_TABLE_STRING,
|
||||||
.scope = OPTIONS_TABLE_WINDOW,
|
.scope = OPTIONS_TABLE_WINDOW,
|
||||||
@ -1161,12 +1283,12 @@ const struct options_table_entry options_table[] = {
|
|||||||
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||||
.default_str = "Pane is dead ("
|
.default_str = "Pane is dead ("
|
||||||
"#{?#{!=:#{pane_dead_status},},"
|
"#{?#{!=:#{pane_dead_status},},"
|
||||||
"status #{pane_dead_status},}"
|
"status #{pane_dead_status},}"
|
||||||
"#{?#{!=:#{pane_dead_signal},},"
|
"#{?#{!=:#{pane_dead_signal},},"
|
||||||
"signal #{pane_dead_signal},}, "
|
"signal #{pane_dead_signal},}, "
|
||||||
"#{t:pane_dead_time})",
|
"#{t:pane_dead_time})",
|
||||||
.text = "Message shown after the program in a pane has exited, if "
|
.text = "Message shown after the program in a pane has exited, if "
|
||||||
"remain-on-exit is enabled."
|
"remain-on-exit is enabled."
|
||||||
},
|
},
|
||||||
|
|
||||||
{ .name = "scroll-on-clear",
|
{ .name = "scroll-on-clear",
|
||||||
@ -1347,6 +1469,8 @@ const struct options_table_entry options_table[] = {
|
|||||||
OPTIONS_TABLE_HOOK("client-focus-out", ""),
|
OPTIONS_TABLE_HOOK("client-focus-out", ""),
|
||||||
OPTIONS_TABLE_HOOK("client-resized", ""),
|
OPTIONS_TABLE_HOOK("client-resized", ""),
|
||||||
OPTIONS_TABLE_HOOK("client-session-changed", ""),
|
OPTIONS_TABLE_HOOK("client-session-changed", ""),
|
||||||
|
OPTIONS_TABLE_HOOK("client-light-theme", ""),
|
||||||
|
OPTIONS_TABLE_HOOK("client-dark-theme", ""),
|
||||||
OPTIONS_TABLE_HOOK("command-error", ""),
|
OPTIONS_TABLE_HOOK("command-error", ""),
|
||||||
OPTIONS_TABLE_PANE_HOOK("pane-died", ""),
|
OPTIONS_TABLE_PANE_HOOK("pane-died", ""),
|
||||||
OPTIONS_TABLE_PANE_HOOK("pane-exited", ""),
|
OPTIONS_TABLE_PANE_HOOK("pane-exited", ""),
|
||||||
|
77
options.c
77
options.c
@ -260,6 +260,7 @@ options_default(struct options *oo, const struct options_table_entry *oe)
|
|||||||
struct options_entry *o;
|
struct options_entry *o;
|
||||||
union options_value *ov;
|
union options_value *ov;
|
||||||
u_int i;
|
u_int i;
|
||||||
|
struct cmd_parse_result *pr;
|
||||||
|
|
||||||
o = options_empty(oo, oe);
|
o = options_empty(oo, oe);
|
||||||
ov = &o->value;
|
ov = &o->value;
|
||||||
@ -278,6 +279,17 @@ options_default(struct options *oo, const struct options_table_entry *oe)
|
|||||||
case OPTIONS_TABLE_STRING:
|
case OPTIONS_TABLE_STRING:
|
||||||
ov->string = xstrdup(oe->default_str);
|
ov->string = xstrdup(oe->default_str);
|
||||||
break;
|
break;
|
||||||
|
case OPTIONS_TABLE_COMMAND:
|
||||||
|
pr = cmd_parse_from_string(oe->default_str, NULL);
|
||||||
|
switch (pr->status) {
|
||||||
|
case CMD_PARSE_ERROR:
|
||||||
|
free(pr->error);
|
||||||
|
break;
|
||||||
|
case CMD_PARSE_SUCCESS:
|
||||||
|
ov->cmdlist = pr->cmdlist;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ov->number = oe->default_num;
|
ov->number = oe->default_num;
|
||||||
break;
|
break;
|
||||||
@ -737,6 +749,19 @@ options_get_number(struct options *oo, const char *name)
|
|||||||
return (o->value.number);
|
return (o->value.number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const struct cmd_list *
|
||||||
|
options_get_command(struct options *oo, const char *name)
|
||||||
|
{
|
||||||
|
struct options_entry *o;
|
||||||
|
|
||||||
|
o = options_get(oo, name);
|
||||||
|
if (o == NULL)
|
||||||
|
fatalx("missing option %s", name);
|
||||||
|
if (!OPTIONS_IS_COMMAND(o))
|
||||||
|
fatalx("option %s is not a command", name);
|
||||||
|
return (o->value.cmdlist);
|
||||||
|
}
|
||||||
|
|
||||||
struct options_entry *
|
struct options_entry *
|
||||||
options_set_string(struct options *oo, const char *name, int append,
|
options_set_string(struct options *oo, const char *name, int append,
|
||||||
const char *fmt, ...)
|
const char *fmt, ...)
|
||||||
@ -798,6 +823,30 @@ options_set_number(struct options *oo, const char *name, long long value)
|
|||||||
return (o);
|
return (o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct options_entry *
|
||||||
|
options_set_command(struct options *oo, const char *name,
|
||||||
|
struct cmd_list *value)
|
||||||
|
{
|
||||||
|
struct options_entry *o;
|
||||||
|
|
||||||
|
if (*name == '@')
|
||||||
|
fatalx("user option %s must be a string", name);
|
||||||
|
|
||||||
|
o = options_get_only(oo, name);
|
||||||
|
if (o == NULL) {
|
||||||
|
o = options_default(oo, options_parent_table_entry(oo, name));
|
||||||
|
if (o == NULL)
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!OPTIONS_IS_COMMAND(o))
|
||||||
|
fatalx("option %s is not a command", name);
|
||||||
|
if (o->value.cmdlist != NULL)
|
||||||
|
cmd_list_free(o->value.cmdlist);
|
||||||
|
o->value.cmdlist = value;
|
||||||
|
return (o);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
options_scope_from_name(struct args *args, int window,
|
options_scope_from_name(struct args *args, int window,
|
||||||
const char *name, struct cmd_find_state *fs, struct options **oo,
|
const char *name, struct cmd_find_state *fs, struct options **oo,
|
||||||
@ -1054,6 +1103,7 @@ options_from_string(struct options *oo, const struct options_table_entry *oe,
|
|||||||
const char *errstr, *new;
|
const char *errstr, *new;
|
||||||
char *old;
|
char *old;
|
||||||
key_code key;
|
key_code key;
|
||||||
|
struct cmd_parse_result *pr;
|
||||||
|
|
||||||
if (oe != NULL) {
|
if (oe != NULL) {
|
||||||
if (value == NULL &&
|
if (value == NULL &&
|
||||||
@ -1112,6 +1162,15 @@ options_from_string(struct options *oo, const struct options_table_entry *oe,
|
|||||||
case OPTIONS_TABLE_CHOICE:
|
case OPTIONS_TABLE_CHOICE:
|
||||||
return (options_from_string_choice(oe, oo, name, value, cause));
|
return (options_from_string_choice(oe, oo, name, value, cause));
|
||||||
case OPTIONS_TABLE_COMMAND:
|
case OPTIONS_TABLE_COMMAND:
|
||||||
|
pr = cmd_parse_from_string(value, NULL);
|
||||||
|
switch (pr->status) {
|
||||||
|
case CMD_PARSE_ERROR:
|
||||||
|
*cause = pr->error;
|
||||||
|
return (-1);
|
||||||
|
case CMD_PARSE_SUCCESS:
|
||||||
|
options_set_command(oo, name, pr->cmdlist);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return (-1);
|
return (-1);
|
||||||
@ -1165,16 +1224,30 @@ options_push_changes(const char *name)
|
|||||||
if (strcmp(name, "window-style") == 0 ||
|
if (strcmp(name, "window-style") == 0 ||
|
||||||
strcmp(name, "window-active-style") == 0) {
|
strcmp(name, "window-active-style") == 0) {
|
||||||
RB_FOREACH(wp, window_pane_tree, &all_window_panes)
|
RB_FOREACH(wp, window_pane_tree, &all_window_panes)
|
||||||
wp->flags |= PANE_STYLECHANGED;
|
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||||
}
|
}
|
||||||
if (strcmp(name, "pane-colours") == 0) {
|
if (strcmp(name, "pane-colours") == 0) {
|
||||||
RB_FOREACH(wp, window_pane_tree, &all_window_panes)
|
RB_FOREACH(wp, window_pane_tree, &all_window_panes)
|
||||||
colour_palette_from_option(&wp->palette, wp->options);
|
colour_palette_from_option(&wp->palette, wp->options);
|
||||||
}
|
}
|
||||||
if (strcmp(name, "pane-border-status") == 0) {
|
if (strcmp(name, "pane-border-status") == 0 ||
|
||||||
|
strcmp(name, "pane-scrollbars") == 0 ||
|
||||||
|
strcmp(name, "pane-scrollbars-position") == 0) {
|
||||||
RB_FOREACH(w, windows, &windows)
|
RB_FOREACH(w, windows, &windows)
|
||||||
layout_fix_panes(w, NULL);
|
layout_fix_panes(w, NULL);
|
||||||
}
|
}
|
||||||
|
if (strcmp(name, "pane-scrollbars-style") == 0) {
|
||||||
|
RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
|
||||||
|
style_set_scrollbar_style_from_option(
|
||||||
|
&wp->scrollbar_style, wp->options);
|
||||||
|
}
|
||||||
|
RB_FOREACH(w, windows, &windows)
|
||||||
|
layout_fix_panes(w, NULL);
|
||||||
|
}
|
||||||
|
if (strcmp(name, "codepoint-widths") == 0)
|
||||||
|
utf8_update_width_cache();
|
||||||
|
if (strcmp(name, "input-buffer-size") == 0)
|
||||||
|
input_set_buffer_size(options_get_number(global_options, name));
|
||||||
RB_FOREACH(s, sessions, &sessions)
|
RB_FOREACH(s, sessions, &sessions)
|
||||||
status_update_cache(s);
|
status_update_cache(s);
|
||||||
|
|
||||||
|
2
paste.c
2
paste.c
@ -240,6 +240,8 @@ paste_rename(const char *oldname, const char *newname, char **cause)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pb_new = paste_get_name(newname);
|
pb_new = paste_get_name(newname);
|
||||||
|
if (pb_new == pb)
|
||||||
|
return (0);
|
||||||
if (pb_new != NULL)
|
if (pb_new != NULL)
|
||||||
paste_free(pb_new);
|
paste_free(pb_new);
|
||||||
|
|
||||||
|
13
popup.c
13
popup.c
@ -352,9 +352,11 @@ popup_make_pane(struct popup_data *pd, enum layout_type type)
|
|||||||
new_wp = window_add_pane(wp->window, NULL, hlimit, 0);
|
new_wp = window_add_pane(wp->window, NULL, hlimit, 0);
|
||||||
layout_assign_pane(lc, new_wp, 0);
|
layout_assign_pane(lc, new_wp, 0);
|
||||||
|
|
||||||
new_wp->fd = job_transfer(pd->job, &new_wp->pid, new_wp->tty,
|
if (pd->job != NULL) {
|
||||||
sizeof new_wp->tty);
|
new_wp->fd = job_transfer(pd->job, &new_wp->pid, new_wp->tty,
|
||||||
pd->job = NULL;
|
sizeof new_wp->tty);
|
||||||
|
pd->job = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
screen_set_title(&pd->s, new_wp->base.title);
|
screen_set_title(&pd->s, new_wp->base.title);
|
||||||
screen_free(&new_wp->base);
|
screen_free(&new_wp->base);
|
||||||
@ -528,7 +530,7 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
|
|||||||
(border == LEFT || border == TOP))
|
(border == LEFT || border == TOP))
|
||||||
goto menu;
|
goto menu;
|
||||||
if (((m->b & MOUSE_MASK_MODIFIERS) == MOUSE_MASK_META) ||
|
if (((m->b & MOUSE_MASK_MODIFIERS) == MOUSE_MASK_META) ||
|
||||||
border != NONE) {
|
(border != NONE && !MOUSE_DRAG(m->lb))) {
|
||||||
if (!MOUSE_DRAG(m->b))
|
if (!MOUSE_DRAG(m->b))
|
||||||
goto out;
|
goto out;
|
||||||
if (MOUSE_BUTTONS(m->lb) == MOUSE_BUTTON_1)
|
if (MOUSE_BUTTONS(m->lb) == MOUSE_BUTTON_1)
|
||||||
@ -691,6 +693,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
|
|||||||
pd->border_cell.attr = 0;
|
pd->border_cell.attr = 0;
|
||||||
|
|
||||||
screen_init(&pd->s, jx, jy, 0);
|
screen_init(&pd->s, jx, jy, 0);
|
||||||
|
screen_set_default_cursor(&pd->s, global_w_options);
|
||||||
colour_palette_init(&pd->palette);
|
colour_palette_init(&pd->palette);
|
||||||
colour_palette_from_option(&pd->palette, global_w_options);
|
colour_palette_from_option(&pd->palette, global_w_options);
|
||||||
|
|
||||||
@ -717,7 +720,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
|
|||||||
|
|
||||||
pd->job = job_run(shellcmd, argc, argv, env, s, cwd,
|
pd->job = job_run(shellcmd, argc, argv, env, s, cwd,
|
||||||
popup_job_update_cb, popup_job_complete_cb, NULL, pd,
|
popup_job_update_cb, popup_job_complete_cb, NULL, pd,
|
||||||
JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE, jx, jy);
|
JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE|JOB_DEFAULTSHELL, jx, jy);
|
||||||
pd->ictx = input_init(NULL, job_get_event(pd->job), &pd->palette);
|
pd->ictx = input_init(NULL, job_get_event(pd->job), &pd->palette);
|
||||||
|
|
||||||
server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
|
server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
|
||||||
|
22
proc.c
22
proc.c
@ -78,8 +78,7 @@ proc_event_cb(__unused int fd, short events, void *arg)
|
|||||||
struct imsg imsg;
|
struct imsg imsg;
|
||||||
|
|
||||||
if (!(peer->flags & PEER_BAD) && (events & EV_READ)) {
|
if (!(peer->flags & PEER_BAD) && (events & EV_READ)) {
|
||||||
if (((n = imsg_read(&peer->ibuf)) == -1 && errno != EAGAIN) ||
|
if (imsgbuf_read(&peer->ibuf) != 1) {
|
||||||
n == 0) {
|
|
||||||
peer->dispatchcb(NULL, peer->arg);
|
peer->dispatchcb(NULL, peer->arg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -93,9 +92,6 @@ proc_event_cb(__unused int fd, short events, void *arg)
|
|||||||
log_debug("peer %p message %d", peer, imsg.hdr.type);
|
log_debug("peer %p message %d", peer, imsg.hdr.type);
|
||||||
|
|
||||||
if (peer_check_version(peer, &imsg) != 0) {
|
if (peer_check_version(peer, &imsg) != 0) {
|
||||||
fd = imsg_get_fd(&imsg);
|
|
||||||
if (fd != -1)
|
|
||||||
close(fd);
|
|
||||||
imsg_free(&imsg);
|
imsg_free(&imsg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -106,13 +102,13 @@ proc_event_cb(__unused int fd, short events, void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (events & EV_WRITE) {
|
if (events & EV_WRITE) {
|
||||||
if (msgbuf_write(&peer->ibuf.w) <= 0 && errno != EAGAIN) {
|
if (imsgbuf_write(&peer->ibuf) == -1) {
|
||||||
peer->dispatchcb(NULL, peer->arg);
|
peer->dispatchcb(NULL, peer->arg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((peer->flags & PEER_BAD) && peer->ibuf.w.queued == 0) {
|
if ((peer->flags & PEER_BAD) && imsgbuf_queuelen(&peer->ibuf) == 0) {
|
||||||
peer->dispatchcb(NULL, peer->arg);
|
peer->dispatchcb(NULL, peer->arg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -153,7 +149,7 @@ proc_update_event(struct tmuxpeer *peer)
|
|||||||
event_del(&peer->event);
|
event_del(&peer->event);
|
||||||
|
|
||||||
events = EV_READ;
|
events = EV_READ;
|
||||||
if (peer->ibuf.w.queued > 0)
|
if (imsgbuf_queuelen(&peer->ibuf) > 0)
|
||||||
events |= EV_WRITE;
|
events |= EV_WRITE;
|
||||||
event_set(&peer->event, peer->ibuf.fd, events, proc_event_cb, peer);
|
event_set(&peer->event, peer->ibuf.fd, events, proc_event_cb, peer);
|
||||||
|
|
||||||
@ -225,7 +221,7 @@ proc_exit(struct tmuxproc *tp)
|
|||||||
struct tmuxpeer *peer;
|
struct tmuxpeer *peer;
|
||||||
|
|
||||||
TAILQ_FOREACH(peer, &tp->peers, entry)
|
TAILQ_FOREACH(peer, &tp->peers, entry)
|
||||||
imsg_flush(&peer->ibuf);
|
imsgbuf_flush(&peer->ibuf);
|
||||||
tp->exit = 1;
|
tp->exit = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,7 +309,9 @@ proc_add_peer(struct tmuxproc *tp, int fd,
|
|||||||
peer->dispatchcb = dispatchcb;
|
peer->dispatchcb = dispatchcb;
|
||||||
peer->arg = arg;
|
peer->arg = arg;
|
||||||
|
|
||||||
imsg_init(&peer->ibuf, fd);
|
if (imsgbuf_init(&peer->ibuf, fd) == -1)
|
||||||
|
fatal("imsgbuf_init");
|
||||||
|
imsgbuf_allow_fdpass(&peer->ibuf);
|
||||||
event_set(&peer->event, fd, EV_READ, proc_event_cb, peer);
|
event_set(&peer->event, fd, EV_READ, proc_event_cb, peer);
|
||||||
|
|
||||||
if (getpeereid(fd, &peer->uid, &gid) != 0)
|
if (getpeereid(fd, &peer->uid, &gid) != 0)
|
||||||
@ -333,7 +331,7 @@ proc_remove_peer(struct tmuxpeer *peer)
|
|||||||
log_debug("remove peer %p", peer);
|
log_debug("remove peer %p", peer);
|
||||||
|
|
||||||
event_del(&peer->event);
|
event_del(&peer->event);
|
||||||
imsg_clear(&peer->ibuf);
|
imsgbuf_clear(&peer->ibuf);
|
||||||
|
|
||||||
close(peer->ibuf.fd);
|
close(peer->ibuf.fd);
|
||||||
free(peer);
|
free(peer);
|
||||||
@ -348,7 +346,7 @@ proc_kill_peer(struct tmuxpeer *peer)
|
|||||||
void
|
void
|
||||||
proc_flush_peer(struct tmuxpeer *peer)
|
proc_flush_peer(struct tmuxpeer *peer)
|
||||||
{
|
{
|
||||||
imsg_flush(&peer->ibuf);
|
imsgbuf_flush(&peer->ibuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -16,7 +16,7 @@ do_test() {
|
|||||||
$TMUX -f/dev/null new -d "
|
$TMUX -f/dev/null new -d "
|
||||||
printf '$1'
|
printf '$1'
|
||||||
$TMUX capturep -peS0 -E1 >$TMP"
|
$TMUX capturep -peS0 -E1 >$TMP"
|
||||||
echo $2 > $TMP2
|
printf "$2\n" > $TMP2
|
||||||
sleep 1
|
sleep 1
|
||||||
cmp $TMP $TMP2 || exit 1
|
cmp $TMP $TMP2 || exit 1
|
||||||
return 0
|
return 0
|
||||||
|
@ -22,8 +22,8 @@ $TMUX -f/dev/null new -d "
|
|||||||
sleep 1
|
sleep 1
|
||||||
|
|
||||||
(
|
(
|
||||||
printf '\033[1m\033[31m\033[42mabc\033[0m\033[31m\033[49mdef\n'
|
printf '\033[1m\033[31m\033[42mabc\033[0m\033[31mdef\033[39m\n'
|
||||||
printf '\033[39m\033[100m bright bg\n'
|
printf '\033[100m bright bg \033[49m\n'
|
||||||
) | cmp - $TMP || exit 1
|
) | cmp - $TMP || exit 1
|
||||||
|
|
||||||
$TMUX has 2>/dev/null && exit 1
|
$TMUX has 2>/dev/null && exit 1
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
👍🏻3
|
👍🏻3
|
||||||
👍🏻 👍🏻4
|
👍🏻 👍🏻4
|
||||||
🤷♂️5
|
🤷♂️5
|
||||||
♂️ 7
|
♂️7
|
||||||
🤷♂️8
|
🤷♂️8
|
||||||
🤷♂️9
|
🤷♂️9
|
||||||
🤷♂️10
|
🤷♂️10
|
||||||
|
@ -35,7 +35,7 @@ set-option -g default-command 'tmux pipe-pane -o "cat >>~/tmux_logs/output-`date
|
|||||||
# from http://stackoverflow.com/questions/17255031/how-to-copy-from-tmux-running-in-putty-to-windows-clipbard
|
# from http://stackoverflow.com/questions/17255031/how-to-copy-from-tmux-running-in-putty-to-windows-clipbard
|
||||||
#
|
#
|
||||||
# for some reason this is wrapping at 80 cols, using save- instead of show- helps
|
# for some reason this is wrapping at 80 cols, using save- instead of show- helps
|
||||||
# -b for background is needed because xclip continues to run to service the clipboard paste reqeusts until the
|
# -b for background is needed because xclip continues to run to service the clipboard paste requests until the
|
||||||
# clipboard buffer is replaced with some new contents
|
# clipboard buffer is replaced with some new contents
|
||||||
#bind C-y run-shell -b "tmux save-buffer - | DISPLAY=$(<~/.xdisplay) xclip -selection clipboard -in && tmux display-message 'xclipped successfully'"
|
#bind C-y run-shell -b "tmux save-buffer - | DISPLAY=$(<~/.xdisplay) xclip -selection clipboard -in && tmux display-message 'xclipped successfully'"
|
||||||
bind C-y save-buffer ~/etc/clipboard.pipe
|
bind C-y save-buffer ~/etc/clipboard.pipe
|
||||||
@ -75,4 +75,4 @@ set-window-option -g window-status-current-format "#{?pane_synchronized,#[bg=red
|
|||||||
set-option -g window-status-current-style bg=blue
|
set-option -g window-status-current-style bg=blue
|
||||||
|
|
||||||
# Toggle input on a pane (from Thomas Sattler)
|
# Toggle input on a pane (from Thomas Sattler)
|
||||||
bind-key R if -F '#{pane_input_off}' "select-pane -e; select-pane -P fg=default" "select-pane -d; select-pane -P fg=yellow"
|
bind-key R if -F '#{pane_input_off}' "select-pane -e; select-pane -P fg=default" "select-pane -d; select-pane -P fg=yellow"
|
||||||
|
@ -42,7 +42,7 @@ $TMUX send-keys -X begin-selection
|
|||||||
$TMUX send-keys -X next-word-end
|
$TMUX send-keys -X next-word-end
|
||||||
$TMUX send-keys -X next-word-end
|
$TMUX send-keys -X next-word-end
|
||||||
$TMUX send-keys -X copy-selection
|
$TMUX send-keys -X copy-selection
|
||||||
[ "$($TMUX show-buffer)" = "$(printf "words\n Indented")" ] || exit 1
|
[ "$($TMUX show-buffer)" = "$(printf "words\n\tIndented")" ] || exit 1
|
||||||
|
|
||||||
# Test that `next-word` wraps around un-indented line breaks.
|
# Test that `next-word` wraps around un-indented line breaks.
|
||||||
$TMUX send-keys -X next-word
|
$TMUX send-keys -X next-word
|
||||||
|
@ -41,7 +41,7 @@ $TMUX send-keys -X begin-selection
|
|||||||
$TMUX send-keys -X next-word-end
|
$TMUX send-keys -X next-word-end
|
||||||
$TMUX send-keys -X next-word-end
|
$TMUX send-keys -X next-word-end
|
||||||
$TMUX send-keys -X copy-selection
|
$TMUX send-keys -X copy-selection
|
||||||
[ "$($TMUX show-buffer)" = "$(printf "words\n Indented")" ] || exit 1
|
[ "$($TMUX show-buffer)" = "$(printf "words\n\tIndented")" ] || exit 1
|
||||||
|
|
||||||
# Test that `next-word` wraps around un-indented line breaks.
|
# Test that `next-word` wraps around un-indented line breaks.
|
||||||
$TMUX send-keys -X next-word
|
$TMUX send-keys -X next-word
|
||||||
|
@ -60,7 +60,13 @@ test_conditional_with_session_name()
|
|||||||
|
|
||||||
$TMUX kill-server 2>/dev/null
|
$TMUX kill-server 2>/dev/null
|
||||||
$TMUX -f/dev/null new-session -d || exit 1
|
$TMUX -f/dev/null new-session -d || exit 1
|
||||||
$TMUX rename-session "Summer" || exit 1 # used later in conditionals
|
|
||||||
|
# used later in conditionals
|
||||||
|
$TMUX rename-session "Summer" || exit 1
|
||||||
|
$TMUX set @true 1 || exit 1
|
||||||
|
$TMUX set @false 0 || exit 1
|
||||||
|
$TMUX set @warm Summer || exit 1
|
||||||
|
$TMUX set @cold Winter || exit 1
|
||||||
|
|
||||||
# Plain string without substitutions et al
|
# Plain string without substitutions et al
|
||||||
test_format "abc xyz" "abc xyz"
|
test_format "abc xyz" "abc xyz"
|
||||||
@ -77,13 +83,21 @@ test_format "###}" "#}" # not a "basic" one but interesting nevertheless
|
|||||||
test_format "#{pane_in_mode}" "0"
|
test_format "#{pane_in_mode}" "0"
|
||||||
|
|
||||||
# Simple conditionals
|
# Simple conditionals
|
||||||
|
test_format "#{?}" ""
|
||||||
|
test_format "#{?abc}" "abc"
|
||||||
|
test_conditional_with_pane_in_mode "#{?pane_in_mode,abc}" "abc" ""
|
||||||
test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,xyz}" "abc" "xyz"
|
test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,xyz}" "abc" "xyz"
|
||||||
|
test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,@true,xyz}" "abc" "xyz"
|
||||||
|
test_format "#{?@false,abc,@false,xyz}" ""
|
||||||
|
test_format "#{?@false,abc,@false,xyz,default}" "default"
|
||||||
|
|
||||||
# Expansion in conditionals
|
# Expansion in conditionals
|
||||||
test_conditional_with_pane_in_mode "#{?pane_in_mode,#{session_name},xyz}" "Summer" "xyz"
|
test_format "#{?#{@warm}}" "Summer"
|
||||||
|
test_conditional_with_pane_in_mode "#{?#{pane_in_mode},#{@warm}}" "Summer" ""
|
||||||
|
test_conditional_with_pane_in_mode "#{?#{pane_in_mode},#{@warm},#{@cold}}" "Summer" "Winter"
|
||||||
|
|
||||||
# Basic escapes in conditionals
|
# Basic escapes in conditionals
|
||||||
# First argument
|
# Value of an (else-)if-condition
|
||||||
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"
|
test_conditional_with_pane_in_mode "#{?pane_in_mode,{,xyz}" "{" "xyz"
|
||||||
@ -91,7 +105,7 @@ 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
|
# not a "basic" one but interesting nevertheless
|
||||||
test_conditional_with_pane_in_mode "#{?pane_in_mode,###},xyz}" "#}" "xyz"
|
test_conditional_with_pane_in_mode "#{?pane_in_mode,###},xyz}" "#}" "xyz"
|
||||||
# Second argument
|
# Default value if no condition matches
|
||||||
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" "{"
|
test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,{}" "abc" "{"
|
||||||
@ -105,9 +119,6 @@ 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,###},##{}" "#}" "#{"
|
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
|
# Curly brackets {...} do not capture a comma inside of conditionals as the
|
||||||
# conditional ends on the first '}'
|
# conditional ends on the first '}'
|
||||||
test_conditional_with_pane_in_mode "#{?pane_in_mode,{abc,xyz},bonus}" "{abc,bonus}" "xyz,bonus}"
|
test_conditional_with_pane_in_mode "#{?pane_in_mode,{abc,xyz},bonus}" "{abc,bonus}" "xyz,bonus}"
|
||||||
@ -116,12 +127,12 @@ test_conditional_with_pane_in_mode "#{?pane_in_mode,{abc,xyz},bonus}" "{abc,bonu
|
|||||||
# invalid format: #{abc,xyz} is not a known variable name.
|
# invalid format: #{abc,xyz} is not a known variable name.
|
||||||
#test_conditional_with_pane_in_mode "#{?pane_in_mode,#{abc,xyz},bonus}" "" "bonus"
|
#test_conditional_with_pane_in_mode "#{?pane_in_mode,#{abc,xyz},bonus}" "" "bonus"
|
||||||
|
|
||||||
# Parenthesis (...) do not captura a comma
|
# Parenthesis (...) do not capture a comma, and "xyz)" is a false condition
|
||||||
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" ""
|
||||||
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
|
# Brackets [...] do not capture a comma, and "xyz]" is a false condition
|
||||||
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" ""
|
||||||
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"
|
||||||
|
|
||||||
|
|
||||||
@ -138,12 +149,12 @@ test_conditional_with_pane_in_mode "#{?pane_in_mode,#(echo #,),xyz}" "" "xyz"
|
|||||||
#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 #{?,,}.
|
# invalid format: '#(' is not closed in the first argument of #{?,,}.
|
||||||
#test_conditional_with_pane_in_mode "#{?pane_in_mode,#(echo ,),xyz}" "" "),xyz"
|
test_conditional_with_pane_in_mode "#{?pane_in_mode,#(echo ,)xyz}" "" ")xyz"
|
||||||
|
|
||||||
# Escape comma inside of #[...]
|
# 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"
|
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 #{?,,}
|
# invalid style: '#[' 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"
|
test_conditional_with_pane_in_mode "#{?pane_in_mode,#[fg=default,bg=default]abc}" "#[fg=default" "bg=default]abc"
|
||||||
|
|
||||||
# Conditionals with comparison
|
# Conditionals with comparison
|
||||||
test_conditional_with_session_name "#{?#{==:#{session_name},Summer},abc,xyz}" "abc" "xyz"
|
test_conditional_with_session_name "#{?#{==:#{session_name},Summer},abc,xyz}" "abc" "xyz"
|
||||||
@ -164,6 +175,47 @@ test_conditional_with_pane_in_mode "#{?#{==:#{?pane_in_mode,#{session_name},#(ec
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Tests for boolean expressions
|
||||||
|
|
||||||
|
# "0" and the empty string are false, everything else is true.
|
||||||
|
test_format "#{!!:0}" "0"
|
||||||
|
test_format "#{!!:}" "0"
|
||||||
|
test_format "#{!!:1}" "1"
|
||||||
|
test_format "#{!!:2}" "1"
|
||||||
|
test_format "#{!!:non-empty string}" "1"
|
||||||
|
test_format "#{!!:-0}" "1"
|
||||||
|
test_format "#{!!:0.0}" "1"
|
||||||
|
|
||||||
|
# Logical operators
|
||||||
|
test_format "#{!:0}" "1"
|
||||||
|
test_format "#{!:1}" "0"
|
||||||
|
|
||||||
|
test_format "#{&&:0}" "0"
|
||||||
|
test_format "#{&&:1}" "1"
|
||||||
|
test_format "#{&&:0,0}" "0"
|
||||||
|
test_format "#{&&:0,1}" "0"
|
||||||
|
test_format "#{&&:1,0}" "0"
|
||||||
|
test_format "#{&&:1,1}" "1"
|
||||||
|
test_format "#{&&:0,0,0}" "0"
|
||||||
|
test_format "#{&&:0,1,1}" "0"
|
||||||
|
test_format "#{&&:1,0,1}" "0"
|
||||||
|
test_format "#{&&:1,1,0}" "0"
|
||||||
|
test_format "#{&&:1,1,1}" "1"
|
||||||
|
|
||||||
|
test_format "#{||:0}" "0"
|
||||||
|
test_format "#{||:1}" "1"
|
||||||
|
test_format "#{||:0,0}" "0"
|
||||||
|
test_format "#{||:0,1}" "1"
|
||||||
|
test_format "#{||:1,0}" "1"
|
||||||
|
test_format "#{||:1,1}" "1"
|
||||||
|
test_format "#{||:0,0,0}" "0"
|
||||||
|
test_format "#{||:1,0,0}" "1"
|
||||||
|
test_format "#{||:0,1,0}" "1"
|
||||||
|
test_format "#{||:0,0,1}" "1"
|
||||||
|
test_format "#{||:1,1,1}" "1"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Format test for the literal option
|
# Format test for the literal option
|
||||||
# Note: The behavior for #{l:...} with escapes is sometimes weird as #{l:...}
|
# Note: The behavior for #{l:...} with escapes is sometimes weird as #{l:...}
|
||||||
# respects the escapes.
|
# respects the escapes.
|
||||||
@ -172,7 +224,7 @@ 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}"
|
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)
|
# With escapes (which escape but are returned literally)
|
||||||
test_format "#{l:##{}" "##{"
|
test_format "#{l:##{}" "#{"
|
||||||
test_format "#{l:#{#}}}" "#{#}}"
|
test_format "#{l:#{#}}}" "#{#}}"
|
||||||
|
|
||||||
# Invalid formats:
|
# Invalid formats:
|
||||||
|
@ -6,10 +6,10 @@ TERM=screen
|
|||||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||||
TMUX="$TEST_TMUX -Ltest"
|
TMUX="$TEST_TMUX -Ltest"
|
||||||
$TMUX kill-server 2>/dev/null
|
$TMUX kill-server 2>/dev/null
|
||||||
|
sleep 1
|
||||||
$TMUX -f/dev/null new -x20 -y2 -d || exit 1
|
$TMUX -f/dev/null new -x20 -y2 -d || exit 1
|
||||||
|
sleep 1
|
||||||
sleep 0.1
|
$TMUX set -g escape-time 0
|
||||||
|
|
||||||
exit_status=0
|
exit_status=0
|
||||||
|
|
||||||
@ -17,11 +17,14 @@ assert_key () {
|
|||||||
key=$1
|
key=$1
|
||||||
expected_code=$2
|
expected_code=$2
|
||||||
|
|
||||||
$TMUX new-window -- sh -c 'stty raw -echo && cat -tv'
|
W=$($TMUX new-window -P -- sh -c 'stty raw -echo && cat -tv')
|
||||||
$TMUX send-keys "$key" $
|
$TMUX send-keys -t$W "$key" 'EOL' || exit 1
|
||||||
|
sleep 0.2
|
||||||
|
|
||||||
actual_code=$($TMUX capturep -p | head -1 | sed -e 's/\$$//')
|
actual_code=$($TMUX capturep -pt$W | \
|
||||||
$TMUX kill-window
|
head -1 | \
|
||||||
|
sed -e 's/EOL.*$//')
|
||||||
|
$TMUX kill-window -t$W || exit 1
|
||||||
|
|
||||||
if [ "$actual_code" = "$expected_code" ]; then
|
if [ "$actual_code" = "$expected_code" ]; then
|
||||||
if [ -n "$VERBOSE" ]; then
|
if [ -n "$VERBOSE" ]; then
|
||||||
@ -205,7 +208,7 @@ assert_key 'PageUp' '^[[5~'
|
|||||||
assert_key 'PgUp' '^[[5~'
|
assert_key 'PgUp' '^[[5~'
|
||||||
|
|
||||||
assert_key 'BTab' '^[[Z'
|
assert_key 'BTab' '^[[Z'
|
||||||
assert_key 'C-S-Tab' '^[[Z'
|
assert_key 'C-S-Tab' '^I'
|
||||||
|
|
||||||
assert_key 'Up' '^[[A'
|
assert_key 'Up' '^[[A'
|
||||||
assert_key 'Down' '^[[B'
|
assert_key 'Down' '^[[B'
|
||||||
@ -291,8 +294,8 @@ assert_extended_key 'Insert' '^[[2;_~'
|
|||||||
assert_extended_key 'DC' '^[[3;_~'
|
assert_extended_key 'DC' '^[[3;_~'
|
||||||
assert_extended_key 'Delete' '^[[3;_~'
|
assert_extended_key 'Delete' '^[[3;_~'
|
||||||
|
|
||||||
assert_key 'C-Tab' "^[[9;5u"
|
assert_key 'C-Tab' "^[[27;5;9~"
|
||||||
assert_key 'C-S-Tab' "^[[1;5Z"
|
assert_key 'C-S-Tab' "^[[27;6;9~"
|
||||||
|
|
||||||
$TMUX kill-server 2>/dev/null
|
$TMUX kill-server 2>/dev/null
|
||||||
|
|
||||||
|
@ -3,16 +3,16 @@
|
|||||||
# new session environment
|
# new session environment
|
||||||
|
|
||||||
PATH=/bin:/usr/bin
|
PATH=/bin:/usr/bin
|
||||||
TERM=screen
|
|
||||||
|
|
||||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||||
TMUX="$TEST_TMUX -Ltest"
|
TMUX="$TEST_TMUX -Ltest"
|
||||||
$TMUX kill-server 2>/dev/null
|
$TMUX kill-server 2>/dev/null
|
||||||
|
|
||||||
|
TERM=$($TMUX start \; show -gv default-terminal)
|
||||||
TMP=$(mktemp)
|
TMP=$(mktemp)
|
||||||
OUT=$(mktemp)
|
OUT=$(mktemp)
|
||||||
SCRIPT=$(mktemp)
|
SCRIPT=$(mktemp)
|
||||||
trap "rm -f $TMP $OUT $SCRIPT" 0 1 15
|
#trap "rm -f $TMP $OUT $SCRIPT" 0 1 15
|
||||||
|
|
||||||
cat <<EOF >$SCRIPT
|
cat <<EOF >$SCRIPT
|
||||||
(
|
(
|
||||||
@ -32,7 +32,7 @@ EOF
|
|||||||
$TMUX -f$TMP start) || exit 1
|
$TMUX -f$TMP start) || exit 1
|
||||||
sleep 1
|
sleep 1
|
||||||
(cat <<EOF|cmp -s - $OUT) || exit 1
|
(cat <<EOF|cmp -s - $OUT) || exit 1
|
||||||
TERM=screen
|
TERM=$TERM
|
||||||
PWD=/
|
PWD=/
|
||||||
PATH=1
|
PATH=1
|
||||||
SHELL=/bin/sh
|
SHELL=/bin/sh
|
||||||
@ -43,7 +43,7 @@ EOF
|
|||||||
$TMUX -f$TMP new -d -- /bin/sh $SCRIPT) || exit 1
|
$TMUX -f$TMP new -d -- /bin/sh $SCRIPT) || exit 1
|
||||||
sleep 1
|
sleep 1
|
||||||
(cat <<EOF|cmp -s - $OUT) || exit 1
|
(cat <<EOF|cmp -s - $OUT) || exit 1
|
||||||
TERM=screen
|
TERM=$TERM
|
||||||
PWD=/
|
PWD=/
|
||||||
PATH=2
|
PATH=2
|
||||||
SHELL=/bin/sh
|
SHELL=/bin/sh
|
||||||
@ -54,7 +54,7 @@ EOF
|
|||||||
$TMUX -f/dev/null new -d source $TMP) || exit 1
|
$TMUX -f/dev/null new -d source $TMP) || exit 1
|
||||||
sleep 1
|
sleep 1
|
||||||
(cat <<EOF|cmp -s - $OUT) || exit 1
|
(cat <<EOF|cmp -s - $OUT) || exit 1
|
||||||
TERM=screen
|
TERM=$TERM
|
||||||
PWD=/
|
PWD=/
|
||||||
PATH=2
|
PATH=2
|
||||||
SHELL=/bin/sh
|
SHELL=/bin/sh
|
||||||
|
25
regress/run-shell-output.sh
Normal file
25
regress/run-shell-output.sh
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# 4476
|
||||||
|
# run-shell should go to stdout if present without -t
|
||||||
|
|
||||||
|
PATH=/bin:/usr/bin
|
||||||
|
TERM=screen
|
||||||
|
|
||||||
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||||
|
TMUX="$TEST_TMUX -Ltest"
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
|
||||||
|
TMP=$(mktemp)
|
||||||
|
trap "rm -f $TMP" 0 1 15
|
||||||
|
|
||||||
|
$TMUX -f/dev/null new -d "$TMUX run 'echo foo' >$TMP; sleep 10" || exit 1
|
||||||
|
sleep 1 && [ "$(cat $TMP)" = "foo" ] || exit 1
|
||||||
|
|
||||||
|
$TMUX -f/dev/null new -d "$TMUX run -t: 'echo foo' >$TMP; sleep 10" || exit 1
|
||||||
|
sleep 1 && [ "$(cat $TMP)" = "" ] || exit 1
|
||||||
|
[ "$($TMUX display -p '#{pane_mode}')" = "view-mode" ] || exit 1
|
||||||
|
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
|
||||||
|
exit 0
|
@ -3,13 +3,26 @@
|
|||||||
PATH=/bin:/usr/bin
|
PATH=/bin:/usr/bin
|
||||||
TERM=screen
|
TERM=screen
|
||||||
|
|
||||||
|
shell=
|
||||||
|
if command -v bash >/dev/null 2>&1; then
|
||||||
|
# If Bash is available, we start a plain Bash session (without any user
|
||||||
|
# configuration files) for testing.
|
||||||
|
#
|
||||||
|
# Note: We disable the command history by passing "+o history". If an
|
||||||
|
# interactive Bash session is started without any configuration files,
|
||||||
|
# the user's command history may be truncated to the default maximum
|
||||||
|
# size of 500. To avoid breaking the user's command history, we disable
|
||||||
|
# the command history.
|
||||||
|
shell='bash --noprofile --norc +o history'
|
||||||
|
fi
|
||||||
|
|
||||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||||
TMUX="$TEST_TMUX -Ltest"
|
TMUX="$TEST_TMUX -Ltest"
|
||||||
$TMUX kill-server 2>/dev/null
|
$TMUX kill-server 2>/dev/null
|
||||||
TMUX2="$TEST_TMUX -Ltest2"
|
TMUX2="$TEST_TMUX -Ltest2"
|
||||||
$TMUX2 kill-server 2>/dev/null
|
$TMUX2 kill-server 2>/dev/null
|
||||||
|
|
||||||
$TMUX2 -f/dev/null new -d "$TMUX -f/dev/null new"
|
$TMUX2 -f/dev/null new -d "$TMUX -f/dev/null new -- $shell"
|
||||||
sleep 2
|
sleep 2
|
||||||
$TMUX set -g status-style fg=default,bg=default
|
$TMUX set -g status-style fg=default,bg=default
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ trap "rm -f $TMP" 0 1 15
|
|||||||
|
|
||||||
$TMUX2 -f/dev/null new -d || exit 1
|
$TMUX2 -f/dev/null new -d || exit 1
|
||||||
$TMUX -f/dev/null new -d "$TMUX2 attach" || exit 1
|
$TMUX -f/dev/null new -d "$TMUX2 attach" || exit 1
|
||||||
sleep 0.1
|
sleep 1
|
||||||
|
|
||||||
exit_status=0
|
exit_status=0
|
||||||
|
|
||||||
@ -60,38 +60,38 @@ assert_key () {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_key 0x00 'C-Space' # -- 'Escape 0x00' 'M-C-Space'
|
assert_key 0x00 'C-Space' # -- 'Escape 0x00' 'C-M-Space'
|
||||||
assert_key 0x01 'C-a' -- 'Escape 0x01' 'M-C-a'
|
assert_key 0x01 'C-a' -- 'Escape 0x01' 'C-M-a'
|
||||||
assert_key 0x02 'C-b' -- 'Escape 0x02' 'M-C-b'
|
assert_key 0x02 'C-b' -- 'Escape 0x02' 'C-M-b'
|
||||||
assert_key 0x03 'C-c' -- 'Escape 0x03' 'M-C-c'
|
assert_key 0x03 'C-c' -- 'Escape 0x03' 'C-M-c'
|
||||||
assert_key 0x04 'C-d' -- 'Escape 0x04' 'M-C-d'
|
assert_key 0x04 'C-d' -- 'Escape 0x04' 'C-M-d'
|
||||||
assert_key 0x05 'C-e' -- 'Escape 0x05' 'M-C-e'
|
assert_key 0x05 'C-e' -- 'Escape 0x05' 'C-M-e'
|
||||||
assert_key 0x06 'C-f' -- 'Escape 0x06' 'M-C-f'
|
assert_key 0x06 'C-f' -- 'Escape 0x06' 'C-M-f'
|
||||||
assert_key 0x07 'C-g' -- 'Escape 0x07' 'M-C-g'
|
assert_key 0x07 'C-g' -- 'Escape 0x07' 'C-M-g'
|
||||||
assert_key 0x08 'C-h' -- 'Escape 0x08' 'M-C-h'
|
assert_key 0x08 'C-h' -- 'Escape 0x08' 'C-M-h'
|
||||||
assert_key 0x09 'Tab' -- 'Escape 0x09' 'M-Tab'
|
assert_key 0x09 'Tab' -- 'Escape 0x09' 'M-Tab'
|
||||||
assert_key 0x0A 'C-j' -- 'Escape 0x0A' 'M-C-j'
|
assert_key 0x0A 'C-j' -- 'Escape 0x0A' 'C-M-j'
|
||||||
assert_key 0x0B 'C-k' -- 'Escape 0x0B' 'M-C-k'
|
assert_key 0x0B 'C-k' -- 'Escape 0x0B' 'C-M-k'
|
||||||
assert_key 0x0C 'C-l' -- 'Escape 0x0C' 'M-C-l'
|
assert_key 0x0C 'C-l' -- 'Escape 0x0C' 'C-M-l'
|
||||||
assert_key 0x0D 'Enter' -- 'Escape 0x0D' 'M-Enter'
|
assert_key 0x0D 'Enter' -- 'Escape 0x0D' 'M-Enter'
|
||||||
assert_key 0x0E 'C-n' -- 'Escape 0x0E' 'M-C-n'
|
assert_key 0x0E 'C-n' -- 'Escape 0x0E' 'C-M-n'
|
||||||
assert_key 0x0F 'C-o' -- 'Escape 0x0F' 'M-C-o'
|
assert_key 0x0F 'C-o' -- 'Escape 0x0F' 'C-M-o'
|
||||||
assert_key 0x10 'C-p' -- 'Escape 0x10' 'M-C-p'
|
assert_key 0x10 'C-p' -- 'Escape 0x10' 'C-M-p'
|
||||||
assert_key 0x11 'C-q' -- 'Escape 0x11' 'M-C-q'
|
assert_key 0x11 'C-q' -- 'Escape 0x11' 'C-M-q'
|
||||||
assert_key 0x12 'C-r' -- 'Escape 0x12' 'M-C-r'
|
assert_key 0x12 'C-r' -- 'Escape 0x12' 'C-M-r'
|
||||||
assert_key 0x13 'C-s' -- 'Escape 0x13' 'M-C-s'
|
assert_key 0x13 'C-s' -- 'Escape 0x13' 'C-M-s'
|
||||||
assert_key 0x14 'C-t' -- 'Escape 0x14' 'M-C-t'
|
assert_key 0x14 'C-t' -- 'Escape 0x14' 'C-M-t'
|
||||||
assert_key 0x15 'C-u' -- 'Escape 0x15' 'M-C-u'
|
assert_key 0x15 'C-u' -- 'Escape 0x15' 'C-M-u'
|
||||||
assert_key 0x16 'C-v' -- 'Escape 0x16' 'M-C-v'
|
assert_key 0x16 'C-v' -- 'Escape 0x16' 'C-M-v'
|
||||||
assert_key 0x17 'C-w' -- 'Escape 0x17' 'M-C-w'
|
assert_key 0x17 'C-w' -- 'Escape 0x17' 'C-M-w'
|
||||||
assert_key 0x18 'C-x' -- 'Escape 0x18' 'M-C-x'
|
assert_key 0x18 'C-x' -- 'Escape 0x18' 'C-M-x'
|
||||||
assert_key 0x19 'C-y' -- 'Escape 0x19' 'M-C-y'
|
assert_key 0x19 'C-y' -- 'Escape 0x19' 'C-M-y'
|
||||||
assert_key 0x1A 'C-z' -- 'Escape 0x1A' 'M-C-z'
|
assert_key 0x1A 'C-z' -- 'Escape 0x1A' 'C-M-z'
|
||||||
assert_key 0x1B 'Escape' -- 'Escape 0x1B' 'M-Escape'
|
assert_key 0x1B 'Escape' -- 'Escape 0x1B' 'M-Escape'
|
||||||
assert_key 0x1C "C-\\" -- 'Escape 0x1C' "M-C-\\"
|
assert_key 0x1C "C-\\" -- 'Escape 0x1C' "C-M-\\"
|
||||||
assert_key 0x1D 'C-]' -- 'Escape 0x1D' 'M-C-]'
|
assert_key 0x1D 'C-]' -- 'Escape 0x1D' 'C-M-]'
|
||||||
assert_key 0x1E 'C-^' -- 'Escape 0x1E' 'M-C-^'
|
assert_key 0x1E 'C-^' -- 'Escape 0x1E' 'C-M-^'
|
||||||
assert_key 0x1F 'C-_' -- 'Escape 0x1F' 'M-C-_'
|
assert_key 0x1F 'C-_' -- 'Escape 0x1F' 'C-M-_'
|
||||||
assert_key 0x20 'Space' -- 'Escape 0x20' 'M-Space'
|
assert_key 0x20 'Space' -- 'Escape 0x20' 'M-Space'
|
||||||
assert_key 0x21 '!' -- 'Escape 0x21' 'M-!'
|
assert_key 0x21 '!' -- 'Escape 0x21' 'M-!'
|
||||||
assert_key 0x22 '"' -- 'Escape 0x22' 'M-"'
|
assert_key 0x22 '"' -- 'Escape 0x22' 'M-"'
|
||||||
@ -304,7 +304,7 @@ assert_extended_key () {
|
|||||||
key_name=$2
|
key_name=$2
|
||||||
|
|
||||||
assert_key "Escape [${code};5u" "C-$key_name"
|
assert_key "Escape [${code};5u" "C-$key_name"
|
||||||
assert_key "Escape [${code};7u" "M-C-$key_name"
|
assert_key "Escape [${code};7u" "C-M-$key_name"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Extended keys
|
# Extended keys
|
||||||
|
21
resize.c
21
resize.c
@ -264,16 +264,9 @@ skip:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
default_window_size_skip_client(struct client *loop, int type,
|
default_window_size_skip_client(struct client *loop, __unused int type,
|
||||||
__unused int current, struct session *s, struct window *w)
|
__unused int current, struct session *s, struct window *w)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Latest checks separately, so do not check here. Otherwise only
|
|
||||||
* include clients where the session contains the window or where the
|
|
||||||
* session is the given session.
|
|
||||||
*/
|
|
||||||
if (type == WINDOW_SIZE_LATEST)
|
|
||||||
return (0);
|
|
||||||
if (w != NULL && !session_has(loop->session, w))
|
if (w != NULL && !session_has(loop->session, w))
|
||||||
return (1);
|
return (1);
|
||||||
if (w == NULL && loop->session != s)
|
if (w == NULL && loop->session != s)
|
||||||
@ -305,12 +298,12 @@ default_window_size(struct client *c, struct session *s, struct window *w,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ignore the given client if it is a control client - the creating
|
* Ignore the given client if it is a control client - the creating
|
||||||
* client should only affect the size if it is not a control client.
|
* client should only affect the size if it is not a control client.
|
||||||
*/
|
*/
|
||||||
if (c != NULL && (c->flags & CLIENT_CONTROL))
|
if (c != NULL && (c->flags & CLIENT_CONTROL))
|
||||||
c = NULL;
|
c = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look for a client to base the size on. If none exists (or the type
|
* Look for a client to base the size on. If none exists (or the type
|
||||||
|
338
screen-redraw.c
338
screen-redraw.c
@ -30,6 +30,11 @@ static void screen_redraw_draw_pane(struct screen_redraw_ctx *,
|
|||||||
struct window_pane *);
|
struct window_pane *);
|
||||||
static void screen_redraw_set_context(struct client *,
|
static void screen_redraw_set_context(struct client *,
|
||||||
struct screen_redraw_ctx *);
|
struct screen_redraw_ctx *);
|
||||||
|
static void screen_redraw_draw_pane_scrollbars(struct screen_redraw_ctx *);
|
||||||
|
static void screen_redraw_draw_scrollbar(struct screen_redraw_ctx *,
|
||||||
|
struct window_pane *, int, int, int, u_int, u_int, u_int);
|
||||||
|
static void screen_redraw_draw_pane_scrollbar(struct screen_redraw_ctx *,
|
||||||
|
struct window_pane *);
|
||||||
|
|
||||||
#define START_ISOLATE "\342\201\246"
|
#define START_ISOLATE "\342\201\246"
|
||||||
#define END_ISOLATE "\342\201\251"
|
#define END_ISOLATE "\342\201\251"
|
||||||
@ -113,9 +118,15 @@ screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp,
|
|||||||
u_int px, u_int py)
|
u_int px, u_int py)
|
||||||
{
|
{
|
||||||
struct options *oo = wp->window->options;
|
struct options *oo = wp->window->options;
|
||||||
int split = 0;
|
|
||||||
u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy;
|
u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy;
|
||||||
int pane_status = ctx->pane_status;
|
int hsplit = 0, vsplit = 0, pane_status = ctx->pane_status;
|
||||||
|
int pane_scrollbars = ctx->pane_scrollbars, sb_w = 0;
|
||||||
|
int sb_pos;
|
||||||
|
|
||||||
|
if (pane_scrollbars != 0)
|
||||||
|
sb_pos = ctx->pane_scrollbars_pos;
|
||||||
|
else
|
||||||
|
sb_pos = 0;
|
||||||
|
|
||||||
/* Inside pane. */
|
/* Inside pane. */
|
||||||
if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey)
|
if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey)
|
||||||
@ -125,62 +136,68 @@ screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp,
|
|||||||
switch (options_get_number(oo, "pane-border-indicators")) {
|
switch (options_get_number(oo, "pane-border-indicators")) {
|
||||||
case PANE_BORDER_COLOUR:
|
case PANE_BORDER_COLOUR:
|
||||||
case PANE_BORDER_BOTH:
|
case PANE_BORDER_BOTH:
|
||||||
split = 1;
|
hsplit = screen_redraw_two_panes(wp->window, 0);
|
||||||
|
vsplit = screen_redraw_two_panes(wp->window, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Left/right borders. */
|
/* Are scrollbars enabled? */
|
||||||
if (pane_status == PANE_STATUS_OFF) {
|
if (window_pane_show_scrollbar(wp, pane_scrollbars))
|
||||||
if (screen_redraw_two_panes(wp->window, 0) && split) {
|
sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad;
|
||||||
if (wp->xoff == 0 && px == wp->sx && py <= wp->sy / 2)
|
|
||||||
return (SCREEN_REDRAW_BORDER_RIGHT);
|
/*
|
||||||
if (wp->xoff != 0 &&
|
* Left/right borders. The wp->sy / 2 test is to colour only half the
|
||||||
px == wp->xoff - 1 &&
|
* active window's border when there are two panes.
|
||||||
py > wp->sy / 2)
|
*/
|
||||||
return (SCREEN_REDRAW_BORDER_LEFT);
|
if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
|
||||||
} else {
|
if (sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||||
if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
|
if (wp->xoff - sb_w == 0 && px == wp->sx + sb_w)
|
||||||
if (wp->xoff != 0 && px == wp->xoff - 1)
|
if (!hsplit || (hsplit && py <= wp->sy / 2))
|
||||||
|
return (SCREEN_REDRAW_BORDER_RIGHT);
|
||||||
|
if (wp->xoff - sb_w != 0) {
|
||||||
|
if (px == wp->xoff - sb_w - 1 &&
|
||||||
|
(!hsplit || (hsplit && py > wp->sy / 2)))
|
||||||
return (SCREEN_REDRAW_BORDER_LEFT);
|
return (SCREEN_REDRAW_BORDER_LEFT);
|
||||||
if (px == ex)
|
if (px == wp->xoff + wp->sx + sb_w - 1)
|
||||||
|
return (SCREEN_REDRAW_BORDER_RIGHT);
|
||||||
|
}
|
||||||
|
} else { /* sb_pos == PANE_SCROLLBARS_RIGHT or disabled*/
|
||||||
|
if (wp->xoff == 0 && px == wp->sx + sb_w)
|
||||||
|
if (!hsplit || (hsplit && py <= wp->sy / 2))
|
||||||
|
return (SCREEN_REDRAW_BORDER_RIGHT);
|
||||||
|
if (wp->xoff != 0) {
|
||||||
|
if (px == wp->xoff - 1 &&
|
||||||
|
(!hsplit || (hsplit && py > wp->sy / 2)))
|
||||||
|
return (SCREEN_REDRAW_BORDER_LEFT);
|
||||||
|
if (px == wp->xoff + wp->sx + sb_w)
|
||||||
return (SCREEN_REDRAW_BORDER_RIGHT);
|
return (SCREEN_REDRAW_BORDER_RIGHT);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
|
|
||||||
if (wp->xoff != 0 && px == wp->xoff - 1)
|
|
||||||
return (SCREEN_REDRAW_BORDER_LEFT);
|
|
||||||
if (px == ex)
|
|
||||||
return (SCREEN_REDRAW_BORDER_RIGHT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Top/bottom borders. */
|
/* Top/bottom borders. */
|
||||||
if (pane_status == PANE_STATUS_OFF) {
|
if (vsplit && pane_status == PANE_STATUS_OFF && sb_w == 0) {
|
||||||
if (screen_redraw_two_panes(wp->window, 1) && split) {
|
if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2)
|
||||||
if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2)
|
return (SCREEN_REDRAW_BORDER_BOTTOM);
|
||||||
return (SCREEN_REDRAW_BORDER_BOTTOM);
|
if (wp->yoff != 0 && py == wp->yoff - 1 && px > wp->sx / 2)
|
||||||
if (wp->yoff != 0 &&
|
return (SCREEN_REDRAW_BORDER_TOP);
|
||||||
py == wp->yoff - 1 &&
|
} else {
|
||||||
px > wp->sx / 2)
|
if (sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||||
return (SCREEN_REDRAW_BORDER_TOP);
|
if ((wp->xoff - sb_w == 0 || px >= wp->xoff - sb_w) &&
|
||||||
} else {
|
(px <= ex || (sb_w != 0 && px < ex + sb_w))) {
|
||||||
if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
|
if (wp->yoff != 0 && py == wp->yoff - 1)
|
||||||
|
return (SCREEN_REDRAW_BORDER_TOP);
|
||||||
|
if (py == ey)
|
||||||
|
return (SCREEN_REDRAW_BORDER_BOTTOM);
|
||||||
|
}
|
||||||
|
} else { /* sb_pos == PANE_SCROLLBARS_RIGHT */
|
||||||
|
if ((wp->xoff == 0 || px >= wp->xoff) &&
|
||||||
|
(px <= ex || (sb_w != 0 && px < ex + sb_w))) {
|
||||||
if (wp->yoff != 0 && py == wp->yoff - 1)
|
if (wp->yoff != 0 && py == wp->yoff - 1)
|
||||||
return (SCREEN_REDRAW_BORDER_TOP);
|
return (SCREEN_REDRAW_BORDER_TOP);
|
||||||
if (py == ey)
|
if (py == ey)
|
||||||
return (SCREEN_REDRAW_BORDER_BOTTOM);
|
return (SCREEN_REDRAW_BORDER_BOTTOM);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if (pane_status == PANE_STATUS_TOP) {
|
|
||||||
if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
|
|
||||||
if (wp->yoff != 0 && py == wp->yoff - 1)
|
|
||||||
return (SCREEN_REDRAW_BORDER_TOP);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
|
|
||||||
if (py == ey)
|
|
||||||
return (SCREEN_REDRAW_BORDER_BOTTOM);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,13 +212,17 @@ screen_redraw_cell_border(struct screen_redraw_ctx *ctx, u_int px, u_int py)
|
|||||||
struct client *c = ctx->c;
|
struct client *c = ctx->c;
|
||||||
struct window *w = c->session->curw->window;
|
struct window *w = c->session->curw->window;
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
|
u_int sy = w->sy;
|
||||||
|
|
||||||
|
if (ctx->pane_status == PANE_STATUS_BOTTOM)
|
||||||
|
sy--;
|
||||||
|
|
||||||
/* Outside the window? */
|
/* Outside the window? */
|
||||||
if (px > w->sx || py > w->sy)
|
if (px > w->sx || py > sy)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
/* On the window border? */
|
/* On the window border? */
|
||||||
if (px == w->sx || py == w->sy)
|
if (px == w->sx || py == sy)
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
/* Check all the panes. */
|
/* Check all the panes. */
|
||||||
@ -231,13 +252,20 @@ screen_redraw_type_of_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py)
|
|||||||
u_int sx = w->sx, sy = w->sy;
|
u_int sx = w->sx, sy = w->sy;
|
||||||
int borders = 0;
|
int borders = 0;
|
||||||
|
|
||||||
|
if (pane_status == PANE_STATUS_BOTTOM)
|
||||||
|
sy--;
|
||||||
|
|
||||||
/* Is this outside the window? */
|
/* Is this outside the window? */
|
||||||
if (px > sx || py > sy)
|
if (px > sx || py > sy)
|
||||||
return (CELL_OUTSIDE);
|
return (CELL_OUTSIDE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Construct a bitmask of whether the cells to the left (bit 4), right,
|
* Construct a bitmask of whether the cells to the left (bit 8), right,
|
||||||
* top, and bottom (bit 1) of this cell are borders.
|
* top, and bottom (bit 1) of this cell are borders.
|
||||||
|
*
|
||||||
|
* bits 8 4 2 1: 2
|
||||||
|
* 8 + 4
|
||||||
|
* 1
|
||||||
*/
|
*/
|
||||||
if (px == 0 || screen_redraw_cell_border(ctx, px - 1, py))
|
if (px == 0 || screen_redraw_cell_border(ctx, px - 1, py))
|
||||||
borders |= 8;
|
borders |= 8;
|
||||||
@ -253,7 +281,7 @@ screen_redraw_type_of_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py)
|
|||||||
if (py == 0 ||
|
if (py == 0 ||
|
||||||
screen_redraw_cell_border(ctx, px, py - 1))
|
screen_redraw_cell_border(ctx, px, py - 1))
|
||||||
borders |= 2;
|
borders |= 2;
|
||||||
if (py != sy - 1 &&
|
if (py != sy &&
|
||||||
screen_redraw_cell_border(ctx, px, py + 1))
|
screen_redraw_cell_border(ctx, px, py + 1))
|
||||||
borders |= 1;
|
borders |= 1;
|
||||||
} else {
|
} else {
|
||||||
@ -305,14 +333,17 @@ screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py,
|
|||||||
struct window *w = c->session->curw->window;
|
struct window *w = c->session->curw->window;
|
||||||
struct window_pane *wp, *active;
|
struct window_pane *wp, *active;
|
||||||
int pane_status = ctx->pane_status;
|
int pane_status = ctx->pane_status;
|
||||||
int border;
|
u_int sx = w->sx, sy = w->sy;
|
||||||
|
int border, pane_scrollbars = ctx->pane_scrollbars;
|
||||||
u_int right, line;
|
u_int right, line;
|
||||||
|
int sb_pos = ctx->pane_scrollbars_pos;
|
||||||
|
int sb_w;
|
||||||
|
|
||||||
*wpp = NULL;
|
*wpp = NULL;
|
||||||
|
|
||||||
if (px > w->sx || py > w->sy)
|
if (px > sx || py > sy)
|
||||||
return (CELL_OUTSIDE);
|
return (CELL_OUTSIDE);
|
||||||
if (px == w->sx || py == w->sy) /* window border */
|
if (px == sx || py == sy) /* window border */
|
||||||
return (screen_redraw_type_of_cell(ctx, px, py));
|
return (screen_redraw_type_of_cell(ctx, px, py));
|
||||||
|
|
||||||
if (pane_status != PANE_STATUS_OFF) {
|
if (pane_status != PANE_STATUS_OFF) {
|
||||||
@ -324,7 +355,7 @@ screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py,
|
|||||||
if (pane_status == PANE_STATUS_TOP)
|
if (pane_status == PANE_STATUS_TOP)
|
||||||
line = wp->yoff - 1;
|
line = wp->yoff - 1;
|
||||||
else
|
else
|
||||||
line = wp->yoff + wp->sy;
|
line = wp->yoff + sy;
|
||||||
right = wp->xoff + 2 + wp->status_size - 1;
|
right = wp->xoff + 2 + wp->status_size - 1;
|
||||||
|
|
||||||
if (py == line && px >= wp->xoff + 2 && px <= right)
|
if (py == line && px >= wp->xoff + 2 && px <= right)
|
||||||
@ -343,6 +374,35 @@ screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py,
|
|||||||
goto next2;
|
goto next2;
|
||||||
*wpp = wp;
|
*wpp = wp;
|
||||||
|
|
||||||
|
/* Check if CELL_SCROLLBAR */
|
||||||
|
if (window_pane_show_scrollbar(wp, pane_scrollbars)) {
|
||||||
|
|
||||||
|
if (pane_status == PANE_STATUS_TOP)
|
||||||
|
line = wp->yoff - 1;
|
||||||
|
else
|
||||||
|
line = wp->yoff + wp->sy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if py could lie within a scrollbar. If the
|
||||||
|
* pane is at the top then py == 0 to sy; if the pane
|
||||||
|
* is not at the top, then yoff to yoff + sy.
|
||||||
|
*/
|
||||||
|
sb_w = wp->scrollbar_style.width +
|
||||||
|
wp->scrollbar_style.pad;
|
||||||
|
if ((pane_status && py != line) ||
|
||||||
|
(wp->yoff == 0 && py < wp->sy) ||
|
||||||
|
(py >= wp->yoff && py < wp->yoff + wp->sy)) {
|
||||||
|
/* Check if px lies within a scrollbar. */
|
||||||
|
if ((sb_pos == PANE_SCROLLBARS_RIGHT &&
|
||||||
|
(px >= wp->xoff + wp->sx &&
|
||||||
|
px < wp->xoff + wp->sx + sb_w)) ||
|
||||||
|
(sb_pos == PANE_SCROLLBARS_LEFT &&
|
||||||
|
(px >= wp->xoff - sb_w &&
|
||||||
|
px < wp->xoff)))
|
||||||
|
return (CELL_SCROLLBAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If definitely inside, return. If not on border, skip.
|
* If definitely inside, return. If not on border, skip.
|
||||||
* Otherwise work out the cell.
|
* Otherwise work out the cell.
|
||||||
@ -386,11 +446,15 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
|
|||||||
const char *fmt;
|
const char *fmt;
|
||||||
struct format_tree *ft;
|
struct format_tree *ft;
|
||||||
char *expanded;
|
char *expanded;
|
||||||
int pane_status = rctx->pane_status;
|
int pane_status = rctx->pane_status, sb_w = 0;
|
||||||
|
int pane_scrollbars = rctx->pane_scrollbars;
|
||||||
u_int width, i, cell_type, px, py;
|
u_int width, i, cell_type, px, py;
|
||||||
struct screen_write_ctx ctx;
|
struct screen_write_ctx ctx;
|
||||||
struct screen old;
|
struct screen old;
|
||||||
|
|
||||||
|
if (window_pane_show_scrollbar(wp, pane_scrollbars))
|
||||||
|
sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad;
|
||||||
|
|
||||||
ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
|
ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
|
||||||
format_defaults(ft, c, c->session, c->session->curw, wp);
|
format_defaults(ft, c, c->session, c->session->curw, wp);
|
||||||
|
|
||||||
@ -404,7 +468,7 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
|
|||||||
if (wp->sx < 4)
|
if (wp->sx < 4)
|
||||||
wp->status_size = width = 0;
|
wp->status_size = width = 0;
|
||||||
else
|
else
|
||||||
wp->status_size = width = wp->sx - 4;
|
wp->status_size = width = wp->sx + sb_w - 2;
|
||||||
|
|
||||||
memcpy(&old, &wp->status_screen, sizeof old);
|
memcpy(&old, &wp->status_screen, sizeof old);
|
||||||
screen_init(&wp->status_screen, width, 1, 0);
|
screen_init(&wp->status_screen, width, 1, 0);
|
||||||
@ -502,14 +566,13 @@ screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
|
|||||||
|
|
||||||
/* Update status line and change flags if unchanged. */
|
/* Update status line and change flags if unchanged. */
|
||||||
static uint64_t
|
static uint64_t
|
||||||
screen_redraw_update(struct client *c, uint64_t flags)
|
screen_redraw_update(struct screen_redraw_ctx *ctx, uint64_t flags)
|
||||||
{
|
{
|
||||||
|
struct client *c = ctx->c;
|
||||||
struct window *w = c->session->curw->window;
|
struct window *w = c->session->curw->window;
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
struct options *wo = w->options;
|
|
||||||
int redraw;
|
int redraw;
|
||||||
enum pane_lines lines;
|
enum pane_lines lines;
|
||||||
struct screen_redraw_ctx ctx;
|
|
||||||
|
|
||||||
if (c->message_string != NULL)
|
if (c->message_string != NULL)
|
||||||
redraw = status_message_redraw(c);
|
redraw = status_message_redraw(c);
|
||||||
@ -523,17 +586,17 @@ screen_redraw_update(struct client *c, uint64_t flags)
|
|||||||
if (c->overlay_draw != NULL)
|
if (c->overlay_draw != NULL)
|
||||||
flags |= CLIENT_REDRAWOVERLAY;
|
flags |= CLIENT_REDRAWOVERLAY;
|
||||||
|
|
||||||
if (options_get_number(wo, "pane-border-status") != PANE_STATUS_OFF) {
|
if (ctx->pane_status != PANE_STATUS_OFF) {
|
||||||
screen_redraw_set_context(c, &ctx);
|
lines = ctx->pane_lines;
|
||||||
lines = options_get_number(wo, "pane-border-lines");
|
|
||||||
redraw = 0;
|
redraw = 0;
|
||||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||||
if (screen_redraw_make_pane_status(c, wp, &ctx, lines))
|
if (screen_redraw_make_pane_status(c, wp, ctx, lines))
|
||||||
redraw = 1;
|
redraw = 1;
|
||||||
}
|
}
|
||||||
if (redraw)
|
if (redraw)
|
||||||
flags |= CLIENT_REDRAWBORDERS;
|
flags |= CLIENT_REDRAWBORDERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (flags);
|
return (flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -560,6 +623,10 @@ screen_redraw_set_context(struct client *c, struct screen_redraw_ctx *ctx)
|
|||||||
ctx->pane_status = options_get_number(wo, "pane-border-status");
|
ctx->pane_status = options_get_number(wo, "pane-border-status");
|
||||||
ctx->pane_lines = options_get_number(wo, "pane-border-lines");
|
ctx->pane_lines = options_get_number(wo, "pane-border-lines");
|
||||||
|
|
||||||
|
ctx->pane_scrollbars = options_get_number(wo, "pane-scrollbars");
|
||||||
|
ctx->pane_scrollbars_pos = options_get_number(wo,
|
||||||
|
"pane-scrollbars-position");
|
||||||
|
|
||||||
tty_window_offset(&c->tty, &ctx->ox, &ctx->oy, &ctx->sx, &ctx->sy);
|
tty_window_offset(&c->tty, &ctx->ox, &ctx->oy, &ctx->sx, &ctx->sy);
|
||||||
|
|
||||||
log_debug("%s: %s @%u ox=%u oy=%u sx=%u sy=%u %u/%d", __func__, c->name,
|
log_debug("%s: %s @%u ox=%u oy=%u sx=%u sy=%u %u/%d", __func__, c->name,
|
||||||
@ -577,23 +644,26 @@ screen_redraw_screen(struct client *c)
|
|||||||
if (c->flags & CLIENT_SUSPENDED)
|
if (c->flags & CLIENT_SUSPENDED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
flags = screen_redraw_update(c, c->flags);
|
screen_redraw_set_context(c, &ctx);
|
||||||
|
|
||||||
|
flags = screen_redraw_update(&ctx, c->flags);
|
||||||
if ((flags & CLIENT_ALLREDRAWFLAGS) == 0)
|
if ((flags & CLIENT_ALLREDRAWFLAGS) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
screen_redraw_set_context(c, &ctx);
|
|
||||||
tty_sync_start(&c->tty);
|
tty_sync_start(&c->tty);
|
||||||
tty_update_mode(&c->tty, c->tty.mode, NULL);
|
tty_update_mode(&c->tty, c->tty.mode, NULL);
|
||||||
|
|
||||||
if (flags & (CLIENT_REDRAWWINDOW|CLIENT_REDRAWBORDERS)) {
|
if (flags & (CLIENT_REDRAWWINDOW|CLIENT_REDRAWBORDERS)) {
|
||||||
log_debug("%s: redrawing borders", c->name);
|
log_debug("%s: redrawing borders", c->name);
|
||||||
|
screen_redraw_draw_borders(&ctx);
|
||||||
if (ctx.pane_status != PANE_STATUS_OFF)
|
if (ctx.pane_status != PANE_STATUS_OFF)
|
||||||
screen_redraw_draw_pane_status(&ctx);
|
screen_redraw_draw_pane_status(&ctx);
|
||||||
screen_redraw_draw_borders(&ctx);
|
screen_redraw_draw_pane_scrollbars(&ctx);
|
||||||
}
|
}
|
||||||
if (flags & CLIENT_REDRAWWINDOW) {
|
if (flags & CLIENT_REDRAWWINDOW) {
|
||||||
log_debug("%s: redrawing panes", c->name);
|
log_debug("%s: redrawing panes", c->name);
|
||||||
screen_redraw_draw_panes(&ctx);
|
screen_redraw_draw_panes(&ctx);
|
||||||
|
screen_redraw_draw_pane_scrollbars(&ctx);
|
||||||
}
|
}
|
||||||
if (ctx.statuslines != 0 &&
|
if (ctx.statuslines != 0 &&
|
||||||
(flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS))) {
|
(flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS))) {
|
||||||
@ -608,11 +678,12 @@ screen_redraw_screen(struct client *c)
|
|||||||
tty_reset(&c->tty);
|
tty_reset(&c->tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Redraw a single pane. */
|
/* Redraw a single pane and its scrollbar. */
|
||||||
void
|
void
|
||||||
screen_redraw_pane(struct client *c, struct window_pane *wp)
|
screen_redraw_pane(struct client *c, struct window_pane *wp,
|
||||||
|
int redraw_scrollbar_only)
|
||||||
{
|
{
|
||||||
struct screen_redraw_ctx ctx;
|
struct screen_redraw_ctx ctx;
|
||||||
|
|
||||||
if (!window_pane_visible(wp))
|
if (!window_pane_visible(wp))
|
||||||
return;
|
return;
|
||||||
@ -621,7 +692,11 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
|
|||||||
tty_sync_start(&c->tty);
|
tty_sync_start(&c->tty);
|
||||||
tty_update_mode(&c->tty, c->tty.mode, NULL);
|
tty_update_mode(&c->tty, c->tty.mode, NULL);
|
||||||
|
|
||||||
screen_redraw_draw_pane(&ctx, wp);
|
if (!redraw_scrollbar_only)
|
||||||
|
screen_redraw_draw_pane(&ctx, wp);
|
||||||
|
|
||||||
|
if (window_pane_show_scrollbar(wp, ctx.pane_scrollbars))
|
||||||
|
screen_redraw_draw_pane_scrollbar(&ctx, wp);
|
||||||
|
|
||||||
tty_reset(&c->tty);
|
tty_reset(&c->tty);
|
||||||
}
|
}
|
||||||
@ -667,8 +742,7 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
|
|||||||
const struct grid_cell *tmp;
|
const struct grid_cell *tmp;
|
||||||
struct overlay_ranges r;
|
struct overlay_ranges r;
|
||||||
u_int cell_type, x = ctx->ox + i, y = ctx->oy + j;
|
u_int cell_type, x = ctx->ox + i, y = ctx->oy + j;
|
||||||
int arrows = 0, border;
|
int arrows = 0, border, isolates;
|
||||||
int isolates;
|
|
||||||
|
|
||||||
if (c->overlay_check != NULL) {
|
if (c->overlay_check != NULL) {
|
||||||
c->overlay_check(c, c->overlay_data, x, y, 1, &r);
|
c->overlay_check(c, c->overlay_data, x, y, 1, &r);
|
||||||
@ -677,7 +751,7 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cell_type = screen_redraw_check_cell(ctx, x, y, &wp);
|
cell_type = screen_redraw_check_cell(ctx, x, y, &wp);
|
||||||
if (cell_type == CELL_INSIDE)
|
if (cell_type == CELL_INSIDE || cell_type == CELL_SCROLLBAR)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (wp == NULL) {
|
if (wp == NULL) {
|
||||||
@ -866,3 +940,127 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
|
|||||||
tty_draw_images(c, wp, s);
|
tty_draw_images(c, wp, s);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Draw the panes scrollbars */
|
||||||
|
static void
|
||||||
|
screen_redraw_draw_pane_scrollbars(struct screen_redraw_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct client *c = ctx->c;
|
||||||
|
struct window *w = c->session->curw->window;
|
||||||
|
struct window_pane *wp;
|
||||||
|
|
||||||
|
log_debug("%s: %s @%u", __func__, c->name, w->id);
|
||||||
|
|
||||||
|
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||||
|
if (window_pane_show_scrollbar(wp, ctx->pane_scrollbars) &&
|
||||||
|
window_pane_visible(wp))
|
||||||
|
screen_redraw_draw_pane_scrollbar(ctx, wp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw pane scrollbar. */
|
||||||
|
void
|
||||||
|
screen_redraw_draw_pane_scrollbar(struct screen_redraw_ctx *ctx,
|
||||||
|
struct window_pane *wp)
|
||||||
|
{
|
||||||
|
struct screen *s = wp->screen;
|
||||||
|
double percent_view;
|
||||||
|
u_int sb = ctx->pane_scrollbars, total_height, sb_h = wp->sy;
|
||||||
|
u_int sb_pos = ctx->pane_scrollbars_pos, slider_h, slider_y;
|
||||||
|
int sb_w = wp->scrollbar_style.width;
|
||||||
|
int sb_pad = wp->scrollbar_style.pad;
|
||||||
|
int cm_y, cm_size, xoff = wp->xoff, ox = ctx->ox;
|
||||||
|
int sb_x, sb_y = (int)(wp->yoff - ctx->oy); /* sb top */
|
||||||
|
|
||||||
|
if (window_pane_mode(wp) == WINDOW_PANE_NO_MODE) {
|
||||||
|
if (sb == PANE_SCROLLBARS_MODAL)
|
||||||
|
return;
|
||||||
|
/* Show slider at the bottom of the scrollbar. */
|
||||||
|
total_height = screen_size_y(s) + screen_hsize(s);
|
||||||
|
percent_view = (double)sb_h / total_height;
|
||||||
|
slider_h = (double)sb_h * percent_view;
|
||||||
|
slider_y = sb_h - slider_h;
|
||||||
|
} else {
|
||||||
|
if (TAILQ_FIRST(&wp->modes) == NULL)
|
||||||
|
return;
|
||||||
|
if (window_copy_get_current_offset(wp, &cm_y, &cm_size) == 0)
|
||||||
|
return;
|
||||||
|
total_height = cm_size + sb_h;
|
||||||
|
percent_view = (double)sb_h / (cm_size + sb_h);
|
||||||
|
slider_h = (double)sb_h * percent_view;
|
||||||
|
slider_y = (sb_h + 1) * ((double)cm_y / total_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sb_pos == PANE_SCROLLBARS_LEFT)
|
||||||
|
sb_x = xoff - sb_w - sb_pad - ox;
|
||||||
|
else
|
||||||
|
sb_x = xoff + wp->sx - ox;
|
||||||
|
|
||||||
|
if (slider_h < 1)
|
||||||
|
slider_h = 1;
|
||||||
|
if (slider_y >= sb_h)
|
||||||
|
slider_y = sb_h - 1;
|
||||||
|
|
||||||
|
screen_redraw_draw_scrollbar(ctx, wp, sb_pos, sb_x, sb_y, sb_h,
|
||||||
|
slider_h, slider_y);
|
||||||
|
|
||||||
|
/* Store current position and height of the slider */
|
||||||
|
wp->sb_slider_y = slider_y; /* top of slider y pos in scrollbar */
|
||||||
|
wp->sb_slider_h = slider_h; /* height of slider */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx,
|
||||||
|
struct window_pane *wp, int sb_pos, int sb_x, int sb_y, u_int sb_h,
|
||||||
|
u_int slider_h, u_int slider_y)
|
||||||
|
{
|
||||||
|
struct client *c = ctx->c;
|
||||||
|
struct tty *tty = &c->tty;
|
||||||
|
struct grid_cell gc, slgc, *gcp;
|
||||||
|
struct style *sb_style = &wp->scrollbar_style;
|
||||||
|
u_int i, j, imax, jmax;
|
||||||
|
u_int sb_w = sb_style->width, sb_pad = sb_style->pad;
|
||||||
|
int px, py, ox = ctx->ox, oy = ctx->oy;
|
||||||
|
int sx = ctx->sx, sy = ctx->sy, xoff = wp->xoff;
|
||||||
|
int yoff = wp->yoff;
|
||||||
|
|
||||||
|
/* Set up style for slider. */
|
||||||
|
gc = sb_style->gc;
|
||||||
|
memcpy(&slgc, &gc, sizeof slgc);
|
||||||
|
slgc.fg = gc.bg;
|
||||||
|
slgc.bg = gc.fg;
|
||||||
|
|
||||||
|
imax = sb_w + sb_pad;
|
||||||
|
if ((int)imax + sb_x > sx)
|
||||||
|
imax = sx - sb_x;
|
||||||
|
jmax = sb_h;
|
||||||
|
if ((int)jmax + sb_y > sy)
|
||||||
|
jmax = sy - sb_y;
|
||||||
|
|
||||||
|
for (j = 0; j < jmax; j++) {
|
||||||
|
py = sb_y + j;
|
||||||
|
for (i = 0; i < imax; i++) {
|
||||||
|
px = sb_x + i;
|
||||||
|
if (px < xoff - ox - (int)sb_w - (int)sb_pad ||
|
||||||
|
px >= sx || px < 0 ||
|
||||||
|
py < yoff - oy - 1 ||
|
||||||
|
py >= sy || py < 0)
|
||||||
|
continue;
|
||||||
|
tty_cursor(tty, px, py);
|
||||||
|
if ((sb_pos == PANE_SCROLLBARS_LEFT &&
|
||||||
|
i >= sb_w && i < sb_w + sb_pad) ||
|
||||||
|
(sb_pos == PANE_SCROLLBARS_RIGHT &&
|
||||||
|
i < sb_pad)) {
|
||||||
|
tty_cell(tty, &grid_default_cell,
|
||||||
|
&grid_default_cell, NULL, NULL);
|
||||||
|
} else {
|
||||||
|
if (j >= slider_y && j < slider_y + slider_h)
|
||||||
|
gcp = &slgc;
|
||||||
|
else
|
||||||
|
gcp = &gc;
|
||||||
|
tty_cell(tty, gcp, &grid_default_cell, NULL,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -151,7 +151,7 @@ screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
|
|||||||
*/
|
*/
|
||||||
log_debug("%s: adding %%%u to deferred redraw", __func__,
|
log_debug("%s: adding %%%u to deferred redraw", __func__,
|
||||||
wp->id);
|
wp->id);
|
||||||
wp->flags |= PANE_REDRAW;
|
wp->flags |= (PANE_REDRAW|PANE_REDRAWSCROLLBAR);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,7 +377,7 @@ screen_write_strlen(const char *fmt, ...)
|
|||||||
if (more == UTF8_DONE)
|
if (more == UTF8_DONE)
|
||||||
size += ud.width;
|
size += ud.width;
|
||||||
} else {
|
} else {
|
||||||
if (*ptr > 0x1f && *ptr < 0x7f)
|
if (*ptr == '\t' || (*ptr > 0x1f && *ptr < 0x7f))
|
||||||
size++;
|
size++;
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
@ -547,7 +547,7 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
|
|||||||
else if (*ptr == '\n') {
|
else if (*ptr == '\n') {
|
||||||
screen_write_linefeed(ctx, 0, 8);
|
screen_write_linefeed(ctx, 0, 8);
|
||||||
screen_write_carriagereturn(ctx);
|
screen_write_carriagereturn(ctx);
|
||||||
} else if (*ptr > 0x1f && *ptr < 0x7f) {
|
} else if (*ptr == '\t' || (*ptr > 0x1f && *ptr < 0x7f)) {
|
||||||
size++;
|
size++;
|
||||||
screen_write_putc(ctx, &gc, *ptr);
|
screen_write_putc(ctx, &gc, *ptr);
|
||||||
}
|
}
|
||||||
@ -567,9 +567,11 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
|
|||||||
u_int px, u_int py, u_int nx, u_int ny)
|
u_int px, u_int py, u_int nx, u_int ny)
|
||||||
{
|
{
|
||||||
struct screen *s = ctx->s;
|
struct screen *s = ctx->s;
|
||||||
|
struct window_pane *wp = ctx->wp;
|
||||||
|
struct tty_ctx ttyctx;
|
||||||
struct grid *gd = src->grid;
|
struct grid *gd = src->grid;
|
||||||
struct grid_cell gc;
|
struct grid_cell gc;
|
||||||
u_int xx, yy, cx, cy;
|
u_int xx, yy, cx = s->cx, cy = s->cy;
|
||||||
|
|
||||||
if (nx == 0 || ny == 0)
|
if (nx == 0 || ny == 0)
|
||||||
return;
|
return;
|
||||||
@ -578,18 +580,28 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
|
|||||||
for (yy = py; yy < py + ny; yy++) {
|
for (yy = py; yy < py + ny; yy++) {
|
||||||
if (yy >= gd->hsize + gd->sy)
|
if (yy >= gd->hsize + gd->sy)
|
||||||
break;
|
break;
|
||||||
cx = s->cx;
|
s->cx = cx;
|
||||||
|
if (wp != NULL)
|
||||||
|
screen_write_initctx(ctx, &ttyctx, 0);
|
||||||
for (xx = px; xx < px + nx; xx++) {
|
for (xx = px; xx < px + nx; xx++) {
|
||||||
if (xx >= grid_get_line(gd, 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)
|
||||||
break;
|
break;
|
||||||
grid_view_set_cell(ctx->s->grid, cx, cy, &gc);
|
grid_view_set_cell(ctx->s->grid, s->cx, s->cy, &gc);
|
||||||
cx++;
|
if (wp != NULL) {
|
||||||
|
ttyctx.cell = &gc;
|
||||||
|
tty_write(tty_cmd_cell, &ttyctx);
|
||||||
|
ttyctx.ocx++;
|
||||||
|
}
|
||||||
|
s->cx++;
|
||||||
}
|
}
|
||||||
cy++;
|
s->cy++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s->cx = cx;
|
||||||
|
s->cy = cy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Select character set for drawing border lines. */
|
/* Select character set for drawing border lines. */
|
||||||
@ -1780,6 +1792,9 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only,
|
|||||||
ttyctx.num = ctx->scrolled;
|
ttyctx.num = ctx->scrolled;
|
||||||
ttyctx.bg = ctx->bg;
|
ttyctx.bg = ctx->bg;
|
||||||
tty_write(tty_cmd_scrollup, &ttyctx);
|
tty_write(tty_cmd_scrollup, &ttyctx);
|
||||||
|
|
||||||
|
if (ctx->wp != NULL)
|
||||||
|
ctx->wp->flags |= PANE_REDRAWSCROLLBAR;
|
||||||
}
|
}
|
||||||
ctx->scrolled = 0;
|
ctx->scrolled = 0;
|
||||||
ctx->bg = 8;
|
ctx->bg = 8;
|
||||||
@ -1899,6 +1914,8 @@ screen_write_collect_add(struct screen_write_ctx *ctx,
|
|||||||
collect = 1;
|
collect = 1;
|
||||||
if (gc->data.width != 1 || gc->data.size != 1 || *gc->data.data >= 0x7f)
|
if (gc->data.width != 1 || gc->data.size != 1 || *gc->data.data >= 0x7f)
|
||||||
collect = 0;
|
collect = 0;
|
||||||
|
else if (gc->flags & GRID_FLAG_TAB)
|
||||||
|
collect = 0;
|
||||||
else if (gc->attr & GRID_ATTR_CHARSET)
|
else if (gc->attr & GRID_ATTR_CHARSET)
|
||||||
collect = 0;
|
collect = 0;
|
||||||
else if (~s->mode & MODE_WRAP)
|
else if (~s->mode & MODE_WRAP)
|
||||||
@ -2088,9 +2105,11 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc)
|
|||||||
*/
|
*/
|
||||||
if (utf8_is_zwj(ud))
|
if (utf8_is_zwj(ud))
|
||||||
zero_width = 1;
|
zero_width = 1;
|
||||||
else if (utf8_is_vs(ud))
|
else if (utf8_is_vs(ud)) {
|
||||||
zero_width = force_wide = 1;
|
zero_width = 1;
|
||||||
else if (ud->width == 0)
|
if (options_get_number(global_options, "variation-selector-always-wide"))
|
||||||
|
force_wide = 1;
|
||||||
|
} else if (ud->width == 0)
|
||||||
zero_width = 1;
|
zero_width = 1;
|
||||||
|
|
||||||
/* Cannot combine empty character or at left. */
|
/* Cannot combine empty character or at left. */
|
||||||
@ -2221,7 +2240,17 @@ screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc,
|
|||||||
break;
|
break;
|
||||||
log_debug("%s: overwrite at %u,%u", __func__, xx,
|
log_debug("%s: overwrite at %u,%u", __func__, xx,
|
||||||
s->cy);
|
s->cy);
|
||||||
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
|
if (gc->flags & GRID_FLAG_TAB) {
|
||||||
|
memcpy(&tmp_gc, gc, sizeof tmp_gc);
|
||||||
|
memset(tmp_gc.data.data, 0,
|
||||||
|
sizeof tmp_gc.data.data);
|
||||||
|
*tmp_gc.data.data = ' ';
|
||||||
|
tmp_gc.data.width = tmp_gc.data.size =
|
||||||
|
tmp_gc.data.have = 1;
|
||||||
|
grid_view_set_cell(gd, xx, s->cy, &tmp_gc);
|
||||||
|
} else
|
||||||
|
grid_view_set_cell(gd, xx, s->cy,
|
||||||
|
&grid_default_cell);
|
||||||
done = 1;
|
done = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2332,6 +2361,9 @@ screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc,
|
|||||||
screen_write_collect_flush(ctx, 0, __func__);
|
screen_write_collect_flush(ctx, 0, __func__);
|
||||||
screen_alternate_on(ctx->s, gc, cursor);
|
screen_alternate_on(ctx->s, gc, cursor);
|
||||||
|
|
||||||
|
if (wp != NULL)
|
||||||
|
layout_fix_panes(wp->window, NULL);
|
||||||
|
|
||||||
screen_write_initctx(ctx, &ttyctx, 1);
|
screen_write_initctx(ctx, &ttyctx, 1);
|
||||||
if (ttyctx.redraw_cb != NULL)
|
if (ttyctx.redraw_cb != NULL)
|
||||||
ttyctx.redraw_cb(&ttyctx);
|
ttyctx.redraw_cb(&ttyctx);
|
||||||
@ -2351,6 +2383,9 @@ screen_write_alternateoff(struct screen_write_ctx *ctx, struct grid_cell *gc,
|
|||||||
screen_write_collect_flush(ctx, 0, __func__);
|
screen_write_collect_flush(ctx, 0, __func__);
|
||||||
screen_alternate_off(ctx->s, gc, cursor);
|
screen_alternate_off(ctx->s, gc, cursor);
|
||||||
|
|
||||||
|
if (wp != NULL)
|
||||||
|
layout_fix_panes(wp->window, NULL);
|
||||||
|
|
||||||
screen_write_initctx(ctx, &ttyctx, 1);
|
screen_write_initctx(ctx, &ttyctx, 1);
|
||||||
if (ttyctx.redraw_cb != NULL)
|
if (ttyctx.redraw_cb != NULL)
|
||||||
ttyctx.redraw_cb(&ttyctx);
|
ttyctx.redraw_cb(&ttyctx);
|
||||||
|
32
screen.c
32
screen.c
@ -114,7 +114,7 @@ screen_reinit(struct screen *s)
|
|||||||
if (options_get_number(global_options, "extended-keys") == 2)
|
if (options_get_number(global_options, "extended-keys") == 2)
|
||||||
s->mode = (s->mode & ~EXTENDED_KEY_MODES)|MODE_KEYS_EXTENDED;
|
s->mode = (s->mode & ~EXTENDED_KEY_MODES)|MODE_KEYS_EXTENDED;
|
||||||
|
|
||||||
if (s->saved_grid != NULL)
|
if (SCREEN_IS_ALTERNATE(s))
|
||||||
screen_alternate_off(s, NULL, 0);
|
screen_alternate_off(s, NULL, 0);
|
||||||
s->saved_cx = UINT_MAX;
|
s->saved_cx = UINT_MAX;
|
||||||
s->saved_cy = UINT_MAX;
|
s->saved_cy = UINT_MAX;
|
||||||
@ -155,7 +155,7 @@ screen_free(struct screen *s)
|
|||||||
if (s->write_list != NULL)
|
if (s->write_list != NULL)
|
||||||
screen_write_free_list(s);
|
screen_write_free_list(s);
|
||||||
|
|
||||||
if (s->saved_grid != NULL)
|
if (SCREEN_IS_ALTERNATE(s))
|
||||||
grid_destroy(s->saved_grid);
|
grid_destroy(s->saved_grid);
|
||||||
grid_destroy(s->grid);
|
grid_destroy(s->grid);
|
||||||
|
|
||||||
@ -182,6 +182,20 @@ screen_reset_tabs(struct screen *s)
|
|||||||
bit_set(s->tabs, i);
|
bit_set(s->tabs, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set default cursor style and colour from options. */
|
||||||
|
void
|
||||||
|
screen_set_default_cursor(struct screen *s, struct options *oo)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
c = options_get_number(oo, "cursor-colour");
|
||||||
|
s->default_ccolour = c;
|
||||||
|
|
||||||
|
c = options_get_number(oo, "cursor-style");
|
||||||
|
s->default_mode = 0;
|
||||||
|
screen_set_cursor_style(c, &s->default_cstyle, &s->default_mode);
|
||||||
|
}
|
||||||
|
|
||||||
/* Set screen cursor style and mode. */
|
/* Set screen cursor style and mode. */
|
||||||
void
|
void
|
||||||
screen_set_cursor_style(u_int style, enum screen_cursor_style *cstyle,
|
screen_set_cursor_style(u_int style, enum screen_cursor_style *cstyle,
|
||||||
@ -574,10 +588,12 @@ screen_select_cell(struct screen *s, struct grid_cell *dst,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
memcpy(dst, &s->sel->cell, sizeof *dst);
|
memcpy(dst, &s->sel->cell, sizeof *dst);
|
||||||
|
if (COLOUR_DEFAULT(dst->fg))
|
||||||
|
dst->fg = src->fg;
|
||||||
|
if (COLOUR_DEFAULT(dst->bg))
|
||||||
|
dst->bg = src->bg;
|
||||||
utf8_copy(&dst->data, &src->data);
|
utf8_copy(&dst->data, &src->data);
|
||||||
dst->attr = dst->attr & ~GRID_ATTR_CHARSET;
|
dst->attr = src->attr;
|
||||||
dst->attr |= src->attr & GRID_ATTR_CHARSET;
|
|
||||||
dst->flags = src->flags;
|
dst->flags = src->flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,7 +630,7 @@ screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor)
|
|||||||
{
|
{
|
||||||
u_int sx, sy;
|
u_int sx, sy;
|
||||||
|
|
||||||
if (s->saved_grid != NULL)
|
if (SCREEN_IS_ALTERNATE(s))
|
||||||
return;
|
return;
|
||||||
sx = screen_size_x(s);
|
sx = screen_size_x(s);
|
||||||
sy = screen_size_y(s);
|
sy = screen_size_y(s);
|
||||||
@ -643,7 +659,7 @@ screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor)
|
|||||||
* If the current size is different, temporarily resize to the old size
|
* If the current size is different, temporarily resize to the old size
|
||||||
* before copying back.
|
* before copying back.
|
||||||
*/
|
*/
|
||||||
if (s->saved_grid != NULL)
|
if (SCREEN_IS_ALTERNATE(s))
|
||||||
screen_resize(s, s->saved_grid->sx, s->saved_grid->sy, 0);
|
screen_resize(s, s->saved_grid->sx, s->saved_grid->sy, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -658,7 +674,7 @@ screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If not in the alternate screen, do nothing more. */
|
/* If not in the alternate screen, do nothing more. */
|
||||||
if (s->saved_grid == NULL) {
|
if (!SCREEN_IS_ALTERNATE(s)) {
|
||||||
if (s->cx > screen_size_x(s) - 1)
|
if (s->cx > screen_size_x(s) - 1)
|
||||||
s->cx = screen_size_x(s) - 1;
|
s->cx = screen_size_x(s) - 1;
|
||||||
if (s->cy > screen_size_y(s) - 1)
|
if (s->cy > screen_size_y(s) - 1)
|
||||||
|
815
server-client.c
815
server-client.c
File diff suppressed because it is too large
Load Diff
21
server-fn.c
21
server-fn.c
@ -426,7 +426,7 @@ void
|
|||||||
server_destroy_session(struct session *s)
|
server_destroy_session(struct session *s)
|
||||||
{
|
{
|
||||||
struct client *c;
|
struct client *c;
|
||||||
struct session *s_new = NULL;
|
struct session *s_new = NULL, *cs_new, *use_s;
|
||||||
int detach_on_destroy;
|
int detach_on_destroy;
|
||||||
|
|
||||||
detach_on_destroy = options_get_number(s->options, "detach-on-destroy");
|
detach_on_destroy = options_get_number(s->options, "detach-on-destroy");
|
||||||
@ -438,15 +438,26 @@ server_destroy_session(struct session *s)
|
|||||||
s_new = session_previous_session(s);
|
s_new = session_previous_session(s);
|
||||||
else if (detach_on_destroy == 4)
|
else if (detach_on_destroy == 4)
|
||||||
s_new = session_next_session(s);
|
s_new = session_next_session(s);
|
||||||
if (s_new == s)
|
|
||||||
s_new = NULL;
|
/*
|
||||||
|
* If no suitable new session was found above, then look for any
|
||||||
|
* session as an alternative in case a client needs it.
|
||||||
|
*/
|
||||||
|
if (s_new == NULL &&
|
||||||
|
(detach_on_destroy == 1 || detach_on_destroy == 2))
|
||||||
|
cs_new = server_find_session(s, server_newer_session);
|
||||||
|
|
||||||
TAILQ_FOREACH(c, &clients, entry) {
|
TAILQ_FOREACH(c, &clients, entry) {
|
||||||
if (c->session != s)
|
if (c->session != s)
|
||||||
continue;
|
continue;
|
||||||
|
use_s = s_new;
|
||||||
|
if (use_s == NULL && (c->flags & CLIENT_NO_DETACH_ON_DESTROY))
|
||||||
|
use_s = cs_new;
|
||||||
|
|
||||||
c->session = NULL;
|
c->session = NULL;
|
||||||
c->last_session = NULL;
|
c->last_session = NULL;
|
||||||
server_client_set_session(c, s_new);
|
server_client_set_session(c, use_s);
|
||||||
if (s_new == NULL)
|
if (use_s == NULL)
|
||||||
c->flags |= CLIENT_EXIT;
|
c->flags |= CLIENT_EXIT;
|
||||||
}
|
}
|
||||||
recalculate_sizes();
|
recalculate_sizes();
|
||||||
|
1
server.c
1
server.c
@ -207,6 +207,7 @@ server_start(struct tmuxproc *client, uint64_t flags, struct event_base *base,
|
|||||||
fatal("pledge failed");
|
fatal("pledge failed");
|
||||||
|
|
||||||
input_key_build();
|
input_key_build();
|
||||||
|
utf8_update_width_cache();
|
||||||
RB_INIT(&windows);
|
RB_INIT(&windows);
|
||||||
RB_INIT(&all_window_panes);
|
RB_INIT(&all_window_panes);
|
||||||
TAILQ_INIT(&clients);
|
TAILQ_INIT(&clients);
|
||||||
|
31
session.c
31
session.c
@ -31,12 +31,9 @@ u_int next_session_id;
|
|||||||
struct session_groups session_groups = RB_INITIALIZER(&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 *);
|
||||||
|
|
||||||
static void session_lock_timer(int, short, void *);
|
static void session_lock_timer(int, short, void *);
|
||||||
|
|
||||||
static struct winlink *session_next_alert(struct winlink *);
|
static struct winlink *session_next_alert(struct winlink *);
|
||||||
static struct winlink *session_previous_alert(struct winlink *);
|
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 *);
|
||||||
|
|
||||||
@ -47,12 +44,12 @@ session_cmp(struct session *s1, struct session *s2)
|
|||||||
}
|
}
|
||||||
RB_GENERATE(sessions, session, entry, session_cmp);
|
RB_GENERATE(sessions, session, entry, session_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);
|
RB_GENERATE(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
|
||||||
@ -270,19 +267,16 @@ session_lock_timer(__unused int fd, __unused short events, void *arg)
|
|||||||
void
|
void
|
||||||
session_update_activity(struct session *s, struct timeval *from)
|
session_update_activity(struct session *s, struct timeval *from)
|
||||||
{
|
{
|
||||||
struct timeval *last = &s->last_activity_time;
|
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
memcpy(last, &s->activity_time, sizeof *last);
|
|
||||||
if (from == NULL)
|
if (from == NULL)
|
||||||
gettimeofday(&s->activity_time, NULL);
|
gettimeofday(&s->activity_time, NULL);
|
||||||
else
|
else
|
||||||
memcpy(&s->activity_time, from, sizeof s->activity_time);
|
memcpy(&s->activity_time, from, sizeof s->activity_time);
|
||||||
|
|
||||||
log_debug("session $%u %s activity %lld.%06d (last %lld.%06d)", s->id,
|
log_debug("session $%u %s activity %lld.%06d", s->id,
|
||||||
s->name, (long long)s->activity_time.tv_sec,
|
s->name, (long long)s->activity_time.tv_sec,
|
||||||
(int)s->activity_time.tv_usec, (long long)last->tv_sec,
|
(int)s->activity_time.tv_usec);
|
||||||
(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);
|
||||||
@ -367,7 +361,7 @@ session_detach(struct session *s, struct winlink *wl)
|
|||||||
|
|
||||||
if (RB_EMPTY(&s->windows))
|
if (RB_EMPTY(&s->windows))
|
||||||
return (1);
|
return (1);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return if session has window. */
|
/* Return if session has window. */
|
||||||
@ -757,3 +751,18 @@ session_renumber_windows(struct session *s)
|
|||||||
RB_FOREACH_SAFE(wl, winlinks, &old_wins, wl1)
|
RB_FOREACH_SAFE(wl, winlinks, &old_wins, wl1)
|
||||||
winlink_remove(&old_wins, wl);
|
winlink_remove(&old_wins, wl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set the PANE_THEMECHANGED flag for every pane in this session. */
|
||||||
|
void
|
||||||
|
session_theme_changed(struct session *s)
|
||||||
|
{
|
||||||
|
struct window_pane *wp;
|
||||||
|
struct winlink *wl;
|
||||||
|
|
||||||
|
if (s != NULL) {
|
||||||
|
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||||
|
TAILQ_FOREACH(wp, &wl->window->panes, entry)
|
||||||
|
wp->flags |= PANE_THEMECHANGED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
26
spawn.c
26
spawn.c
@ -229,8 +229,9 @@ spawn_pane(struct spawn_context *sc, char **cause)
|
|||||||
if (sc->cwd != NULL) {
|
if (sc->cwd != NULL) {
|
||||||
cwd = format_single(item, sc->cwd, c, target->s, NULL, NULL);
|
cwd = format_single(item, sc->cwd, c, target->s, NULL, NULL);
|
||||||
if (*cwd != '/') {
|
if (*cwd != '/') {
|
||||||
xasprintf(&new_cwd, "%s/%s", server_client_get_cwd(c,
|
xasprintf(&new_cwd, "%s%s%s",
|
||||||
target->s), cwd);
|
server_client_get_cwd(c, target->s),
|
||||||
|
*cwd != '\0' ? "/" : "", cwd);
|
||||||
free(cwd);
|
free(cwd);
|
||||||
cwd = new_cwd;
|
cwd = new_cwd;
|
||||||
}
|
}
|
||||||
@ -382,20 +383,19 @@ spawn_pane(struct spawn_context *sc, char **cause)
|
|||||||
|
|
||||||
/* In the parent process, everything is done now. */
|
/* In the parent process, everything is done now. */
|
||||||
if (new_wp->pid != 0) {
|
if (new_wp->pid != 0) {
|
||||||
#if defined(HAVE_SYSTEMD) && defined(ENABLE_CGROUPS)
|
|
||||||
/*
|
|
||||||
* Move the child process into a new cgroup for systemd-oomd
|
|
||||||
* isolation.
|
|
||||||
*/
|
|
||||||
if (systemd_move_pid_to_new_cgroup(new_wp->pid, cause) < 0) {
|
|
||||||
log_debug("%s: moving pane to new cgroup failed: %s",
|
|
||||||
__func__, *cause);
|
|
||||||
free (*cause);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
goto complete;
|
goto complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_SYSTEMD) && defined(ENABLE_CGROUPS)
|
||||||
|
/*
|
||||||
|
* Move the child process into a new cgroup for systemd-oomd isolation.
|
||||||
|
*/
|
||||||
|
if (systemd_move_to_new_cgroup(cause) < 0) {
|
||||||
|
log_debug("%s: moving pane to new cgroup failed: %s",
|
||||||
|
__func__, *cause);
|
||||||
|
free (*cause);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
* Child process. Change to the working directory or home if that
|
* Child process. Change to the working directory or home if that
|
||||||
* fails.
|
* fails.
|
||||||
|
177
status.c
177
status.c
@ -470,7 +470,7 @@ status_redraw(struct client *c)
|
|||||||
/* Set a status line message. */
|
/* Set a status line message. */
|
||||||
void
|
void
|
||||||
status_message_set(struct client *c, int delay, int ignore_styles,
|
status_message_set(struct client *c, int delay, int ignore_styles,
|
||||||
int ignore_keys, const char *fmt, ...)
|
int ignore_keys, int no_freeze, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@ -514,7 +514,9 @@ status_message_set(struct client *c, int delay, int ignore_styles,
|
|||||||
c->message_ignore_keys = ignore_keys;
|
c->message_ignore_keys = ignore_keys;
|
||||||
c->message_ignore_styles = ignore_styles;
|
c->message_ignore_styles = ignore_styles;
|
||||||
|
|
||||||
c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE);
|
if (!no_freeze)
|
||||||
|
c->tty.flags |= TTY_FREEZE;
|
||||||
|
c->tty.flags |= TTY_NOCURSOR;
|
||||||
c->flags |= CLIENT_REDRAWSTATUS;
|
c->flags |= CLIENT_REDRAWSTATUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -598,6 +600,19 @@ status_message_redraw(struct client *c)
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Accept prompt immediately. */
|
||||||
|
static enum cmd_retval
|
||||||
|
status_prompt_accept(__unused struct cmdq_item *item, void *data)
|
||||||
|
{
|
||||||
|
struct client *c = data;
|
||||||
|
|
||||||
|
if (c->prompt_string != NULL) {
|
||||||
|
c->prompt_inputcb(c, c->prompt_data, "y", 1);
|
||||||
|
status_prompt_clear(c);
|
||||||
|
}
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Enable status line prompt. */
|
/* Enable status line prompt. */
|
||||||
void
|
void
|
||||||
status_prompt_set(struct client *c, struct cmd_find_state *fs,
|
status_prompt_set(struct client *c, struct cmd_find_state *fs,
|
||||||
@ -616,17 +631,18 @@ status_prompt_set(struct client *c, struct cmd_find_state *fs,
|
|||||||
|
|
||||||
if (input == NULL)
|
if (input == NULL)
|
||||||
input = "";
|
input = "";
|
||||||
if (flags & PROMPT_NOFORMAT)
|
|
||||||
tmp = xstrdup(input);
|
|
||||||
else
|
|
||||||
tmp = format_expand_time(ft, input);
|
|
||||||
|
|
||||||
status_message_clear(c);
|
status_message_clear(c);
|
||||||
status_prompt_clear(c);
|
status_prompt_clear(c);
|
||||||
status_push_screen(c);
|
status_push_screen(c);
|
||||||
|
|
||||||
c->prompt_string = format_expand_time(ft, msg);
|
c->prompt_formats = ft;
|
||||||
|
c->prompt_string = xstrdup (msg);
|
||||||
|
|
||||||
|
if (flags & PROMPT_NOFORMAT)
|
||||||
|
tmp = xstrdup(input);
|
||||||
|
else
|
||||||
|
tmp = format_expand_time(ft, input);
|
||||||
if (flags & PROMPT_INCREMENTAL) {
|
if (flags & PROMPT_INCREMENTAL) {
|
||||||
c->prompt_last = xstrdup(tmp);
|
c->prompt_last = xstrdup(tmp);
|
||||||
c->prompt_buffer = utf8_fromcstr("");
|
c->prompt_buffer = utf8_fromcstr("");
|
||||||
@ -635,6 +651,7 @@ status_prompt_set(struct client *c, struct cmd_find_state *fs,
|
|||||||
c->prompt_buffer = utf8_fromcstr(tmp);
|
c->prompt_buffer = utf8_fromcstr(tmp);
|
||||||
}
|
}
|
||||||
c->prompt_index = utf8_strlen(c->prompt_buffer);
|
c->prompt_index = utf8_strlen(c->prompt_buffer);
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
c->prompt_inputcb = inputcb;
|
c->prompt_inputcb = inputcb;
|
||||||
c->prompt_freecb = freecb;
|
c->prompt_freecb = freecb;
|
||||||
@ -647,14 +664,14 @@ status_prompt_set(struct client *c, struct cmd_find_state *fs,
|
|||||||
c->prompt_mode = PROMPT_ENTRY;
|
c->prompt_mode = PROMPT_ENTRY;
|
||||||
|
|
||||||
if (~flags & PROMPT_INCREMENTAL)
|
if (~flags & PROMPT_INCREMENTAL)
|
||||||
c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE);
|
c->tty.flags |= TTY_FREEZE;
|
||||||
c->flags |= CLIENT_REDRAWSTATUS;
|
c->flags |= CLIENT_REDRAWSTATUS;
|
||||||
|
|
||||||
if (flags & PROMPT_INCREMENTAL)
|
if (flags & PROMPT_INCREMENTAL)
|
||||||
c->prompt_inputcb(c, c->prompt_data, "=", 0);
|
c->prompt_inputcb(c, c->prompt_data, "=", 0);
|
||||||
|
|
||||||
free(tmp);
|
if ((flags & PROMPT_SINGLE) && (flags & PROMPT_ACCEPT))
|
||||||
format_free(ft);
|
cmdq_append(c, cmdq_get_callback(status_prompt_accept, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove status line prompt. */
|
/* Remove status line prompt. */
|
||||||
@ -670,6 +687,9 @@ status_prompt_clear(struct client *c)
|
|||||||
free(c->prompt_last);
|
free(c->prompt_last);
|
||||||
c->prompt_last = NULL;
|
c->prompt_last = NULL;
|
||||||
|
|
||||||
|
format_free(c->prompt_formats);
|
||||||
|
c->prompt_formats = NULL;
|
||||||
|
|
||||||
free(c->prompt_string);
|
free(c->prompt_string);
|
||||||
c->prompt_string = NULL;
|
c->prompt_string = NULL;
|
||||||
|
|
||||||
@ -689,27 +709,69 @@ status_prompt_clear(struct client *c)
|
|||||||
void
|
void
|
||||||
status_prompt_update(struct client *c, const char *msg, const char *input)
|
status_prompt_update(struct client *c, const char *msg, const char *input)
|
||||||
{
|
{
|
||||||
struct format_tree *ft;
|
char *tmp;
|
||||||
char *tmp;
|
|
||||||
|
|
||||||
ft = format_create(c, NULL, FORMAT_NONE, 0);
|
|
||||||
format_defaults(ft, c, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
tmp = format_expand_time(ft, input);
|
|
||||||
|
|
||||||
free(c->prompt_string);
|
free(c->prompt_string);
|
||||||
c->prompt_string = format_expand_time(ft, msg);
|
c->prompt_string = xstrdup(msg);
|
||||||
|
|
||||||
free(c->prompt_buffer);
|
free(c->prompt_buffer);
|
||||||
|
tmp = format_expand_time(c->prompt_formats, input);
|
||||||
c->prompt_buffer = utf8_fromcstr(tmp);
|
c->prompt_buffer = utf8_fromcstr(tmp);
|
||||||
c->prompt_index = utf8_strlen(c->prompt_buffer);
|
c->prompt_index = utf8_strlen(c->prompt_buffer);
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
memset(c->prompt_hindex, 0, sizeof c->prompt_hindex);
|
memset(c->prompt_hindex, 0, sizeof c->prompt_hindex);
|
||||||
|
|
||||||
c->flags |= CLIENT_REDRAWSTATUS;
|
c->flags |= CLIENT_REDRAWSTATUS;
|
||||||
|
}
|
||||||
|
|
||||||
free(tmp);
|
/* Redraw character. Return 1 if can continue redrawing, 0 otherwise. */
|
||||||
format_free(ft);
|
static int
|
||||||
|
status_prompt_redraw_character(struct screen_write_ctx *ctx, u_int offset,
|
||||||
|
u_int pwidth, u_int *width, struct grid_cell *gc,
|
||||||
|
const struct utf8_data *ud)
|
||||||
|
{
|
||||||
|
u_char ch;
|
||||||
|
|
||||||
|
if (*width < offset) {
|
||||||
|
*width += ud->width;
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if (*width >= offset + pwidth)
|
||||||
|
return (0);
|
||||||
|
*width += ud->width;
|
||||||
|
if (*width > offset + pwidth)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
ch = *ud->data;
|
||||||
|
if (ud->size == 1 && (ch <= 0x1f || ch == 0x7f)) {
|
||||||
|
gc->data.data[0] = '^';
|
||||||
|
gc->data.data[1] = (ch == 0x7f) ? '?' : ch|0x40;
|
||||||
|
gc->data.size = gc->data.have = 2;
|
||||||
|
gc->data.width = 2;
|
||||||
|
} else
|
||||||
|
utf8_copy(&gc->data, ud);
|
||||||
|
screen_write_cell(ctx, gc);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Redraw quote indicator '^' if necessary. Return 1 if can continue redrawing,
|
||||||
|
* 0 otherwise.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
status_prompt_redraw_quote(const struct client *c, u_int pcursor,
|
||||||
|
struct screen_write_ctx *ctx, u_int offset, u_int pwidth, u_int *width,
|
||||||
|
struct grid_cell *gc)
|
||||||
|
{
|
||||||
|
struct utf8_data ud;
|
||||||
|
|
||||||
|
if (c->prompt_flags & PROMPT_QUOTENEXT && ctx->s->cx == pcursor + 1) {
|
||||||
|
utf8_set(&ud, '^');
|
||||||
|
return (status_prompt_redraw_character(ctx, offset, pwidth,
|
||||||
|
width, gc, &ud));
|
||||||
|
}
|
||||||
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Draw client prompt on status line of present else on last line. */
|
/* Draw client prompt on status line of present else on last line. */
|
||||||
@ -720,10 +782,11 @@ status_prompt_redraw(struct client *c)
|
|||||||
struct screen_write_ctx ctx;
|
struct screen_write_ctx ctx;
|
||||||
struct session *s = c->session;
|
struct session *s = c->session;
|
||||||
struct screen old_screen;
|
struct screen old_screen;
|
||||||
u_int i, lines, offset, left, start, width;
|
u_int i, lines, offset, left, start, width, n;
|
||||||
u_int pcursor, pwidth, promptline;
|
u_int pcursor, pwidth, promptline;
|
||||||
struct grid_cell gc, cursorgc;
|
struct grid_cell gc;
|
||||||
struct format_tree *ft;
|
struct format_tree *ft = c->prompt_formats;
|
||||||
|
char *prompt, *tmp;
|
||||||
|
|
||||||
if (c->tty.sx == 0 || c->tty.sy == 0)
|
if (c->tty.sx == 0 || c->tty.sy == 0)
|
||||||
return (0);
|
return (0);
|
||||||
@ -734,21 +797,27 @@ status_prompt_redraw(struct client *c)
|
|||||||
lines = 1;
|
lines = 1;
|
||||||
screen_init(sl->active, c->tty.sx, lines, 0);
|
screen_init(sl->active, c->tty.sx, lines, 0);
|
||||||
|
|
||||||
|
n = options_get_number(s->options, "prompt-cursor-colour");
|
||||||
|
sl->active->default_ccolour = n;
|
||||||
|
n = options_get_number(s->options, "prompt-cursor-style");
|
||||||
|
screen_set_cursor_style(n, &sl->active->default_cstyle,
|
||||||
|
&sl->active->default_mode);
|
||||||
|
|
||||||
promptline = status_prompt_line_at(c);
|
promptline = status_prompt_line_at(c);
|
||||||
if (promptline > lines - 1)
|
if (promptline > lines - 1)
|
||||||
promptline = lines - 1;
|
promptline = lines - 1;
|
||||||
|
|
||||||
ft = format_create_defaults(NULL, c, NULL, NULL, NULL);
|
|
||||||
if (c->prompt_mode == PROMPT_COMMAND)
|
if (c->prompt_mode == PROMPT_COMMAND)
|
||||||
style_apply(&gc, s->options, "message-command-style", ft);
|
style_apply(&gc, s->options, "message-command-style", ft);
|
||||||
else
|
else
|
||||||
style_apply(&gc, s->options, "message-style", ft);
|
style_apply(&gc, s->options, "message-style", ft);
|
||||||
format_free(ft);
|
|
||||||
|
|
||||||
memcpy(&cursorgc, &gc, sizeof cursorgc);
|
tmp = utf8_tocstr(c->prompt_buffer);
|
||||||
cursorgc.attr ^= GRID_ATTR_REVERSE;
|
format_add(c->prompt_formats, "prompt-input", "%s", tmp);
|
||||||
|
prompt = format_expand_time(c->prompt_formats, c->prompt_string);
|
||||||
|
free (tmp);
|
||||||
|
|
||||||
start = format_width(c->prompt_string);
|
start = format_width(prompt);
|
||||||
if (start > c->tty.sx)
|
if (start > c->tty.sx)
|
||||||
start = c->tty.sx;
|
start = c->tty.sx;
|
||||||
|
|
||||||
@ -758,7 +827,7 @@ status_prompt_redraw(struct client *c)
|
|||||||
for (offset = 0; offset < c->tty.sx; offset++)
|
for (offset = 0; offset < c->tty.sx; offset++)
|
||||||
screen_write_putc(&ctx, &gc, ' ');
|
screen_write_putc(&ctx, &gc, ' ');
|
||||||
screen_write_cursormove(&ctx, 0, promptline, 0);
|
screen_write_cursormove(&ctx, 0, promptline, 0);
|
||||||
format_draw(&ctx, &gc, start, c->prompt_string, NULL, 0);
|
format_draw(&ctx, &gc, start, prompt, NULL, 0);
|
||||||
screen_write_cursormove(&ctx, start, promptline, 0);
|
screen_write_cursormove(&ctx, start, promptline, 0);
|
||||||
|
|
||||||
left = c->tty.sx - start;
|
left = c->tty.sx - start;
|
||||||
@ -767,6 +836,8 @@ status_prompt_redraw(struct client *c)
|
|||||||
|
|
||||||
pcursor = utf8_strwidth(c->prompt_buffer, c->prompt_index);
|
pcursor = utf8_strwidth(c->prompt_buffer, c->prompt_index);
|
||||||
pwidth = utf8_strwidth(c->prompt_buffer, -1);
|
pwidth = utf8_strwidth(c->prompt_buffer, -1);
|
||||||
|
if (c->prompt_flags & PROMPT_QUOTENEXT)
|
||||||
|
pwidth++;
|
||||||
if (pcursor >= left) {
|
if (pcursor >= left) {
|
||||||
/*
|
/*
|
||||||
* The cursor would be outside the screen so start drawing
|
* The cursor would be outside the screen so start drawing
|
||||||
@ -778,30 +849,19 @@ status_prompt_redraw(struct client *c)
|
|||||||
offset = 0;
|
offset = 0;
|
||||||
if (pwidth > left)
|
if (pwidth > left)
|
||||||
pwidth = left;
|
pwidth = left;
|
||||||
c->prompt_cursor = start + c->prompt_index - offset;
|
c->prompt_cursor = start + pcursor - offset;
|
||||||
|
|
||||||
width = 0;
|
width = 0;
|
||||||
for (i = 0; c->prompt_buffer[i].size != 0; i++) {
|
for (i = 0; c->prompt_buffer[i].size != 0; i++) {
|
||||||
if (width < offset) {
|
if (!status_prompt_redraw_quote(c, pcursor, &ctx, offset,
|
||||||
width += c->prompt_buffer[i].width;
|
pwidth, &width, &gc))
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (width >= offset + pwidth)
|
|
||||||
break;
|
break;
|
||||||
width += c->prompt_buffer[i].width;
|
if (!status_prompt_redraw_character(&ctx, offset, pwidth,
|
||||||
if (width > offset + pwidth)
|
&width, &gc, &c->prompt_buffer[i]))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (i != c->prompt_index) {
|
|
||||||
utf8_copy(&gc.data, &c->prompt_buffer[i]);
|
|
||||||
screen_write_cell(&ctx, &gc);
|
|
||||||
} else {
|
|
||||||
utf8_copy(&cursorgc.data, &c->prompt_buffer[i]);
|
|
||||||
screen_write_cell(&ctx, &cursorgc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (sl->active->cx < screen_size_x(sl->active) && c->prompt_index >= i)
|
status_prompt_redraw_quote(c, pcursor, &ctx, offset, pwidth, &width,
|
||||||
screen_write_putc(&ctx, &cursorgc, ' ');
|
&gc);
|
||||||
|
|
||||||
finished:
|
finished:
|
||||||
screen_write_stop(&ctx);
|
screen_write_stop(&ctx);
|
||||||
@ -852,6 +912,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
|
|||||||
case 'p'|KEYC_CTRL:
|
case 'p'|KEYC_CTRL:
|
||||||
case 't'|KEYC_CTRL:
|
case 't'|KEYC_CTRL:
|
||||||
case 'u'|KEYC_CTRL:
|
case 'u'|KEYC_CTRL:
|
||||||
|
case 'v'|KEYC_CTRL:
|
||||||
case 'w'|KEYC_CTRL:
|
case 'w'|KEYC_CTRL:
|
||||||
case 'y'|KEYC_CTRL:
|
case 'y'|KEYC_CTRL:
|
||||||
case '\n':
|
case '\n':
|
||||||
@ -1250,6 +1311,19 @@ status_prompt_key(struct client *c, key_code key)
|
|||||||
}
|
}
|
||||||
key &= ~KEYC_MASK_FLAGS;
|
key &= ~KEYC_MASK_FLAGS;
|
||||||
|
|
||||||
|
if (c->prompt_flags & (PROMPT_SINGLE|PROMPT_QUOTENEXT)) {
|
||||||
|
if ((key & KEYC_MASK_KEY) == KEYC_BSPACE)
|
||||||
|
key = 0x7f;
|
||||||
|
else if ((key & KEYC_MASK_KEY) > 0x7f) {
|
||||||
|
if (!KEYC_IS_UNICODE(key))
|
||||||
|
return (0);
|
||||||
|
key &= KEYC_MASK_KEY;
|
||||||
|
} else
|
||||||
|
key &= (key & KEYC_CTRL) ? 0x1f : KEYC_MASK_KEY;
|
||||||
|
c->prompt_flags &= ~PROMPT_QUOTENEXT;
|
||||||
|
goto append_key;
|
||||||
|
}
|
||||||
|
|
||||||
keys = options_get_number(c->session->options, "status-keys");
|
keys = options_get_number(c->session->options, "status-keys");
|
||||||
if (keys == MODEKEY_VI) {
|
if (keys == MODEKEY_VI) {
|
||||||
switch (status_prompt_translate_key(c, key, &key)) {
|
switch (status_prompt_translate_key(c, key, &key)) {
|
||||||
@ -1472,6 +1546,9 @@ process_key:
|
|||||||
} else
|
} else
|
||||||
prefix = '+';
|
prefix = '+';
|
||||||
goto changed;
|
goto changed;
|
||||||
|
case 'v'|KEYC_CTRL:
|
||||||
|
c->prompt_flags |= PROMPT_QUOTENEXT;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
goto append_key;
|
goto append_key;
|
||||||
}
|
}
|
||||||
@ -1480,9 +1557,11 @@ process_key:
|
|||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
append_key:
|
append_key:
|
||||||
if (key <= 0x7f)
|
if (key <= 0x7f) {
|
||||||
utf8_set(&tmp, key);
|
utf8_set(&tmp, key);
|
||||||
else if (KEYC_IS_UNICODE(key))
|
if (key <= 0x1f || key == 0x7f)
|
||||||
|
tmp.width = 2;
|
||||||
|
} else if (KEYC_IS_UNICODE(key))
|
||||||
utf8_to_data(key, &tmp);
|
utf8_to_data(key, &tmp);
|
||||||
else
|
else
|
||||||
return (0);
|
return (0);
|
||||||
|
52
style.c
52
style.c
@ -39,6 +39,8 @@ static struct style style_default = {
|
|||||||
|
|
||||||
STYLE_RANGE_NONE, 0, "",
|
STYLE_RANGE_NONE, 0, "",
|
||||||
|
|
||||||
|
STYLE_WIDTH_DEFAULT, STYLE_PAD_DEFAULT,
|
||||||
|
|
||||||
STYLE_DEFAULT_BASE
|
STYLE_DEFAULT_BASE
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -96,6 +98,8 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
|
|||||||
sy->default_type = STYLE_DEFAULT_PUSH;
|
sy->default_type = STYLE_DEFAULT_PUSH;
|
||||||
else if (strcasecmp(tmp, "pop-default") == 0)
|
else if (strcasecmp(tmp, "pop-default") == 0)
|
||||||
sy->default_type = STYLE_DEFAULT_POP;
|
sy->default_type = STYLE_DEFAULT_POP;
|
||||||
|
else if (strcasecmp(tmp, "set-default") == 0)
|
||||||
|
sy->default_type = STYLE_DEFAULT_SET;
|
||||||
else if (strcasecmp(tmp, "nolist") == 0)
|
else if (strcasecmp(tmp, "nolist") == 0)
|
||||||
sy->list = STYLE_LIST_OFF;
|
sy->list = STYLE_LIST_OFF;
|
||||||
else if (strncasecmp(tmp, "list=", 5) == 0) {
|
else if (strncasecmp(tmp, "list=", 5) == 0) {
|
||||||
@ -213,9 +217,21 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
|
|||||||
} else if (strcasecmp(tmp, "none") == 0)
|
} else if (strcasecmp(tmp, "none") == 0)
|
||||||
sy->gc.attr = 0;
|
sy->gc.attr = 0;
|
||||||
else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) {
|
else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) {
|
||||||
if ((value = attributes_fromstring(tmp + 2)) == -1)
|
if (strcmp(tmp + 2, "attr") == 0)
|
||||||
|
value = 0xffff & ~GRID_ATTR_CHARSET;
|
||||||
|
else if ((value = attributes_fromstring(tmp + 2)) == -1)
|
||||||
goto error;
|
goto error;
|
||||||
sy->gc.attr &= ~value;
|
sy->gc.attr &= ~value;
|
||||||
|
} else if (end > 6 && strncasecmp(tmp, "width=", 6) == 0) {
|
||||||
|
n = strtonum(tmp + 6, 0, UINT_MAX, &errstr);
|
||||||
|
if (errstr != NULL)
|
||||||
|
goto error;
|
||||||
|
sy->width = (int)n;
|
||||||
|
} else if (end > 4 && strncasecmp(tmp, "pad=", 4) == 0) {
|
||||||
|
n = strtonum(tmp + 4, 0, UINT_MAX, &errstr);
|
||||||
|
if (errstr != NULL)
|
||||||
|
goto error;
|
||||||
|
sy->pad = (int)n;
|
||||||
} else {
|
} else {
|
||||||
if ((value = attributes_fromstring(tmp)) == -1)
|
if ((value = attributes_fromstring(tmp)) == -1)
|
||||||
goto error;
|
goto error;
|
||||||
@ -298,6 +314,8 @@ style_tostring(struct style *sy)
|
|||||||
tmp = "push-default";
|
tmp = "push-default";
|
||||||
else if (sy->default_type == STYLE_DEFAULT_POP)
|
else if (sy->default_type == STYLE_DEFAULT_POP)
|
||||||
tmp = "pop-default";
|
tmp = "pop-default";
|
||||||
|
else if (sy->default_type == STYLE_DEFAULT_SET)
|
||||||
|
tmp = "set-default";
|
||||||
off += xsnprintf(s + off, sizeof s - off, "%s%s", comma, tmp);
|
off += xsnprintf(s + off, sizeof s - off, "%s%s", comma, tmp);
|
||||||
comma = ",";
|
comma = ",";
|
||||||
}
|
}
|
||||||
@ -326,7 +344,16 @@ style_tostring(struct style *sy)
|
|||||||
attributes_tostring(gc->attr));
|
attributes_tostring(gc->attr));
|
||||||
comma = ",";
|
comma = ",";
|
||||||
}
|
}
|
||||||
|
if (sy->width >= 0) {
|
||||||
|
xsnprintf(s + off, sizeof s - off, "%swidth=%u", comma,
|
||||||
|
sy->width);
|
||||||
|
comma = ",";
|
||||||
|
}
|
||||||
|
if (sy->pad >= 0) {
|
||||||
|
xsnprintf(s + off, sizeof s - off, "%spad=%u", comma,
|
||||||
|
sy->pad);
|
||||||
|
comma = ",";
|
||||||
|
}
|
||||||
if (*s == '\0')
|
if (*s == '\0')
|
||||||
return ("default");
|
return ("default");
|
||||||
return (s);
|
return (s);
|
||||||
@ -381,3 +408,24 @@ style_copy(struct style *dst, struct style *src)
|
|||||||
{
|
{
|
||||||
memcpy(dst, src, sizeof *dst);
|
memcpy(dst, src, sizeof *dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
style_set_scrollbar_style_from_option(struct style *sb_style, struct options *oo)
|
||||||
|
{
|
||||||
|
struct style *sy;
|
||||||
|
|
||||||
|
sy = options_string_to_style(oo, "pane-scrollbars-style", NULL);
|
||||||
|
if (sy == NULL) {
|
||||||
|
style_set(sb_style, &grid_default_cell);
|
||||||
|
sb_style->width = PANE_SCROLLBARS_DEFAULT_WIDTH;
|
||||||
|
sb_style->pad = PANE_SCROLLBARS_DEFAULT_PADDING;
|
||||||
|
utf8_set(&sb_style->gc.data, PANE_SCROLLBARS_CHARACTER);
|
||||||
|
} else {
|
||||||
|
style_copy(sb_style, sy);
|
||||||
|
if (sb_style->width < 1)
|
||||||
|
sb_style->width = PANE_SCROLLBARS_DEFAULT_WIDTH;
|
||||||
|
if (sb_style->pad < 0)
|
||||||
|
sb_style->pad = PANE_SCROLLBARS_DEFAULT_PADDING;
|
||||||
|
utf8_set(&sb_style->gc.data, PANE_SCROLLBARS_CHARACTER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
26
tmux.c
26
tmux.c
@ -43,20 +43,20 @@ const char *socket_path;
|
|||||||
int ptm_fd = -1;
|
int ptm_fd = -1;
|
||||||
const char *shell_command;
|
const char *shell_command;
|
||||||
|
|
||||||
static __dead void usage(void);
|
static __dead void usage(int);
|
||||||
static char *make_label(const char *, char **);
|
static char *make_label(const char *, char **);
|
||||||
|
|
||||||
static int areshell(const char *);
|
static int areshell(const char *);
|
||||||
static const char *getshell(void);
|
static const char *getshell(void);
|
||||||
|
|
||||||
static __dead void
|
static __dead void
|
||||||
usage(void)
|
usage(int status)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(status ? stderr : stdout,
|
||||||
"usage: %s [-2CDlNuVv] [-c shell-command] [-f file] [-L socket-name]\n"
|
"usage: %s [-2CDhlNuVv] [-c shell-command] [-f file] [-L socket-name]\n"
|
||||||
" [-S socket-path] [-T features] [command [flags]]\n",
|
" [-S socket-path] [-T features] [command [flags]]\n",
|
||||||
getprogname());
|
getprogname());
|
||||||
exit(1);
|
exit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
@ -222,7 +222,7 @@ make_label(const char *label, char **cause)
|
|||||||
xasprintf(cause, "%s is not a directory", base);
|
xasprintf(cause, "%s is not a directory", base);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (sb.st_uid != uid || (sb.st_mode & S_IRWXO) != 0) {
|
if (sb.st_uid != uid || (sb.st_mode & TMUX_SOCK_PERM) != 0) {
|
||||||
xasprintf(cause, "directory %s has unsafe permissions", base);
|
xasprintf(cause, "directory %s has unsafe permissions", base);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@ -379,7 +379,7 @@ main(int argc, char **argv)
|
|||||||
environ_set(global_environ, "PWD", 0, "%s", cwd);
|
environ_set(global_environ, "PWD", 0, "%s", cwd);
|
||||||
expand_paths(TMUX_CONF, &cfg_files, &cfg_nfiles, 1);
|
expand_paths(TMUX_CONF, &cfg_files, &cfg_nfiles, 1);
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "2c:CDdf:lL:NqS:T:uUvV")) != -1) {
|
while ((opt = getopt(argc, argv, "2c:CDdf:hlL:NqS:T:uUvV")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case '2':
|
case '2':
|
||||||
tty_add_features(&feat, "256", ":,");
|
tty_add_features(&feat, "256", ":,");
|
||||||
@ -408,9 +408,11 @@ main(int argc, char **argv)
|
|||||||
cfg_files[cfg_nfiles++] = xstrdup(optarg);
|
cfg_files[cfg_nfiles++] = xstrdup(optarg);
|
||||||
cfg_quiet = 0;
|
cfg_quiet = 0;
|
||||||
break;
|
break;
|
||||||
case 'V':
|
case 'h':
|
||||||
|
usage(0);
|
||||||
|
case 'V':
|
||||||
printf("tmux %s\n", getversion());
|
printf("tmux %s\n", getversion());
|
||||||
exit(0);
|
exit(0);
|
||||||
case 'l':
|
case 'l':
|
||||||
flags |= CLIENT_LOGIN;
|
flags |= CLIENT_LOGIN;
|
||||||
break;
|
break;
|
||||||
@ -437,16 +439,16 @@ main(int argc, char **argv)
|
|||||||
log_add_level();
|
log_add_level();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
|
|
||||||
if (shell_command != NULL && argc != 0)
|
if (shell_command != NULL && argc != 0)
|
||||||
usage();
|
usage(1);
|
||||||
if ((flags & CLIENT_NOFORK) && argc != 0)
|
if ((flags & CLIENT_NOFORK) && argc != 0)
|
||||||
usage();
|
usage(1);
|
||||||
|
|
||||||
if ((ptm_fd = getptmfd()) == -1)
|
if ((ptm_fd = getptmfd()) == -1)
|
||||||
err(1, "getptmfd");
|
err(1, "getptmfd");
|
||||||
|
183
tmux.h
183
tmux.h
@ -84,6 +84,9 @@ struct winlink;
|
|||||||
#ifndef TMUX_SOCK
|
#ifndef TMUX_SOCK
|
||||||
#define TMUX_SOCK "$TMUX_TMPDIR:" _PATH_TMP
|
#define TMUX_SOCK "$TMUX_TMPDIR:" _PATH_TMP
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef TMUX_SOCK_PERM
|
||||||
|
#define TMUX_SOCK_PERM (7 /* o+rwx */)
|
||||||
|
#endif
|
||||||
#ifndef TMUX_TERM
|
#ifndef TMUX_TERM
|
||||||
#define TMUX_TERM "screen"
|
#define TMUX_TERM "screen"
|
||||||
#endif
|
#endif
|
||||||
@ -171,23 +174,34 @@ struct winlink;
|
|||||||
(((key) & KEYC_MASK_KEY) < KEYC_USER || \
|
(((key) & KEYC_MASK_KEY) < KEYC_USER || \
|
||||||
((key) & KEYC_MASK_KEY) >= KEYC_USER_END))
|
((key) & KEYC_MASK_KEY) >= KEYC_USER_END))
|
||||||
|
|
||||||
|
/* Is this a paste key? */
|
||||||
|
#define KEYC_IS_PASTE(key) \
|
||||||
|
(((key) & KEYC_MASK_KEY) == KEYC_PASTE_START || \
|
||||||
|
((key) & KEYC_MASK_KEY) == KEYC_PASTE_END)
|
||||||
|
|
||||||
/* Multiple click timeout. */
|
/* Multiple click timeout. */
|
||||||
#define KEYC_CLICK_TIMEOUT 300
|
#define KEYC_CLICK_TIMEOUT 300
|
||||||
|
|
||||||
/* Mouse key codes. */
|
/* Mouse key codes. */
|
||||||
#define KEYC_MOUSE_KEY(name) \
|
#define KEYC_MOUSE_KEY(name) \
|
||||||
KEYC_ ## name ## _PANE, \
|
KEYC_ ## name ## _PANE, \
|
||||||
KEYC_ ## name ## _STATUS, \
|
KEYC_ ## name ## _STATUS, \
|
||||||
KEYC_ ## name ## _STATUS_LEFT, \
|
KEYC_ ## name ## _STATUS_LEFT, \
|
||||||
KEYC_ ## name ## _STATUS_RIGHT, \
|
KEYC_ ## name ## _STATUS_RIGHT, \
|
||||||
KEYC_ ## name ## _STATUS_DEFAULT, \
|
KEYC_ ## name ## _STATUS_DEFAULT, \
|
||||||
|
KEYC_ ## name ## _SCROLLBAR_UP, \
|
||||||
|
KEYC_ ## name ## _SCROLLBAR_SLIDER, \
|
||||||
|
KEYC_ ## name ## _SCROLLBAR_DOWN, \
|
||||||
KEYC_ ## name ## _BORDER
|
KEYC_ ## name ## _BORDER
|
||||||
#define KEYC_MOUSE_STRING(name, s) \
|
#define KEYC_MOUSE_STRING(name, s) \
|
||||||
{ #s "Pane", KEYC_ ## name ## _PANE }, \
|
{ #s "Pane", KEYC_ ## name ## _PANE }, \
|
||||||
{ #s "Status", KEYC_ ## name ## _STATUS }, \
|
{ #s "Status", KEYC_ ## name ## _STATUS }, \
|
||||||
{ #s "StatusLeft", KEYC_ ## name ## _STATUS_LEFT }, \
|
{ #s "StatusLeft", KEYC_ ## name ## _STATUS_LEFT }, \
|
||||||
{ #s "StatusRight", KEYC_ ## name ## _STATUS_RIGHT }, \
|
{ #s "StatusRight", KEYC_ ## name ## _STATUS_RIGHT }, \
|
||||||
{ #s "StatusDefault", KEYC_ ## name ## _STATUS_DEFAULT }, \
|
{ #s "StatusDefault", KEYC_ ## name ## _STATUS_DEFAULT }, \
|
||||||
|
{ #s "ScrollbarUp", KEYC_ ## name ## _SCROLLBAR_UP }, \
|
||||||
|
{ #s "ScrollbarSlider", KEYC_ ## name ## _SCROLLBAR_SLIDER }, \
|
||||||
|
{ #s "ScrollbarDown", KEYC_ ## name ## _SCROLLBAR_DOWN }, \
|
||||||
{ #s "Border", KEYC_ ## name ## _BORDER }
|
{ #s "Border", KEYC_ ## name ## _BORDER }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -364,6 +378,10 @@ enum {
|
|||||||
KEYC_KP_ZERO,
|
KEYC_KP_ZERO,
|
||||||
KEYC_KP_PERIOD,
|
KEYC_KP_PERIOD,
|
||||||
|
|
||||||
|
/* Theme reporting. */
|
||||||
|
KEYC_REPORT_DARK_THEME,
|
||||||
|
KEYC_REPORT_LIGHT_THEME,
|
||||||
|
|
||||||
/* End of special keys. */
|
/* End of special keys. */
|
||||||
KEYC_BASE_END
|
KEYC_BASE_END
|
||||||
};
|
};
|
||||||
@ -605,7 +623,7 @@ enum tty_code_code {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Character classes. */
|
/* Character classes. */
|
||||||
#define WHITESPACE " "
|
#define WHITESPACE "\t "
|
||||||
|
|
||||||
/* Mode keys. */
|
/* Mode keys. */
|
||||||
#define MODEKEY_EMACS 0
|
#define MODEKEY_EMACS 0
|
||||||
@ -631,6 +649,7 @@ enum tty_code_code {
|
|||||||
#define MODE_CURSOR_VERY_VISIBLE 0x10000
|
#define MODE_CURSOR_VERY_VISIBLE 0x10000
|
||||||
#define MODE_CURSOR_BLINKING_SET 0x20000
|
#define MODE_CURSOR_BLINKING_SET 0x20000
|
||||||
#define MODE_KEYS_EXTENDED_2 0x40000
|
#define MODE_KEYS_EXTENDED_2 0x40000
|
||||||
|
#define MODE_THEME_UPDATES 0x80000
|
||||||
|
|
||||||
#define ALL_MODES 0xffffff
|
#define ALL_MODES 0xffffff
|
||||||
#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)
|
||||||
@ -652,7 +671,7 @@ typedef u_int utf8_char;
|
|||||||
* characters as well. It can't be more than 32 bytes without changes to how
|
* characters as well. It can't be more than 32 bytes without changes to how
|
||||||
* characters are stored.
|
* characters are stored.
|
||||||
*/
|
*/
|
||||||
#define UTF8_SIZE 21
|
#define UTF8_SIZE 32
|
||||||
struct utf8_data {
|
struct utf8_data {
|
||||||
u_char data[UTF8_SIZE];
|
u_char data[UTF8_SIZE];
|
||||||
|
|
||||||
@ -715,6 +734,7 @@ struct colour_palette {
|
|||||||
#define GRID_FLAG_SELECTED 0x10
|
#define GRID_FLAG_SELECTED 0x10
|
||||||
#define GRID_FLAG_NOPALETTE 0x20
|
#define GRID_FLAG_NOPALETTE 0x20
|
||||||
#define GRID_FLAG_CLEARED 0x40
|
#define GRID_FLAG_CLEARED 0x40
|
||||||
|
#define GRID_FLAG_TAB 0x80
|
||||||
|
|
||||||
/* Grid line flags. */
|
/* Grid line flags. */
|
||||||
#define GRID_LINE_WRAPPED 0x1
|
#define GRID_LINE_WRAPPED 0x1
|
||||||
@ -744,6 +764,7 @@ struct colour_palette {
|
|||||||
#define CELL_RIGHTJOIN 10
|
#define CELL_RIGHTJOIN 10
|
||||||
#define CELL_JOIN 11
|
#define CELL_JOIN 11
|
||||||
#define CELL_OUTSIDE 12
|
#define CELL_OUTSIDE 12
|
||||||
|
#define CELL_SCROLLBAR 13
|
||||||
|
|
||||||
/* Cell borders. */
|
/* Cell borders. */
|
||||||
#define CELL_BORDERS " xqlkmjwvtun~"
|
#define CELL_BORDERS " xqlkmjwvtun~"
|
||||||
@ -861,11 +882,16 @@ struct style_range {
|
|||||||
};
|
};
|
||||||
TAILQ_HEAD(style_ranges, style_range);
|
TAILQ_HEAD(style_ranges, style_range);
|
||||||
|
|
||||||
|
/* Default style width and pad. */
|
||||||
|
#define STYLE_WIDTH_DEFAULT -1
|
||||||
|
#define STYLE_PAD_DEFAULT -1
|
||||||
|
|
||||||
/* Style default. */
|
/* Style default. */
|
||||||
enum style_default_type {
|
enum style_default_type {
|
||||||
STYLE_DEFAULT_BASE,
|
STYLE_DEFAULT_BASE,
|
||||||
STYLE_DEFAULT_PUSH,
|
STYLE_DEFAULT_PUSH,
|
||||||
STYLE_DEFAULT_POP
|
STYLE_DEFAULT_POP,
|
||||||
|
STYLE_DEFAULT_SET
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Style option. */
|
/* Style option. */
|
||||||
@ -881,6 +907,9 @@ struct style {
|
|||||||
u_int range_argument;
|
u_int range_argument;
|
||||||
char range_string[16];
|
char range_string[16];
|
||||||
|
|
||||||
|
int width;
|
||||||
|
int pad;
|
||||||
|
|
||||||
enum style_default_type default_type;
|
enum style_default_type default_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1012,6 +1041,9 @@ struct screen_redraw_ctx {
|
|||||||
int pane_status;
|
int pane_status;
|
||||||
enum pane_lines pane_lines;
|
enum pane_lines pane_lines;
|
||||||
|
|
||||||
|
int pane_scrollbars;
|
||||||
|
int pane_scrollbars_pos;
|
||||||
|
|
||||||
struct grid_cell no_pane_gc;
|
struct grid_cell no_pane_gc;
|
||||||
int no_pane_gc_set;
|
int no_pane_gc_set;
|
||||||
|
|
||||||
@ -1065,6 +1097,7 @@ struct window_mode {
|
|||||||
struct mouse_event *);
|
struct mouse_event *);
|
||||||
void (*formats)(struct window_mode_entry *,
|
void (*formats)(struct window_mode_entry *,
|
||||||
struct format_tree *);
|
struct format_tree *);
|
||||||
|
struct screen *(*get_screen)(struct window_mode_entry *);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Active window mode. */
|
/* Active window mode. */
|
||||||
@ -1129,7 +1162,12 @@ struct window_pane {
|
|||||||
#define PANE_STATUSDRAWN 0x400
|
#define PANE_STATUSDRAWN 0x400
|
||||||
#define PANE_EMPTY 0x800
|
#define PANE_EMPTY 0x800
|
||||||
#define PANE_STYLECHANGED 0x1000
|
#define PANE_STYLECHANGED 0x1000
|
||||||
#define PANE_UNSEENCHANGES 0x2000
|
#define PANE_THEMECHANGED 0x2000
|
||||||
|
#define PANE_UNSEENCHANGES 0x4000
|
||||||
|
#define PANE_REDRAWSCROLLBAR 0x8000
|
||||||
|
|
||||||
|
u_int sb_slider_y;
|
||||||
|
u_int sb_slider_h;
|
||||||
|
|
||||||
int argc;
|
int argc;
|
||||||
char **argv;
|
char **argv;
|
||||||
@ -1177,6 +1215,8 @@ struct window_pane {
|
|||||||
int control_bg;
|
int control_bg;
|
||||||
int control_fg;
|
int control_fg;
|
||||||
|
|
||||||
|
struct style scrollbar_style;
|
||||||
|
|
||||||
TAILQ_ENTRY(window_pane) entry; /* link in list of all panes */
|
TAILQ_ENTRY(window_pane) entry; /* link in list of all panes */
|
||||||
TAILQ_ENTRY(window_pane) sentry; /* link in list of last visited */
|
TAILQ_ENTRY(window_pane) sentry; /* link in list of last visited */
|
||||||
RB_ENTRY(window_pane) tree_entry;
|
RB_ENTRY(window_pane) tree_entry;
|
||||||
@ -1272,6 +1312,23 @@ TAILQ_HEAD(winlink_stack, winlink);
|
|||||||
#define PANE_STATUS_TOP 1
|
#define PANE_STATUS_TOP 1
|
||||||
#define PANE_STATUS_BOTTOM 2
|
#define PANE_STATUS_BOTTOM 2
|
||||||
|
|
||||||
|
/* Pane scrollbars option. */
|
||||||
|
#define PANE_SCROLLBARS_OFF 0
|
||||||
|
#define PANE_SCROLLBARS_MODAL 1
|
||||||
|
#define PANE_SCROLLBARS_ALWAYS 2
|
||||||
|
|
||||||
|
/* Pane scrollbars position option. */
|
||||||
|
#define PANE_SCROLLBARS_RIGHT 0
|
||||||
|
#define PANE_SCROLLBARS_LEFT 1
|
||||||
|
|
||||||
|
/* Pane scrollbars width, padding and fill character. */
|
||||||
|
#define PANE_SCROLLBARS_DEFAULT_PADDING 0
|
||||||
|
#define PANE_SCROLLBARS_DEFAULT_WIDTH 1
|
||||||
|
#define PANE_SCROLLBARS_CHARACTER ' '
|
||||||
|
|
||||||
|
/* True if screen in alternate screen. */
|
||||||
|
#define SCREEN_IS_ALTERNATE(s) ((s)->saved_grid != NULL)
|
||||||
|
|
||||||
/* Layout direction. */
|
/* Layout direction. */
|
||||||
enum layout_type {
|
enum layout_type {
|
||||||
LAYOUT_LEFTRIGHT,
|
LAYOUT_LEFTRIGHT,
|
||||||
@ -1342,8 +1399,7 @@ struct session {
|
|||||||
|
|
||||||
struct options *options;
|
struct options *options;
|
||||||
|
|
||||||
#define SESSION_PASTING 0x1
|
#define SESSION_ALERTED 0x1
|
||||||
#define SESSION_ALERTED 0x2
|
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
u_int attached;
|
u_int attached;
|
||||||
@ -1421,8 +1477,11 @@ struct mouse_event {
|
|||||||
|
|
||||||
/* Key event. */
|
/* Key event. */
|
||||||
struct key_event {
|
struct key_event {
|
||||||
key_code key;
|
key_code key;
|
||||||
struct mouse_event m;
|
struct mouse_event m;
|
||||||
|
|
||||||
|
char *buf;
|
||||||
|
size_t len;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Terminal definition. */
|
/* Terminal definition. */
|
||||||
@ -1508,6 +1567,7 @@ struct tty {
|
|||||||
#define TTY_HAVEXDA 0x200
|
#define TTY_HAVEXDA 0x200
|
||||||
#define TTY_SYNCING 0x400
|
#define TTY_SYNCING 0x400
|
||||||
#define TTY_HAVEDA2 0x800 /* Secondary DA. */
|
#define TTY_HAVEDA2 0x800 /* Secondary DA. */
|
||||||
|
#define TTY_WINSIZEQUERY 0x1000
|
||||||
#define TTY_ALL_REQUEST_FLAGS \
|
#define TTY_ALL_REQUEST_FLAGS \
|
||||||
(TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA)
|
(TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA)
|
||||||
int flags;
|
int flags;
|
||||||
@ -1518,6 +1578,9 @@ struct tty {
|
|||||||
u_int mouse_last_y;
|
u_int mouse_last_y;
|
||||||
u_int mouse_last_b;
|
u_int mouse_last_b;
|
||||||
int mouse_drag_flag;
|
int mouse_drag_flag;
|
||||||
|
int mouse_scrolling_flag;
|
||||||
|
int mouse_slider_mpos;
|
||||||
|
|
||||||
void (*mouse_drag_update)(struct client *,
|
void (*mouse_drag_update)(struct client *,
|
||||||
struct mouse_event *);
|
struct mouse_event *);
|
||||||
void (*mouse_drag_release)(struct client *,
|
void (*mouse_drag_release)(struct client *,
|
||||||
@ -1809,6 +1872,16 @@ struct overlay_ranges {
|
|||||||
u_int nx[OVERLAY_MAX_RANGES];
|
u_int nx[OVERLAY_MAX_RANGES];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Client theme, this is worked out from the background colour if not reported
|
||||||
|
* by terminal.
|
||||||
|
*/
|
||||||
|
enum client_theme {
|
||||||
|
THEME_UNKNOWN,
|
||||||
|
THEME_LIGHT,
|
||||||
|
THEME_DARK
|
||||||
|
};
|
||||||
|
|
||||||
/* Client connection. */
|
/* Client connection. */
|
||||||
typedef int (*prompt_input_cb)(struct client *, void *, const char *, int);
|
typedef int (*prompt_input_cb)(struct client *, void *, const char *, int);
|
||||||
typedef void (*prompt_free_cb)(void *);
|
typedef void (*prompt_free_cb)(void *);
|
||||||
@ -1839,6 +1912,7 @@ struct client {
|
|||||||
|
|
||||||
struct timeval creation_time;
|
struct timeval creation_time;
|
||||||
struct timeval activity_time;
|
struct timeval activity_time;
|
||||||
|
struct timeval last_activity_time;
|
||||||
|
|
||||||
struct environ *environ;
|
struct environ *environ;
|
||||||
struct format_job_tree *jobs;
|
struct format_job_tree *jobs;
|
||||||
@ -1867,6 +1941,7 @@ struct client {
|
|||||||
struct mouse_event click_event;
|
struct mouse_event click_event;
|
||||||
|
|
||||||
struct status_line status;
|
struct status_line status;
|
||||||
|
enum client_theme theme;
|
||||||
|
|
||||||
#define CLIENT_TERMINAL 0x1
|
#define CLIENT_TERMINAL 0x1
|
||||||
#define CLIENT_LOGIN 0x2
|
#define CLIENT_LOGIN 0x2
|
||||||
@ -1905,13 +1980,17 @@ struct client {
|
|||||||
#define CLIENT_WINDOWSIZECHANGED 0x400000000ULL
|
#define CLIENT_WINDOWSIZECHANGED 0x400000000ULL
|
||||||
#define CLIENT_CLIPBOARDBUFFER 0x800000000ULL
|
#define CLIENT_CLIPBOARDBUFFER 0x800000000ULL
|
||||||
#define CLIENT_BRACKETPASTING 0x1000000000ULL
|
#define CLIENT_BRACKETPASTING 0x1000000000ULL
|
||||||
|
#define CLIENT_ASSUMEPASTING 0x2000000000ULL
|
||||||
|
#define CLIENT_REDRAWSCROLLBARS 0x4000000000ULL
|
||||||
|
#define CLIENT_NO_DETACH_ON_DESTROY 0x8000000000ULL
|
||||||
#define CLIENT_ALLREDRAWFLAGS \
|
#define CLIENT_ALLREDRAWFLAGS \
|
||||||
(CLIENT_REDRAWWINDOW| \
|
(CLIENT_REDRAWWINDOW| \
|
||||||
CLIENT_REDRAWSTATUS| \
|
CLIENT_REDRAWSTATUS| \
|
||||||
CLIENT_REDRAWSTATUSALWAYS| \
|
CLIENT_REDRAWSTATUSALWAYS| \
|
||||||
CLIENT_REDRAWBORDERS| \
|
CLIENT_REDRAWBORDERS| \
|
||||||
CLIENT_REDRAWOVERLAY| \
|
CLIENT_REDRAWOVERLAY| \
|
||||||
CLIENT_REDRAWPANES)
|
CLIENT_REDRAWPANES| \
|
||||||
|
CLIENT_REDRAWSCROLLBARS)
|
||||||
#define CLIENT_UNATTACHEDFLAGS \
|
#define CLIENT_UNATTACHEDFLAGS \
|
||||||
(CLIENT_DEAD| \
|
(CLIENT_DEAD| \
|
||||||
CLIENT_SUSPENDED| \
|
CLIENT_SUSPENDED| \
|
||||||
@ -1935,8 +2014,10 @@ struct client {
|
|||||||
char *exit_message;
|
char *exit_message;
|
||||||
|
|
||||||
struct key_table *keytable;
|
struct key_table *keytable;
|
||||||
|
key_code last_key;
|
||||||
|
|
||||||
uint64_t redraw_panes;
|
uint64_t redraw_panes;
|
||||||
|
uint64_t redraw_scrollbars;
|
||||||
|
|
||||||
int message_ignore_keys;
|
int message_ignore_keys;
|
||||||
int message_ignore_styles;
|
int message_ignore_styles;
|
||||||
@ -1944,6 +2025,7 @@ struct client {
|
|||||||
struct event message_timer;
|
struct event message_timer;
|
||||||
|
|
||||||
char *prompt_string;
|
char *prompt_string;
|
||||||
|
struct format_tree *prompt_formats;
|
||||||
struct utf8_data *prompt_buffer;
|
struct utf8_data *prompt_buffer;
|
||||||
char *prompt_last;
|
char *prompt_last;
|
||||||
size_t prompt_index;
|
size_t prompt_index;
|
||||||
@ -1961,6 +2043,8 @@ struct client {
|
|||||||
#define PROMPT_INCREMENTAL 0x4
|
#define PROMPT_INCREMENTAL 0x4
|
||||||
#define PROMPT_NOFORMAT 0x8
|
#define PROMPT_NOFORMAT 0x8
|
||||||
#define PROMPT_KEY 0x10
|
#define PROMPT_KEY 0x10
|
||||||
|
#define PROMPT_ACCEPT 0x20
|
||||||
|
#define PROMPT_QUOTENEXT 0x40
|
||||||
int prompt_flags;
|
int prompt_flags;
|
||||||
enum prompt_type prompt_type;
|
enum prompt_type prompt_type;
|
||||||
int prompt_cursor;
|
int prompt_cursor;
|
||||||
@ -1984,6 +2068,7 @@ struct client {
|
|||||||
struct event overlay_timer;
|
struct event overlay_timer;
|
||||||
|
|
||||||
struct client_files files;
|
struct client_files files;
|
||||||
|
u_int source_file_depth;
|
||||||
|
|
||||||
u_int *clipboard_panes;
|
u_int *clipboard_panes;
|
||||||
u_int clipboard_npanes;
|
u_int clipboard_npanes;
|
||||||
@ -2310,10 +2395,13 @@ struct options_entry *options_match_get(struct options *, const char *, int *,
|
|||||||
int, int *);
|
int, int *);
|
||||||
const char *options_get_string(struct options *, const char *);
|
const char *options_get_string(struct options *, const char *);
|
||||||
long long options_get_number(struct options *, const char *);
|
long long options_get_number(struct options *, const char *);
|
||||||
|
const struct cmd_list *options_get_command(struct options *, const char *);
|
||||||
struct options_entry * printflike(4, 5) options_set_string(struct options *,
|
struct options_entry * printflike(4, 5) options_set_string(struct options *,
|
||||||
const char *, int, const char *, ...);
|
const char *, int, const char *, ...);
|
||||||
struct options_entry *options_set_number(struct options *, const char *,
|
struct options_entry *options_set_number(struct options *, const char *,
|
||||||
long long);
|
long long);
|
||||||
|
struct options_entry *options_set_command(struct options *, const char *,
|
||||||
|
struct cmd_list *);
|
||||||
int options_scope_from_name(struct args *, int,
|
int options_scope_from_name(struct args *, int,
|
||||||
const char *, struct cmd_find_state *, struct options **,
|
const char *, struct cmd_find_state *, struct options **,
|
||||||
char **);
|
char **);
|
||||||
@ -2341,6 +2429,8 @@ typedef void (*job_free_cb) (void *);
|
|||||||
#define JOB_NOWAIT 0x1
|
#define JOB_NOWAIT 0x1
|
||||||
#define JOB_KEEPWRITE 0x2
|
#define JOB_KEEPWRITE 0x2
|
||||||
#define JOB_PTY 0x4
|
#define JOB_PTY 0x4
|
||||||
|
#define JOB_DEFAULTSHELL 0x8
|
||||||
|
#define JOB_SHOWSTDERR 0x10
|
||||||
struct job *job_run(const char *, int, char **, struct environ *,
|
struct job *job_run(const char *, int, char **, struct environ *,
|
||||||
struct session *, const char *, job_update_cb,
|
struct session *, const char *, job_update_cb,
|
||||||
job_complete_cb, job_free_cb, void *, int, int, int);
|
job_complete_cb, job_free_cb, void *, int, int, int);
|
||||||
@ -2403,6 +2493,7 @@ void tty_cell(struct tty *, const struct grid_cell *,
|
|||||||
int tty_init(struct tty *, struct client *);
|
int tty_init(struct tty *, struct client *);
|
||||||
void tty_resize(struct tty *);
|
void tty_resize(struct tty *);
|
||||||
void tty_set_size(struct tty *, u_int, u_int, u_int, u_int);
|
void tty_set_size(struct tty *, u_int, u_int, u_int, u_int);
|
||||||
|
void tty_invalidate(struct tty *);
|
||||||
void tty_start_tty(struct tty *);
|
void tty_start_tty(struct tty *);
|
||||||
void tty_send_requests(struct tty *);
|
void tty_send_requests(struct tty *);
|
||||||
void tty_repeat_requests(struct tty *);
|
void tty_repeat_requests(struct tty *);
|
||||||
@ -2575,6 +2666,7 @@ int cmd_find_from_nothing(struct cmd_find_state *, int);
|
|||||||
|
|
||||||
/* cmd.c */
|
/* cmd.c */
|
||||||
extern const struct cmd_entry *cmd_table[];
|
extern const struct cmd_entry *cmd_table[];
|
||||||
|
const struct cmd_entry *cmd_find(const char *, char **);
|
||||||
void printflike(3, 4) cmd_log_argv(int, char **, const char *, ...);
|
void printflike(3, 4) cmd_log_argv(int, char **, const char *, ...);
|
||||||
void cmd_prepend_argv(int *, char ***, const char *);
|
void cmd_prepend_argv(int *, char ***, const char *);
|
||||||
void cmd_append_argv(int *, char ***, const char *);
|
void cmd_append_argv(int *, char ***, const char *);
|
||||||
@ -2594,12 +2686,12 @@ struct cmd *cmd_copy(struct cmd *, int, char **);
|
|||||||
void cmd_free(struct cmd *);
|
void cmd_free(struct cmd *);
|
||||||
char *cmd_print(struct cmd *);
|
char *cmd_print(struct cmd *);
|
||||||
struct cmd_list *cmd_list_new(void);
|
struct cmd_list *cmd_list_new(void);
|
||||||
struct cmd_list *cmd_list_copy(struct cmd_list *, int, char **);
|
struct cmd_list *cmd_list_copy(const struct cmd_list *, int, char **);
|
||||||
void cmd_list_append(struct cmd_list *, struct cmd *);
|
void cmd_list_append(struct cmd_list *, struct cmd *);
|
||||||
void cmd_list_append_all(struct cmd_list *, struct cmd_list *);
|
void cmd_list_append_all(struct cmd_list *, struct cmd_list *);
|
||||||
void cmd_list_move(struct cmd_list *, struct cmd_list *);
|
void cmd_list_move(struct cmd_list *, struct cmd_list *);
|
||||||
void cmd_list_free(struct cmd_list *);
|
void cmd_list_free(struct cmd_list *);
|
||||||
char *cmd_list_print(struct cmd_list *, int);
|
char *cmd_list_print(const struct cmd_list *, int);
|
||||||
struct cmd *cmd_list_first(struct cmd_list *);
|
struct cmd *cmd_list_first(struct cmd_list *);
|
||||||
struct cmd *cmd_list_next(struct cmd *);
|
struct cmd *cmd_list_next(struct cmd *);
|
||||||
int cmd_list_all_have(struct cmd_list *, int);
|
int cmd_list_all_have(struct cmd_list *, int);
|
||||||
@ -2665,7 +2757,7 @@ u_int cmdq_next(struct client *);
|
|||||||
struct cmdq_item *cmdq_running(struct client *);
|
struct cmdq_item *cmdq_running(struct client *);
|
||||||
void cmdq_guard(struct cmdq_item *, const char *, int);
|
void cmdq_guard(struct cmdq_item *, const char *, int);
|
||||||
void printflike(2, 3) cmdq_print(struct cmdq_item *, const char *, ...);
|
void printflike(2, 3) cmdq_print(struct cmdq_item *, const char *, ...);
|
||||||
void cmdq_print_data(struct cmdq_item *, int, struct evbuffer *);
|
void cmdq_print_data(struct cmdq_item *, struct evbuffer *);
|
||||||
void printflike(2, 3) cmdq_error(struct cmdq_item *, const char *, ...);
|
void printflike(2, 3) cmdq_error(struct cmdq_item *, const char *, ...);
|
||||||
|
|
||||||
/* cmd-wait-for.c */
|
/* cmd-wait-for.c */
|
||||||
@ -2824,7 +2916,7 @@ struct style_range *status_get_range(struct client *, u_int, u_int);
|
|||||||
void status_init(struct client *);
|
void status_init(struct client *);
|
||||||
void status_free(struct client *);
|
void status_free(struct client *);
|
||||||
int status_redraw(struct client *);
|
int status_redraw(struct client *);
|
||||||
void printflike(5, 6) status_message_set(struct client *, int, int, int,
|
void printflike(6, 7) status_message_set(struct client *, int, int, int, int,
|
||||||
const char *, ...);
|
const char *, ...);
|
||||||
void status_message_clear(struct client *);
|
void status_message_clear(struct client *);
|
||||||
int status_message_redraw(struct client *);
|
int status_message_redraw(struct client *);
|
||||||
@ -2849,6 +2941,7 @@ void recalculate_sizes(void);
|
|||||||
void recalculate_sizes_now(int);
|
void recalculate_sizes_now(int);
|
||||||
|
|
||||||
/* input.c */
|
/* input.c */
|
||||||
|
#define INPUT_BUF_DEFAULT_SIZE 1048576
|
||||||
struct input_ctx *input_init(struct window_pane *, struct bufferevent *,
|
struct input_ctx *input_init(struct window_pane *, struct bufferevent *,
|
||||||
struct colour_palette *);
|
struct colour_palette *);
|
||||||
void input_free(struct input_ctx *);
|
void input_free(struct input_ctx *);
|
||||||
@ -2860,6 +2953,7 @@ void input_parse_screen(struct input_ctx *, struct screen *,
|
|||||||
screen_write_init_ctx_cb, void *, u_char *, size_t);
|
screen_write_init_ctx_cb, void *, u_char *, size_t);
|
||||||
void input_reply_clipboard(struct bufferevent *, const char *, size_t,
|
void input_reply_clipboard(struct bufferevent *, const char *, size_t,
|
||||||
const char *);
|
const char *);
|
||||||
|
void input_set_buffer_size(size_t);
|
||||||
|
|
||||||
/* input-key.c */
|
/* input-key.c */
|
||||||
void input_key_build(void);
|
void input_key_build(void);
|
||||||
@ -2874,7 +2968,8 @@ int colour_join_rgb(u_char, u_char, u_char);
|
|||||||
void colour_split_rgb(int, u_char *, u_char *, u_char *);
|
void colour_split_rgb(int, u_char *, u_char *, u_char *);
|
||||||
int colour_force_rgb(int);
|
int colour_force_rgb(int);
|
||||||
const char *colour_tostring(int);
|
const char *colour_tostring(int);
|
||||||
int colour_fromstring(const char *s);
|
enum client_theme colour_totheme(int);
|
||||||
|
int colour_fromstring(const char *);
|
||||||
int colour_256toRGB(int);
|
int colour_256toRGB(int);
|
||||||
int colour_256to16(int);
|
int colour_256to16(int);
|
||||||
int colour_byname(const char *);
|
int colour_byname(const char *);
|
||||||
@ -2893,6 +2988,7 @@ int attributes_fromstring(const char *);
|
|||||||
/* grid.c */
|
/* grid.c */
|
||||||
extern const struct grid_cell grid_default_cell;
|
extern const struct grid_cell grid_default_cell;
|
||||||
void grid_empty_line(struct grid *, u_int, u_int);
|
void grid_empty_line(struct grid *, u_int, u_int);
|
||||||
|
void grid_set_tab(struct grid_cell *, u_int);
|
||||||
int grid_cells_equal(const struct grid_cell *, const struct grid_cell *);
|
int grid_cells_equal(const struct grid_cell *, const struct grid_cell *);
|
||||||
int grid_cells_look_equal(const struct grid_cell *,
|
int grid_cells_look_equal(const struct grid_cell *,
|
||||||
const struct grid_cell *);
|
const struct grid_cell *);
|
||||||
@ -2924,6 +3020,7 @@ void grid_reflow(struct grid *, u_int);
|
|||||||
void grid_wrap_position(struct grid *, u_int, u_int, u_int *, u_int *);
|
void grid_wrap_position(struct grid *, u_int, u_int, u_int *, u_int *);
|
||||||
void grid_unwrap_position(struct grid *, u_int *, u_int *, u_int, u_int);
|
void grid_unwrap_position(struct grid *, u_int *, u_int *, u_int, u_int);
|
||||||
u_int grid_line_length(struct grid *, u_int);
|
u_int grid_line_length(struct grid *, u_int);
|
||||||
|
int grid_in_set(struct grid *, u_int, u_int, const char *);
|
||||||
|
|
||||||
/* grid-reader.c */
|
/* grid-reader.c */
|
||||||
void grid_reader_start(struct grid_reader *, struct grid *, u_int, u_int);
|
void grid_reader_start(struct grid_reader *, struct grid *, u_int, u_int);
|
||||||
@ -3047,7 +3144,7 @@ void screen_write_alternateoff(struct screen_write_ctx *,
|
|||||||
|
|
||||||
/* screen-redraw.c */
|
/* screen-redraw.c */
|
||||||
void screen_redraw_screen(struct client *);
|
void screen_redraw_screen(struct client *);
|
||||||
void screen_redraw_pane(struct client *, struct window_pane *);
|
void screen_redraw_pane(struct client *, struct window_pane *, int);
|
||||||
|
|
||||||
/* screen.c */
|
/* screen.c */
|
||||||
void screen_init(struct screen *, u_int, u_int, u_int);
|
void screen_init(struct screen *, u_int, u_int, u_int);
|
||||||
@ -3055,6 +3152,7 @@ void screen_reinit(struct screen *);
|
|||||||
void screen_free(struct screen *);
|
void screen_free(struct screen *);
|
||||||
void screen_reset_tabs(struct screen *);
|
void screen_reset_tabs(struct screen *);
|
||||||
void screen_reset_hyperlinks(struct screen *);
|
void screen_reset_hyperlinks(struct screen *);
|
||||||
|
void screen_set_default_cursor(struct screen *, struct options *);
|
||||||
void screen_set_cursor_style(u_int, enum screen_cursor_style *, int *);
|
void screen_set_cursor_style(u_int, enum screen_cursor_style *, int *);
|
||||||
void screen_set_cursor_colour(struct screen *, int);
|
void screen_set_cursor_colour(struct screen *, int);
|
||||||
int screen_set_title(struct screen *, const char *);
|
int screen_set_title(struct screen *, const char *);
|
||||||
@ -3142,6 +3240,8 @@ void window_pane_reset_mode_all(struct window_pane *);
|
|||||||
int window_pane_key(struct window_pane *, struct client *,
|
int window_pane_key(struct window_pane *, struct client *,
|
||||||
struct session *, struct winlink *, key_code,
|
struct session *, struct winlink *, key_code,
|
||||||
struct mouse_event *);
|
struct mouse_event *);
|
||||||
|
void window_pane_paste(struct window_pane *, key_code, char *,
|
||||||
|
size_t);
|
||||||
int window_pane_visible(struct window_pane *);
|
int window_pane_visible(struct window_pane *);
|
||||||
int window_pane_exited(struct window_pane *);
|
int window_pane_exited(struct window_pane *);
|
||||||
u_int window_pane_search(struct window_pane *, const char *, int,
|
u_int window_pane_search(struct window_pane *, const char *, int,
|
||||||
@ -3169,6 +3269,14 @@ void window_pane_update_used_data(struct window_pane *,
|
|||||||
void window_set_fill_character(struct window *);
|
void window_set_fill_character(struct window *);
|
||||||
void window_pane_default_cursor(struct window_pane *);
|
void window_pane_default_cursor(struct window_pane *);
|
||||||
int window_pane_mode(struct window_pane *);
|
int window_pane_mode(struct window_pane *);
|
||||||
|
int window_pane_show_scrollbar(struct window_pane *, int);
|
||||||
|
int window_pane_get_bg(struct window_pane *);
|
||||||
|
int window_pane_get_fg(struct window_pane *);
|
||||||
|
int window_pane_get_fg_control_client(struct window_pane *);
|
||||||
|
int window_pane_get_bg_control_client(struct window_pane *);
|
||||||
|
int window_get_bg_client(struct window_pane *);
|
||||||
|
enum client_theme window_pane_get_theme(struct window_pane *);
|
||||||
|
void window_pane_send_theme_update(struct window_pane *);
|
||||||
|
|
||||||
/* layout.c */
|
/* layout.c */
|
||||||
u_int layout_count_cells(struct layout_cell *);
|
u_int layout_count_cells(struct layout_cell *);
|
||||||
@ -3222,6 +3330,7 @@ typedef int (*mode_tree_search_cb)(void *, void *, const char *);
|
|||||||
typedef void (*mode_tree_menu_cb)(void *, struct client *, key_code);
|
typedef void (*mode_tree_menu_cb)(void *, struct client *, key_code);
|
||||||
typedef u_int (*mode_tree_height_cb)(void *, u_int);
|
typedef u_int (*mode_tree_height_cb)(void *, u_int);
|
||||||
typedef key_code (*mode_tree_key_cb)(void *, void *, u_int);
|
typedef key_code (*mode_tree_key_cb)(void *, void *, u_int);
|
||||||
|
typedef int (*mode_tree_swap_cb)(void *, void *);
|
||||||
typedef void (*mode_tree_each_cb)(void *, void *, struct client *, key_code);
|
typedef void (*mode_tree_each_cb)(void *, void *, struct client *, key_code);
|
||||||
u_int mode_tree_count_tagged(struct mode_tree_data *);
|
u_int mode_tree_count_tagged(struct mode_tree_data *);
|
||||||
void *mode_tree_get_current(struct mode_tree_data *);
|
void *mode_tree_get_current(struct mode_tree_data *);
|
||||||
@ -3236,8 +3345,9 @@ void mode_tree_up(struct mode_tree_data *, int);
|
|||||||
int mode_tree_down(struct mode_tree_data *, int);
|
int 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,
|
||||||
mode_tree_menu_cb, mode_tree_height_cb, mode_tree_key_cb, void *,
|
mode_tree_menu_cb, mode_tree_height_cb, mode_tree_key_cb,
|
||||||
const struct menu_item *, const char **, u_int, struct screen **);
|
mode_tree_swap_cb, void *, const struct menu_item *, const char **,
|
||||||
|
u_int, struct screen **);
|
||||||
void mode_tree_zoom(struct mode_tree_data *, struct args *);
|
void mode_tree_zoom(struct mode_tree_data *, struct args *);
|
||||||
void mode_tree_build(struct mode_tree_data *);
|
void mode_tree_build(struct mode_tree_data *);
|
||||||
void mode_tree_free(struct mode_tree_data *);
|
void mode_tree_free(struct mode_tree_data *);
|
||||||
@ -3247,6 +3357,7 @@ struct mode_tree_item *mode_tree_add(struct mode_tree_data *,
|
|||||||
const char *, int);
|
const char *, int);
|
||||||
void mode_tree_draw_as_parent(struct mode_tree_item *);
|
void mode_tree_draw_as_parent(struct mode_tree_item *);
|
||||||
void mode_tree_no_tag(struct mode_tree_item *);
|
void mode_tree_no_tag(struct mode_tree_item *);
|
||||||
|
void mode_tree_align(struct mode_tree_item *, int);
|
||||||
void mode_tree_remove(struct mode_tree_data *, struct mode_tree_item *);
|
void mode_tree_remove(struct mode_tree_data *, struct mode_tree_item *);
|
||||||
void mode_tree_draw(struct mode_tree_data *);
|
void mode_tree_draw(struct mode_tree_data *);
|
||||||
int mode_tree_key(struct mode_tree_data *, struct client *, key_code *,
|
int mode_tree_key(struct mode_tree_data *, struct client *, key_code *,
|
||||||
@ -3274,11 +3385,15 @@ void printflike(3, 4) window_copy_add(struct window_pane *, int, const char *,
|
|||||||
...);
|
...);
|
||||||
void printflike(3, 0) window_copy_vadd(struct window_pane *, int, const char *,
|
void printflike(3, 0) window_copy_vadd(struct window_pane *, int, const char *,
|
||||||
va_list);
|
va_list);
|
||||||
|
void window_copy_scroll(struct window_pane *, int, u_int, int);
|
||||||
void window_copy_pageup(struct window_pane *, int);
|
void window_copy_pageup(struct window_pane *, int);
|
||||||
void window_copy_pagedown(struct window_pane *, int, int);
|
void window_copy_pagedown(struct window_pane *, int, int);
|
||||||
void window_copy_start_drag(struct client *, struct mouse_event *);
|
void window_copy_start_drag(struct client *, struct mouse_event *);
|
||||||
char *window_copy_get_word(struct window_pane *, u_int, u_int);
|
char *window_copy_get_word(struct window_pane *, u_int, u_int);
|
||||||
char *window_copy_get_line(struct window_pane *, u_int);
|
char *window_copy_get_line(struct window_pane *, u_int);
|
||||||
|
int window_copy_get_current_offset(struct window_pane *, u_int *,
|
||||||
|
u_int *);
|
||||||
|
char *window_copy_get_hyperlink(struct window_pane *, u_int, u_int);
|
||||||
|
|
||||||
/* window-option.c */
|
/* window-option.c */
|
||||||
extern const struct window_mode window_customize_mode;
|
extern const struct window_mode window_customize_mode;
|
||||||
@ -3325,9 +3440,12 @@ void control_notify_paste_buffer_deleted(const char *);
|
|||||||
|
|
||||||
/* session.c */
|
/* session.c */
|
||||||
extern struct sessions sessions;
|
extern struct sessions sessions;
|
||||||
|
extern struct session_groups session_groups;
|
||||||
extern u_int next_session_id;
|
extern u_int next_session_id;
|
||||||
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 *s2);
|
||||||
|
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 *);
|
||||||
@ -3360,11 +3478,12 @@ void session_group_synchronize_from(struct session *);
|
|||||||
u_int session_group_count(struct session_group *);
|
u_int session_group_count(struct session_group *);
|
||||||
u_int session_group_attached_count(struct session_group *);
|
u_int session_group_attached_count(struct session_group *);
|
||||||
void session_renumber_windows(struct session *);
|
void session_renumber_windows(struct session *);
|
||||||
|
void session_theme_changed(struct session *);
|
||||||
|
|
||||||
/* utf8.c */
|
/* utf8.c */
|
||||||
enum utf8_state utf8_towc (const struct utf8_data *, wchar_t *);
|
enum utf8_state utf8_towc (const struct utf8_data *, wchar_t *);
|
||||||
enum utf8_state utf8_fromwc(wchar_t wc, struct utf8_data *);
|
enum utf8_state utf8_fromwc(wchar_t wc, struct utf8_data *);
|
||||||
int utf8_in_table(wchar_t, const wchar_t *, u_int);
|
void utf8_update_width_cache(void);
|
||||||
utf8_char utf8_build_one(u_char);
|
utf8_char utf8_build_one(u_char);
|
||||||
enum utf8_state utf8_from_data(const struct utf8_data *, utf8_char *);
|
enum utf8_state utf8_from_data(const struct utf8_data *, utf8_char *);
|
||||||
void utf8_to_data(utf8_char, struct utf8_data *);
|
void utf8_to_data(utf8_char, struct utf8_data *);
|
||||||
@ -3463,6 +3582,8 @@ void style_apply(struct grid_cell *, struct options *,
|
|||||||
const char *, struct format_tree *);
|
const char *, struct format_tree *);
|
||||||
void style_set(struct style *, const struct grid_cell *);
|
void style_set(struct style *, const struct grid_cell *);
|
||||||
void style_copy(struct style *, struct style *);
|
void style_copy(struct style *, struct style *);
|
||||||
|
void style_set_scrollbar_style_from_option(struct style *,
|
||||||
|
struct options *);
|
||||||
|
|
||||||
/* spawn.c */
|
/* spawn.c */
|
||||||
struct winlink *spawn_window(struct spawn_context *, char **);
|
struct winlink *spawn_window(struct spawn_context *, char **);
|
||||||
@ -3481,7 +3602,7 @@ int image_scroll_up(struct screen *, u_int);
|
|||||||
|
|
||||||
/* image-sixel.c */
|
/* image-sixel.c */
|
||||||
#define SIXEL_COLOUR_REGISTERS 1024
|
#define SIXEL_COLOUR_REGISTERS 1024
|
||||||
struct sixel_image *sixel_parse(const char *, size_t, u_int, u_int);
|
struct sixel_image *sixel_parse(const char *, size_t, u_int, u_int, u_int);
|
||||||
void sixel_free(struct sixel_image *);
|
void sixel_free(struct sixel_image *);
|
||||||
void sixel_log(struct sixel_image *);
|
void sixel_log(struct sixel_image *);
|
||||||
void sixel_size_in_cells(struct sixel_image *, u_int *, u_int *);
|
void sixel_size_in_cells(struct sixel_image *, u_int *, u_int *);
|
||||||
|
@ -488,6 +488,10 @@ tty_default_features(int *feat, const char *name, u_int version)
|
|||||||
.features = TTY_FEATURES_BASE_MODERN_XTERM
|
.features = TTY_FEATURES_BASE_MODERN_XTERM
|
||||||
",cstyle,extkeys,margins,usstyle,sync,osc7,hyperlinks"
|
",cstyle,extkeys,margins,usstyle,sync,osc7,hyperlinks"
|
||||||
},
|
},
|
||||||
|
{ .name = "foot",
|
||||||
|
.features = TTY_FEATURES_BASE_MODERN_XTERM
|
||||||
|
",cstyle,extkeys"
|
||||||
|
},
|
||||||
{ .name = "XTerm",
|
{ .name = "XTerm",
|
||||||
/*
|
/*
|
||||||
* xterm also supports DECSLRM and DECFRA, but they can be
|
* xterm also supports DECSLRM and DECFRA, but they can be
|
||||||
|
169
tty-keys.c
169
tty-keys.c
@ -208,11 +208,15 @@ static const struct tty_default_key_raw tty_default_raw_keys[] = {
|
|||||||
{ "\033[O", KEYC_FOCUS_OUT },
|
{ "\033[O", KEYC_FOCUS_OUT },
|
||||||
|
|
||||||
/* Paste keys. */
|
/* Paste keys. */
|
||||||
{ "\033[200~", KEYC_PASTE_START },
|
{ "\033[200~", KEYC_PASTE_START|KEYC_IMPLIED_META },
|
||||||
{ "\033[201~", KEYC_PASTE_END },
|
{ "\033[201~", KEYC_PASTE_END|KEYC_IMPLIED_META },
|
||||||
|
|
||||||
/* Extended keys. */
|
/* Extended keys. */
|
||||||
{ "\033[1;5Z", '\011'|KEYC_CTRL|KEYC_SHIFT },
|
{ "\033[1;5Z", '\011'|KEYC_CTRL|KEYC_SHIFT },
|
||||||
|
|
||||||
|
/* Theme reporting. */
|
||||||
|
{ "\033[?997;1n", KEYC_REPORT_DARK_THEME },
|
||||||
|
{ "\033[?997;2n", KEYC_REPORT_LIGHT_THEME },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Default xterm keys. */
|
/* Default xterm keys. */
|
||||||
@ -654,6 +658,74 @@ tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key,
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Process window size change escape sequences. */
|
||||||
|
static int
|
||||||
|
tty_keys_winsz(struct tty *tty, const char *buf, size_t len, size_t *size)
|
||||||
|
{
|
||||||
|
struct client *c = tty->client;
|
||||||
|
size_t end;
|
||||||
|
char tmp[64];
|
||||||
|
u_int sx, sy, xpixel, ypixel, char_x, char_y;
|
||||||
|
|
||||||
|
*size = 0;
|
||||||
|
|
||||||
|
/* If we did not request this, ignore it. */
|
||||||
|
if (!(tty->flags & TTY_WINSIZEQUERY))
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
/* First two bytes are always \033[. */
|
||||||
|
if (buf[0] != '\033')
|
||||||
|
return (-1);
|
||||||
|
if (len == 1)
|
||||||
|
return (1);
|
||||||
|
if (buf[1] != '[')
|
||||||
|
return (-1);
|
||||||
|
if (len == 2)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop at either 't' or anything that isn't a
|
||||||
|
* number or ';'.
|
||||||
|
*/
|
||||||
|
for (end = 2; end < len && end != sizeof tmp; end++) {
|
||||||
|
if (buf[end] == 't')
|
||||||
|
break;
|
||||||
|
if (!isdigit((u_char)buf[end]) && buf[end] != ';')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (end == len)
|
||||||
|
return (1);
|
||||||
|
if (end == sizeof tmp || buf[end] != 't')
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
/* Copy to the buffer. */
|
||||||
|
memcpy(tmp, buf + 2, end - 2);
|
||||||
|
tmp[end - 2] = '\0';
|
||||||
|
|
||||||
|
/* Try to parse the window size sequence. */
|
||||||
|
if (sscanf(tmp, "8;%u;%u", &sy, &sx) == 2) {
|
||||||
|
/* Window size in characters. */
|
||||||
|
tty_set_size(tty, sx, sy, tty->xpixel, tty->ypixel);
|
||||||
|
|
||||||
|
*size = end + 1;
|
||||||
|
return (0);
|
||||||
|
} else if (sscanf(tmp, "4;%u;%u", &ypixel, &xpixel) == 2) {
|
||||||
|
/* Window size in pixels. */
|
||||||
|
char_x = (xpixel && tty->sx) ? xpixel / tty->sx : 0;
|
||||||
|
char_y = (ypixel && tty->sy) ? ypixel / tty->sy : 0;
|
||||||
|
tty_set_size(tty, tty->sx, tty->sy, char_x, char_y);
|
||||||
|
tty_invalidate(tty);
|
||||||
|
|
||||||
|
tty->flags &= ~TTY_WINSIZEQUERY;
|
||||||
|
*size = end + 1;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("%s: unrecognized window size sequence: %s", c->name, tmp);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Process at least one key in the buffer. Return 0 if no keys present. */
|
/* Process at least one key in the buffer. Return 0 if no keys present. */
|
||||||
int
|
int
|
||||||
tty_keys_next(struct tty *tty)
|
tty_keys_next(struct tty *tty)
|
||||||
@ -723,10 +795,12 @@ tty_keys_next(struct tty *tty)
|
|||||||
switch (tty_keys_colours(tty, buf, len, &size, &tty->fg, &tty->bg)) {
|
switch (tty_keys_colours(tty, buf, len, &size, &tty->fg, &tty->bg)) {
|
||||||
case 0: /* yes */
|
case 0: /* yes */
|
||||||
key = KEYC_UNKNOWN;
|
key = KEYC_UNKNOWN;
|
||||||
|
session_theme_changed(c->session);
|
||||||
goto complete_key;
|
goto complete_key;
|
||||||
case -1: /* no, or not valid */
|
case -1: /* no, or not valid */
|
||||||
break;
|
break;
|
||||||
case 1: /* partial */
|
case 1: /* partial */
|
||||||
|
session_theme_changed(c->session);
|
||||||
goto partial_key;
|
goto partial_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -754,6 +828,17 @@ tty_keys_next(struct tty *tty)
|
|||||||
goto partial_key;
|
goto partial_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for window size query */
|
||||||
|
switch (tty_keys_winsz(tty, buf, len, &size)) {
|
||||||
|
case 0: /* yes */
|
||||||
|
key = KEYC_UNKNOWN;
|
||||||
|
goto complete_key;
|
||||||
|
case -1: /* no, or not valid */
|
||||||
|
break;
|
||||||
|
case 1: /* partial */
|
||||||
|
goto partial_key;
|
||||||
|
}
|
||||||
|
|
||||||
first_key:
|
first_key:
|
||||||
/* Try to lookup complete key. */
|
/* Try to lookup complete key. */
|
||||||
n = tty_keys_next1(tty, buf, len, &key, &size, expired);
|
n = tty_keys_next1(tty, buf, len, &key, &size, expired);
|
||||||
@ -806,6 +891,17 @@ first_key:
|
|||||||
if ((key & KEYC_MASK_KEY) == C0_NUL)
|
if ((key & KEYC_MASK_KEY) == C0_NUL)
|
||||||
key = ' ' | KEYC_CTRL | (key & KEYC_META);
|
key = ' ' | KEYC_CTRL | (key & KEYC_META);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for backspace key using termios VERASE - the terminfo
|
||||||
|
* kbs entry is extremely unreliable, so cannot be safely
|
||||||
|
* used. termios should have a better idea.
|
||||||
|
*/
|
||||||
|
bspace = tty->tio.c_cc[VERASE];
|
||||||
|
if (bspace != _POSIX_VDISABLE && key == bspace) {
|
||||||
|
log_debug("%s: key %#llx is backspace", c->name, key);
|
||||||
|
key = KEYC_BSPACE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fix up all C0 control codes that don't have a dedicated key into
|
* Fix up all C0 control codes that don't have a dedicated key into
|
||||||
* corresponding Ctrl keys. Convert characters in the A-Z range into
|
* corresponding Ctrl keys. Convert characters in the A-Z range into
|
||||||
@ -841,6 +937,11 @@ partial_key:
|
|||||||
delay = options_get_number(global_options, "escape-time");
|
delay = options_get_number(global_options, "escape-time");
|
||||||
if (delay == 0)
|
if (delay == 0)
|
||||||
delay = 1;
|
delay = 1;
|
||||||
|
if ((tty->flags & TTY_ALL_REQUEST_FLAGS) != TTY_ALL_REQUEST_FLAGS) {
|
||||||
|
log_debug("%s: increasing delay for active DA query", c->name);
|
||||||
|
if (delay < 500)
|
||||||
|
delay = 500;
|
||||||
|
}
|
||||||
tv.tv_sec = delay / 1000;
|
tv.tv_sec = delay / 1000;
|
||||||
tv.tv_usec = (delay % 1000) * 1000L;
|
tv.tv_usec = (delay % 1000) * 1000L;
|
||||||
|
|
||||||
@ -856,18 +957,6 @@ partial_key:
|
|||||||
complete_key:
|
complete_key:
|
||||||
log_debug("%s: complete key %.*s %#llx", c->name, (int)size, buf, key);
|
log_debug("%s: complete key %.*s %#llx", c->name, (int)size, buf, key);
|
||||||
|
|
||||||
/*
|
|
||||||
* Check for backspace key using termios VERASE - the terminfo
|
|
||||||
* kbs entry is extremely unreliable, so cannot be safely
|
|
||||||
* used. termios should have a better idea.
|
|
||||||
*/
|
|
||||||
bspace = tty->tio.c_cc[VERASE];
|
|
||||||
if (bspace != _POSIX_VDISABLE && (key & KEYC_MASK_KEY) == bspace)
|
|
||||||
key = (key & KEYC_MASK_MODIFIERS)|KEYC_BSPACE;
|
|
||||||
|
|
||||||
/* Remove data from buffer. */
|
|
||||||
evbuffer_drain(tty->in, size);
|
|
||||||
|
|
||||||
/* Remove key timer. */
|
/* Remove key timer. */
|
||||||
if (event_initialized(&tty->key_timer))
|
if (event_initialized(&tty->key_timer))
|
||||||
evtimer_del(&tty->key_timer);
|
evtimer_del(&tty->key_timer);
|
||||||
@ -886,13 +975,23 @@ complete_key:
|
|||||||
|
|
||||||
/* Fire the key. */
|
/* Fire the key. */
|
||||||
if (key != KEYC_UNKNOWN) {
|
if (key != KEYC_UNKNOWN) {
|
||||||
event = xmalloc(sizeof *event);
|
event = xcalloc(1, sizeof *event);
|
||||||
event->key = key;
|
event->key = key;
|
||||||
memcpy(&event->m, &m, sizeof event->m);
|
memcpy(&event->m, &m, sizeof event->m);
|
||||||
if (!server_client_handle_key(c, event))
|
|
||||||
|
event->buf = xmalloc(size);
|
||||||
|
event->len = size;
|
||||||
|
memcpy (event->buf, buf, event->len);
|
||||||
|
|
||||||
|
if (!server_client_handle_key(c, event)) {
|
||||||
|
free(event->buf);
|
||||||
free(event);
|
free(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remove data from buffer. */
|
||||||
|
evbuffer_drain(tty->in, size);
|
||||||
|
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
discard_key:
|
discard_key:
|
||||||
@ -930,7 +1029,7 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
|
|||||||
u_int number, modifiers;
|
u_int number, modifiers;
|
||||||
char tmp[64];
|
char tmp[64];
|
||||||
cc_t bspace;
|
cc_t bspace;
|
||||||
key_code nkey;
|
key_code nkey, onlykey;
|
||||||
struct utf8_data ud;
|
struct utf8_data ud;
|
||||||
utf8_char uc;
|
utf8_char uc;
|
||||||
|
|
||||||
@ -962,8 +1061,8 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
|
|||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
/* Copy to the buffer. */
|
/* Copy to the buffer. */
|
||||||
memcpy(tmp, buf + 2, end);
|
memcpy(tmp, buf + 2, end - 2);
|
||||||
tmp[end] = '\0';
|
tmp[end - 2] = '\0';
|
||||||
|
|
||||||
/* Try to parse either form of key. */
|
/* Try to parse either form of key. */
|
||||||
if (buf[end] == '~') {
|
if (buf[end] == '~') {
|
||||||
@ -983,7 +1082,7 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
|
|||||||
nkey = number;
|
nkey = number;
|
||||||
|
|
||||||
/* Convert UTF-32 codepoint into internal representation. */
|
/* Convert UTF-32 codepoint into internal representation. */
|
||||||
if (nkey & ~0x7f) {
|
if (nkey != KEYC_BSPACE && nkey & ~0x7f) {
|
||||||
if (utf8_fromwc(nkey, &ud) == UTF8_DONE &&
|
if (utf8_fromwc(nkey, &ud) == UTF8_DONE &&
|
||||||
utf8_from_data(&ud, &uc) == UTF8_DONE)
|
utf8_from_data(&ud, &uc) == UTF8_DONE)
|
||||||
nkey = uc;
|
nkey = uc;
|
||||||
@ -994,13 +1093,7 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
|
|||||||
/* Update the modifiers. */
|
/* Update the modifiers. */
|
||||||
if (modifiers > 0) {
|
if (modifiers > 0) {
|
||||||
modifiers--;
|
modifiers--;
|
||||||
/*
|
if (modifiers & 1)
|
||||||
* The Shift modifier may not be reported in some input modes,
|
|
||||||
* which is unfortunate, as in general case determining if a
|
|
||||||
* character is shifted or not requires knowing the input
|
|
||||||
* keyboard layout. So we only fix up the trivial case.
|
|
||||||
*/
|
|
||||||
if (modifiers & 1 || (nkey >= 'A' && nkey <= 'Z'))
|
|
||||||
nkey |= KEYC_SHIFT;
|
nkey |= KEYC_SHIFT;
|
||||||
if (modifiers & 2)
|
if (modifiers & 2)
|
||||||
nkey |= (KEYC_META|KEYC_IMPLIED_META); /* Alt */
|
nkey |= (KEYC_META|KEYC_IMPLIED_META); /* Alt */
|
||||||
@ -1014,6 +1107,26 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
|
|||||||
if ((nkey & KEYC_MASK_KEY) == '\011' && (nkey & KEYC_SHIFT))
|
if ((nkey & KEYC_MASK_KEY) == '\011' && (nkey & KEYC_SHIFT))
|
||||||
nkey = KEYC_BTAB | (nkey & ~KEYC_MASK_KEY & ~KEYC_SHIFT);
|
nkey = KEYC_BTAB | (nkey & ~KEYC_MASK_KEY & ~KEYC_SHIFT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Deal with the Shift modifier when present alone. The problem is that
|
||||||
|
* in mode 2 some terminals would report shifted keys, like S-a, as
|
||||||
|
* just A, and some as S-A.
|
||||||
|
*
|
||||||
|
* Because we need an unambiguous internal representation, and because
|
||||||
|
* restoring the Shift modifier when it's missing would require knowing
|
||||||
|
* the keyboard layout, and because S-A would cause a lot of issues
|
||||||
|
* downstream, we choose to lose the Shift for all printable
|
||||||
|
* characters.
|
||||||
|
*
|
||||||
|
* That still leaves some ambiguity, such as C-S-A vs. C-A, but that's
|
||||||
|
* OK, and applications can handle that.
|
||||||
|
*/
|
||||||
|
onlykey = nkey & KEYC_MASK_KEY;
|
||||||
|
if (((onlykey > 0x20 && onlykey < 0x7f) ||
|
||||||
|
KEYC_IS_UNICODE(nkey)) &&
|
||||||
|
(nkey & KEYC_MASK_MODIFIERS) == KEYC_SHIFT)
|
||||||
|
nkey &= ~KEYC_SHIFT;
|
||||||
|
|
||||||
if (log_get_level() != 0) {
|
if (log_get_level() != 0) {
|
||||||
log_debug("%s: extended key %.*s is %llx (%s)", c->name,
|
log_debug("%s: extended key %.*s is %llx (%s)", c->name,
|
||||||
(int)*size, buf, nkey, key_string_lookup_key(nkey, 1));
|
(int)*size, buf, nkey, key_string_lookup_key(nkey, 1));
|
||||||
@ -1492,6 +1605,8 @@ tty_keys_extended_device_attributes(struct tty *tty, const char *buf,
|
|||||||
tty_default_features(features, "XTerm", 0);
|
tty_default_features(features, "XTerm", 0);
|
||||||
else if (strncmp(tmp, "mintty ", 7) == 0)
|
else if (strncmp(tmp, "mintty ", 7) == 0)
|
||||||
tty_default_features(features, "mintty", 0);
|
tty_default_features(features, "mintty", 0);
|
||||||
|
else if (strncmp(tmp, "foot(", 5) == 0)
|
||||||
|
tty_default_features(features, "foot", 0);
|
||||||
log_debug("%s: received extended DA %.*s", c->name, (int)*size, buf);
|
log_debug("%s: received extended DA %.*s", c->name, (int)*size, buf);
|
||||||
|
|
||||||
free(c->term_type);
|
free(c->term_type);
|
||||||
|
64
tty.c
64
tty.c
@ -42,7 +42,6 @@ static void tty_cursor_pane(struct tty *, const struct tty_ctx *, u_int,
|
|||||||
u_int);
|
u_int);
|
||||||
static void tty_cursor_pane_unless_wrap(struct tty *,
|
static void tty_cursor_pane_unless_wrap(struct tty *,
|
||||||
const struct tty_ctx *, u_int, u_int);
|
const struct tty_ctx *, u_int, u_int);
|
||||||
static void tty_invalidate(struct tty *);
|
|
||||||
static void tty_colours(struct tty *, const struct grid_cell *);
|
static void tty_colours(struct tty *, const struct grid_cell *);
|
||||||
static void tty_check_fg(struct tty *, struct colour_palette *,
|
static void tty_check_fg(struct tty *, struct colour_palette *,
|
||||||
struct grid_cell *);
|
struct grid_cell *);
|
||||||
@ -140,6 +139,14 @@ tty_resize(struct tty *tty)
|
|||||||
ypixel = 0;
|
ypixel = 0;
|
||||||
} else
|
} else
|
||||||
ypixel = ws.ws_ypixel / sy;
|
ypixel = ws.ws_ypixel / sy;
|
||||||
|
|
||||||
|
if ((xpixel == 0 || ypixel == 0) &&
|
||||||
|
tty->out != NULL &&
|
||||||
|
!(tty->flags & TTY_WINSIZEQUERY) &&
|
||||||
|
(tty->term->flags & TERM_VT100LIKE)) {
|
||||||
|
tty_puts(tty, "\033[18t\033[14t");
|
||||||
|
tty->flags |= TTY_WINSIZEQUERY;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sx = 80;
|
sx = 80;
|
||||||
sy = 24;
|
sy = 24;
|
||||||
@ -349,6 +356,11 @@ tty_start_tty(struct tty *tty)
|
|||||||
if (tty_term_has(tty->term, TTYC_ENBP))
|
if (tty_term_has(tty->term, TTYC_ENBP))
|
||||||
tty_putcode(tty, TTYC_ENBP);
|
tty_putcode(tty, TTYC_ENBP);
|
||||||
|
|
||||||
|
if (tty->term->flags & TERM_VT100LIKE) {
|
||||||
|
/* Subscribe to theme changes and request theme now. */
|
||||||
|
tty_puts(tty, "\033[?2031h\033[?996n");
|
||||||
|
}
|
||||||
|
|
||||||
evtimer_set(&tty->start_timer, tty_start_timer_callback, tty);
|
evtimer_set(&tty->start_timer, tty_start_timer_callback, tty);
|
||||||
evtimer_add(&tty->start_timer, &tv);
|
evtimer_add(&tty->start_timer, &tv);
|
||||||
|
|
||||||
@ -461,6 +473,9 @@ tty_stop_tty(struct tty *tty)
|
|||||||
tty_raw(tty, tty_term_string(tty->term, TTYC_DSMG));
|
tty_raw(tty, tty_term_string(tty->term, TTYC_DSMG));
|
||||||
tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP));
|
tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP));
|
||||||
|
|
||||||
|
if (tty->term->flags & TERM_VT100LIKE)
|
||||||
|
tty_raw(tty, "\033[?2031l");
|
||||||
|
|
||||||
setblocking(c->fd, 1);
|
setblocking(c->fd, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1359,6 +1374,8 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc)
|
|||||||
/* Characters less than 0x7f are always fine, no matter what. */
|
/* Characters less than 0x7f are always fine, no matter what. */
|
||||||
if (gc->data.size == 1 && *gc->data.data < 0x7f)
|
if (gc->data.size == 1 && *gc->data.data < 0x7f)
|
||||||
return (gc);
|
return (gc);
|
||||||
|
if (gc->flags & GRID_FLAG_TAB)
|
||||||
|
return (gc);
|
||||||
|
|
||||||
/* UTF-8 terminal and a UTF-8 character - fine. */
|
/* UTF-8 terminal and a UTF-8 character - fine. */
|
||||||
if (tty->client->flags & CLIENT_UTF8)
|
if (tty->client->flags & CLIENT_UTF8)
|
||||||
@ -2369,7 +2386,7 @@ tty_reset(struct tty *tty)
|
|||||||
memcpy(&tty->last_cell, &grid_default_cell, sizeof tty->last_cell);
|
memcpy(&tty->last_cell, &grid_default_cell, sizeof tty->last_cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
tty_invalidate(struct tty *tty)
|
tty_invalidate(struct tty *tty)
|
||||||
{
|
{
|
||||||
memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell);
|
memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell);
|
||||||
@ -2739,8 +2756,7 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc,
|
|||||||
if (changed & GRID_ATTR_ITALICS)
|
if (changed & GRID_ATTR_ITALICS)
|
||||||
tty_set_italics(tty);
|
tty_set_italics(tty);
|
||||||
if (changed & GRID_ATTR_ALL_UNDERSCORE) {
|
if (changed & GRID_ATTR_ALL_UNDERSCORE) {
|
||||||
if ((changed & GRID_ATTR_UNDERSCORE) ||
|
if (changed & GRID_ATTR_UNDERSCORE)
|
||||||
!tty_term_has(tty->term, TTYC_SMULX))
|
|
||||||
tty_putcode(tty, TTYC_SMUL);
|
tty_putcode(tty, TTYC_SMUL);
|
||||||
else if (changed & GRID_ATTR_UNDERSCORE_2)
|
else if (changed & GRID_ATTR_UNDERSCORE_2)
|
||||||
tty_putcode_i(tty, TTYC_SMULX, 2);
|
tty_putcode_i(tty, TTYC_SMULX, 2);
|
||||||
@ -2865,13 +2881,23 @@ tty_check_fg(struct tty *tty, struct colour_palette *palette,
|
|||||||
/* Is this a 256-colour colour? */
|
/* Is this a 256-colour colour? */
|
||||||
if (gc->fg & COLOUR_FLAG_256) {
|
if (gc->fg & COLOUR_FLAG_256) {
|
||||||
/* And not a 256 colour mode? */
|
/* And not a 256 colour mode? */
|
||||||
if (colours < 256) {
|
if (colours >= 256)
|
||||||
gc->fg = colour_256to16(gc->fg);
|
return;
|
||||||
if (gc->fg & 8) {
|
gc->fg = colour_256to16(gc->fg);
|
||||||
gc->fg &= 7;
|
if (~gc->fg & 8)
|
||||||
if (colours >= 16)
|
return;
|
||||||
gc->fg += 90;
|
gc->fg &= 7;
|
||||||
}
|
if (colours >= 16)
|
||||||
|
gc->fg += 90;
|
||||||
|
else {
|
||||||
|
/*
|
||||||
|
* Mapping to black-on-black or white-on-white is not
|
||||||
|
* much use, so change the foreground.
|
||||||
|
*/
|
||||||
|
if (gc->fg == 0 && gc->bg == 0)
|
||||||
|
gc->fg = 7;
|
||||||
|
else if (gc->fg == 7 && gc->bg == 7)
|
||||||
|
gc->fg = 0;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2919,14 +2945,14 @@ tty_check_bg(struct tty *tty, struct colour_palette *palette,
|
|||||||
* palette. Bold background doesn't exist portably, so just
|
* palette. Bold background doesn't exist portably, so just
|
||||||
* discard the bold bit if set.
|
* discard the bold bit if set.
|
||||||
*/
|
*/
|
||||||
if (colours < 256) {
|
if (colours >= 256)
|
||||||
gc->bg = colour_256to16(gc->bg);
|
return;
|
||||||
if (gc->bg & 8) {
|
gc->bg = colour_256to16(gc->bg);
|
||||||
gc->bg &= 7;
|
if (~gc->bg & 8)
|
||||||
if (colours >= 16)
|
return;
|
||||||
gc->bg += 90;
|
gc->bg &= 7;
|
||||||
}
|
if (colours >= 16)
|
||||||
}
|
gc->bg += 90;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,40 +24,6 @@
|
|||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
static const wchar_t utf8_modifier_table[] = {
|
|
||||||
0x1F1E6,
|
|
||||||
0x1F1E7,
|
|
||||||
0x1F1E8,
|
|
||||||
0x1F1E9,
|
|
||||||
0x1F1EA,
|
|
||||||
0x1F1EB,
|
|
||||||
0x1F1EC,
|
|
||||||
0x1F1ED,
|
|
||||||
0x1F1EE,
|
|
||||||
0x1F1EF,
|
|
||||||
0x1F1F0,
|
|
||||||
0x1F1F1,
|
|
||||||
0x1F1F2,
|
|
||||||
0x1F1F3,
|
|
||||||
0x1F1F4,
|
|
||||||
0x1F1F5,
|
|
||||||
0x1F1F6,
|
|
||||||
0x1F1F7,
|
|
||||||
0x1F1F8,
|
|
||||||
0x1F1F9,
|
|
||||||
0x1F1FA,
|
|
||||||
0x1F1FB,
|
|
||||||
0x1F1FC,
|
|
||||||
0x1F1FD,
|
|
||||||
0x1F1FE,
|
|
||||||
0x1F1FF,
|
|
||||||
0x1F3FB,
|
|
||||||
0x1F3FC,
|
|
||||||
0x1F3FD,
|
|
||||||
0x1F3FE,
|
|
||||||
0x1F3FF
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Has this got a zero width joiner at the end? */
|
/* Has this got a zero width joiner at the end? */
|
||||||
int
|
int
|
||||||
utf8_has_zwj(const struct utf8_data *ud)
|
utf8_has_zwj(const struct utf8_data *ud)
|
||||||
@ -93,8 +59,39 @@ utf8_is_modifier(const struct utf8_data *ud)
|
|||||||
|
|
||||||
if (utf8_towc(ud, &wc) != UTF8_DONE)
|
if (utf8_towc(ud, &wc) != UTF8_DONE)
|
||||||
return (0);
|
return (0);
|
||||||
if (!utf8_in_table(wc, utf8_modifier_table,
|
switch (wc) {
|
||||||
nitems(utf8_modifier_table)))
|
case 0x1F1E6:
|
||||||
return (0);
|
case 0x1F1E7:
|
||||||
return (1);
|
case 0x1F1E8:
|
||||||
|
case 0x1F1E9:
|
||||||
|
case 0x1F1EA:
|
||||||
|
case 0x1F1EB:
|
||||||
|
case 0x1F1EC:
|
||||||
|
case 0x1F1ED:
|
||||||
|
case 0x1F1EE:
|
||||||
|
case 0x1F1EF:
|
||||||
|
case 0x1F1F0:
|
||||||
|
case 0x1F1F1:
|
||||||
|
case 0x1F1F2:
|
||||||
|
case 0x1F1F3:
|
||||||
|
case 0x1F1F4:
|
||||||
|
case 0x1F1F5:
|
||||||
|
case 0x1F1F6:
|
||||||
|
case 0x1F1F7:
|
||||||
|
case 0x1F1F8:
|
||||||
|
case 0x1F1F9:
|
||||||
|
case 0x1F1FA:
|
||||||
|
case 0x1F1FB:
|
||||||
|
case 0x1F1FC:
|
||||||
|
case 0x1F1FD:
|
||||||
|
case 0x1F1FE:
|
||||||
|
case 0x1F1FF:
|
||||||
|
case 0x1F3FB:
|
||||||
|
case 0x1F3FC:
|
||||||
|
case 0x1F3FD:
|
||||||
|
case 0x1F3FE:
|
||||||
|
case 0x1F3FF:
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user