mirror of
https://github.com/tmux/tmux.git
synced 2026-03-12 19:45:46 +00:00
Compare commits
309 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c22470bd14 | ||
|
|
31cb95893e | ||
|
|
52b8274285 | ||
|
|
a924694820 | ||
|
|
0a94dbe051 | ||
|
|
ebc9dcb3bb | ||
|
|
f31847db62 | ||
|
|
e337c1ba7d | ||
|
|
db5a7c1740 | ||
|
|
53914e50b9 | ||
|
|
e252984993 | ||
|
|
17bc11bd15 | ||
|
|
1a3a973bd0 | ||
|
|
e4eec92852 | ||
|
|
75d112c484 | ||
|
|
a05c3a7aa6 | ||
|
|
47795d1695 | ||
|
|
7cdb1cfc8d | ||
|
|
8827b7f9a6 | ||
|
|
7eeb479705 | ||
|
|
8d137233a9 | ||
|
|
05d07413ff | ||
|
|
b8360504f3 | ||
|
|
a062650d4b | ||
|
|
f012db9be9 | ||
|
|
299d4f3aaa | ||
|
|
eba6cf61c9 | ||
|
|
0ec410689c | ||
|
|
e0fd295054 | ||
|
|
99a8469ee4 | ||
|
|
12255411f2 | ||
|
|
c0116b2c5b | ||
|
|
799a154b91 | ||
|
|
793f4d89d6 | ||
|
|
90cd045cf3 | ||
|
|
94f6488f0e | ||
|
|
d4bf4bd7c7 | ||
|
|
522d1bd309 | ||
|
|
a21de4c483 | ||
|
|
714311a696 | ||
|
|
9f0904ce6f | ||
|
|
ae3eba6e08 | ||
|
|
6b332127ca | ||
|
|
bd40d704e2 | ||
|
|
65e5e14561 | ||
|
|
103e44d936 | ||
|
|
097973e3d5 | ||
|
|
5fef946df4 | ||
|
|
023c2c5392 | ||
|
|
e90d4a6021 | ||
|
|
2e84d1cf03 | ||
|
|
6431005169 | ||
|
|
9beb3eb593 | ||
|
|
6dee409981 | ||
|
|
f3fc81b178 | ||
|
|
463bd8abb9 | ||
|
|
a65a6d62d1 | ||
|
|
207789dc2d | ||
|
|
d7586d3d65 | ||
|
|
f8d3d247d8 | ||
|
|
6b0fa14470 | ||
|
|
a69211aff5 | ||
|
|
930245d7ff | ||
|
|
0dc8b7d5d8 | ||
|
|
19a3a9ee20 | ||
|
|
f3e01ecc42 | ||
|
|
6c260af56d | ||
|
|
e817821104 | ||
|
|
f006116bac | ||
|
|
43431e7e84 | ||
|
|
eb8b51effc | ||
|
|
389cf63cbc | ||
|
|
2148fe33cd | ||
|
|
1a6540fea0 | ||
|
|
7d702f3cef | ||
|
|
d0c462f718 | ||
|
|
238d2aa870 | ||
|
|
6bb505eb73 | ||
|
|
83b9807370 | ||
|
|
3e6e533779 | ||
|
|
27bfb56ad5 | ||
|
|
c49f2a0365 | ||
|
|
3e3eb1dd0f | ||
|
|
a4fe7e81c8 | ||
|
|
4ce26b0393 | ||
|
|
82bf0f4d48 | ||
|
|
8590ee65e6 | ||
|
|
d67b99c7e4 | ||
|
|
092c7bfeb8 | ||
|
|
bf2cf33fc6 | ||
|
|
75aeb733f2 | ||
|
|
723010ba72 | ||
|
|
7ca2e2fe88 | ||
|
|
9d450cc6d0 | ||
|
|
5571d7a21c | ||
|
|
e353d0cab3 | ||
|
|
282f7fbd37 | ||
|
|
b68fc7f104 | ||
|
|
54dfe36340 | ||
|
|
c4f4904f9b | ||
|
|
d769fec8d6 | ||
|
|
f1ce611345 | ||
|
|
3856116069 | ||
|
|
afe231c94c | ||
|
|
ae4cccb4f1 | ||
|
|
98ee93bde3 | ||
|
|
87d82170a6 | ||
|
|
3a7e15511b | ||
|
|
e128c7fcd8 | ||
|
|
8db89f8efb | ||
|
|
c271cb9ff8 | ||
|
|
6e0c663a89 | ||
|
|
56246c2936 | ||
|
|
54da493476 | ||
|
|
82ebd98c5f | ||
|
|
831c67c2d8 | ||
|
|
d6f7be6345 | ||
|
|
eb064e8a62 | ||
|
|
9b83b1daa6 | ||
|
|
4acd345c6a | ||
|
|
d9ac0e7576 | ||
|
|
dcf0bc2cc9 | ||
|
|
cf4566b47b | ||
|
|
50e77536fe | ||
|
|
cd4e467751 | ||
|
|
9228fead48 | ||
|
|
38b8a198ba | ||
|
|
1eefbd28e8 | ||
|
|
1ee944a19d | ||
|
|
1b0512aa7e | ||
|
|
b5b5d35eee | ||
|
|
c5f660e33a | ||
|
|
e1e520d741 | ||
|
|
699d9d2fac | ||
|
|
c3c3927c2b | ||
|
|
00f19b7f91 | ||
|
|
42da951edf | ||
|
|
180bbab1fc | ||
|
|
69c59c52b6 | ||
|
|
19370631ea | ||
|
|
99c1853792 | ||
|
|
a131655235 | ||
|
|
677bb168a9 | ||
|
|
c91323e4d6 | ||
|
|
50d1d04913 | ||
|
|
67e2f5869a | ||
|
|
3a9c199ae7 | ||
|
|
bd6d0b3101 | ||
|
|
f1dd65cbdf | ||
|
|
c18d7c5fcb | ||
|
|
0d64531f66 | ||
|
|
f44dafd224 | ||
|
|
198b0a23a2 | ||
|
|
ad27b7decd | ||
|
|
fc00839adc | ||
|
|
aa13bd4016 | ||
|
|
d62fd78655 | ||
|
|
6dcca5fda4 | ||
|
|
c5f6ea5c0d | ||
|
|
004a9b52f0 | ||
|
|
e5f06d2cf6 | ||
|
|
cb10bfb8ef | ||
|
|
2e00d775e4 | ||
|
|
21d9750450 | ||
|
|
f431e20f3d | ||
|
|
3c68e51609 | ||
|
|
299b7289ea | ||
|
|
4bc45fc95a | ||
|
|
f9682d2e55 | ||
|
|
a384245c5a | ||
|
|
b24d7d9c95 | ||
|
|
453a62c672 | ||
|
|
89db309e10 | ||
|
|
d53d3bce59 | ||
|
|
3439c02e9d | ||
|
|
fcd0e3082b | ||
|
|
d9767b8112 | ||
|
|
85a9c2f52b | ||
|
|
69440d19b7 | ||
|
|
eac30a86d7 | ||
|
|
d4177e954c | ||
|
|
45ae9a8e35 | ||
|
|
9f75635596 | ||
|
|
4d505574dc | ||
|
|
e8e4f4ec3e | ||
|
|
4097257bef | ||
|
|
a14512e23e | ||
|
|
84e4652513 | ||
|
|
fc3d85e34b | ||
|
|
43656d4ea7 | ||
|
|
fff85d854e | ||
|
|
cf6075fb29 | ||
|
|
33298d6df6 | ||
|
|
4bb48998e0 | ||
|
|
5d9e591ae8 | ||
|
|
4d16df9312 | ||
|
|
18e554aa61 | ||
|
|
c176361788 | ||
|
|
dc7e53897a | ||
|
|
429c4bc51b | ||
|
|
1156d91cf8 | ||
|
|
4c5b0fbbcc | ||
|
|
5a288b1efe | ||
|
|
82c789ee58 | ||
|
|
7e0f9ab3eb | ||
|
|
87bd8965c6 | ||
|
|
2aa517c805 | ||
|
|
ec81bd2399 | ||
|
|
3ab229da70 | ||
|
|
2cecabd75e | ||
|
|
c4b0da5513 | ||
|
|
5489796737 | ||
|
|
85f09f9a4c | ||
|
|
293fd0d258 | ||
|
|
dfb7bb6830 | ||
|
|
f1e14f86c4 | ||
|
|
6644d209d2 | ||
|
|
7c4a2253e8 | ||
|
|
2d65bbd941 | ||
|
|
a609e6361a | ||
|
|
32a81e197b | ||
|
|
f2c0605d6d | ||
|
|
1677bb0dea | ||
|
|
dddc544b8f | ||
|
|
643eecde86 | ||
|
|
567d3e27ab | ||
|
|
a2e08b587a | ||
|
|
cb75ec25c8 | ||
|
|
7d06216289 | ||
|
|
4ab208ecc8 | ||
|
|
6aa0bedad2 | ||
|
|
c6e39976c6 | ||
|
|
c869366133 | ||
|
|
b9022e33ea | ||
|
|
772b3b7a06 | ||
|
|
b0d7623b7e | ||
|
|
4a96f599f6 | ||
|
|
564e44adc6 | ||
|
|
6752f41c2a | ||
|
|
51c09bf2b4 | ||
|
|
8d752f5aaa | ||
|
|
e7827f8bc2 | ||
|
|
f980e868dd | ||
|
|
3c1f0cfc34 | ||
|
|
5b9211d827 | ||
|
|
3f189945d8 | ||
|
|
f3ab05e7cd | ||
|
|
2219f7cc73 | ||
|
|
1fd3b9ec1c | ||
|
|
da31eddadc | ||
|
|
c660e46149 | ||
|
|
e3b1358bbc | ||
|
|
5943cd1907 | ||
|
|
78287e27c8 | ||
|
|
82bc2c87a9 | ||
|
|
e6ee3e9504 | ||
|
|
1c1ec84aa3 | ||
|
|
f3fcf977e4 | ||
|
|
4a3ac3bd26 | ||
|
|
3c5d3a3780 | ||
|
|
fe44f90e5b | ||
|
|
031e9bc854 | ||
|
|
0cbccc90ab | ||
|
|
71d90c11dd | ||
|
|
2546572e8e | ||
|
|
835ccbac46 | ||
|
|
b5b67c5386 | ||
|
|
fbe488e4de | ||
|
|
bb629f3be7 | ||
|
|
883a428e27 | ||
|
|
e44e2c48dd | ||
|
|
ece737274e | ||
|
|
5ece386cdf | ||
|
|
7653328ce7 | ||
|
|
fc111d2b12 | ||
|
|
04402db616 | ||
|
|
1b5a8a0f09 | ||
|
|
e33b623f21 | ||
|
|
5a97af7961 | ||
|
|
f4aefb738e | ||
|
|
cb039b986e | ||
|
|
f6c54f3f03 | ||
|
|
06d58b3b7b | ||
|
|
c9ef144dca | ||
|
|
09f71ed1b2 | ||
|
|
f0ddc301b7 | ||
|
|
bfc1f0ca62 | ||
|
|
7bcc0d16f2 | ||
|
|
f03776c262 | ||
|
|
ffa4d48967 | ||
|
|
79c3fd4f39 | ||
|
|
294accea1b | ||
|
|
792fcb1dbf | ||
|
|
da359269cb | ||
|
|
ecc5cea09b | ||
|
|
d68a17a1df | ||
|
|
52cb7a6382 | ||
|
|
405bb8435c | ||
|
|
c6c4960b35 | ||
|
|
2c4f2393ec | ||
|
|
08bc226527 | ||
|
|
6b38334b28 | ||
|
|
c1f0918f8a | ||
|
|
6861045d38 | ||
|
|
9f8d193b11 | ||
|
|
a13e57f701 | ||
|
|
e722ba38e3 | ||
|
|
b1dc2b5353 | ||
|
|
0a913b09cf |
71
.github/CONTRIBUTING.md
vendored
Normal file
71
.github/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
## What should I do before opening an issue?
|
||||
|
||||
Before opening an issue, please ensure that:
|
||||
|
||||
- `$TERM` inside tmux is screen, screen-256color, tmux or tmux-256color. Check
|
||||
by running `echo $TERM` inside tmux.
|
||||
|
||||
- You can reproduce the problem with the latest tmux release, or a build from
|
||||
Git master.
|
||||
|
||||
- Your question or issue is not covered in the manual (run man tmux).
|
||||
|
||||
- Nobody else has opened the same issue recently.
|
||||
|
||||
## What should I include in an issue?
|
||||
|
||||
Please include the output of:
|
||||
|
||||
~~~bash
|
||||
uname -sp && tmux -V && echo $TERM
|
||||
~~~
|
||||
|
||||
Also include:
|
||||
|
||||
- Your platform (Linux, OS X, or whatever).
|
||||
|
||||
- A brief description of the problem with steps to reproduce.
|
||||
|
||||
- A minimal tmux config, if you can't reproduce without a config.
|
||||
|
||||
- Your terminal, and `$TERM` inside and outside of tmux.
|
||||
|
||||
- Logs from tmux (see below).
|
||||
|
||||
- At most one or two screenshots, if helpful.
|
||||
|
||||
## How do I test without a .tmux.conf?
|
||||
|
||||
Run a separate tmux server with `-f/dev/null` to skip loading `.tmux.conf`:
|
||||
|
||||
~~~bash
|
||||
tmux -Ltest kill-server
|
||||
tmux -Ltest -f/dev/null new
|
||||
~~~
|
||||
|
||||
## How do I get logs from tmux?
|
||||
|
||||
Add `-vv` to tmux to create three log files in the current directory. If you can
|
||||
reproduce without a configuration file:
|
||||
|
||||
~~~bash
|
||||
tmux -Ltest kill-server
|
||||
tmux -vv -Ltest -f/dev/null new
|
||||
~~~
|
||||
|
||||
Or if you need your configuration:
|
||||
|
||||
~~~base
|
||||
tmux kill-server
|
||||
tmux -vv new
|
||||
~~~
|
||||
|
||||
The log files are:
|
||||
|
||||
- `tmux-server*.log`: server log file.
|
||||
|
||||
- `tmux-client*.log`: client log file.
|
||||
|
||||
- `tmux-out*.log`: output log file.
|
||||
|
||||
Please attach the log files to your issue.
|
||||
19
.github/ISSUE_TEMPLATE.md
vendored
Normal file
19
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
### Issue description
|
||||
|
||||
Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md
|
||||
before opening an issue.
|
||||
|
||||
Describe the problem and the steps to reproduce. Add a minimal tmux config if
|
||||
necessary. Screenshots can be helpful, but no more than one or two.
|
||||
|
||||
Do not report bugs (crashes, incorrect behaviour) without reproducing on a tmux
|
||||
built from the latest code in Git.
|
||||
|
||||
### Required information
|
||||
|
||||
Please provide the following information:
|
||||
|
||||
* tmux version (`tmux -V`).
|
||||
* Platform (`uname -sp`).
|
||||
* $TERM inside and outside of tmux (`echo $TERM`).
|
||||
* Logs from tmux (`tmux kill-server; tmux -vv new`).
|
||||
88
.github/README.md
vendored
Normal file
88
.github/README.md
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
# Welcome to tmux!
|
||||
|
||||
tmux is a terminal multiplexer: it enables a number of terminals to be created,
|
||||
accessed, and controlled from a single screen. tmux may be detached from a
|
||||
screen and continue running in the background, then later reattached.
|
||||
|
||||
This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.
|
||||
|
||||
## Dependencies
|
||||
|
||||
tmux depends on [libevent](https://libevent.org) 2.x, available from [this
|
||||
page](https://github.com/libevent/libevent/releases/latest).
|
||||
|
||||
It also depends on [ncurses](https://www.gnu.org/software/ncurses/), available
|
||||
from [this page](https://invisible-mirror.net/archives/ncurses/).
|
||||
|
||||
## Installation
|
||||
|
||||
### From release tarball
|
||||
|
||||
To build and install tmux from a release tarball, use:
|
||||
|
||||
~~~bash
|
||||
./configure && make
|
||||
sudo make install
|
||||
~~~
|
||||
|
||||
tmux can use the utempter library to update utmp(5), if it is installed - run
|
||||
configure with `--enable-utempter` to enable this.
|
||||
|
||||
### From version control
|
||||
|
||||
To get and build the latest from version control:
|
||||
|
||||
~~~bash
|
||||
git clone https://github.com/tmux/tmux.git
|
||||
cd tmux
|
||||
sh autogen.sh
|
||||
./configure && make
|
||||
~~~
|
||||
|
||||
(Note that this requires at least a working C compiler, `make`, `autoconf`,
|
||||
`automake`, `pkg-config` as well as `libevent` and `ncurses` libraries and
|
||||
headers.)
|
||||
|
||||
## Contributing
|
||||
|
||||
Bug reports, feature suggestions and especially code contributions are most
|
||||
welcome. Please send by email to:
|
||||
|
||||
tmux-users@googlegroups.com
|
||||
|
||||
Or open a GitHub issue or pull request.
|
||||
|
||||
There is [a TODO list](https://github.com/tmux/tmux/wiki/Contributing) which
|
||||
explains some ideas for tmux not yet developed. Please feel free to ask for
|
||||
clarifications on the mailing list if you're thinking of working on these or
|
||||
need further information.
|
||||
|
||||
Please read the CONTRIBUTING file before opening an issue.
|
||||
|
||||
## Documentation
|
||||
|
||||
For documentation on using tmux, see the tmux.1 manpage. View it from the
|
||||
source tree with:
|
||||
|
||||
~~~bash
|
||||
nroff -mdoc tmux.1|less
|
||||
~~~
|
||||
|
||||
A small example configuration is in `example_tmux.conf`.
|
||||
|
||||
And a bash(1) completion file at:
|
||||
|
||||
https://github.com/imomaliev/tmux-bash-completion
|
||||
|
||||
For debugging, run tmux with `-v` or `-vv` to generate server and client log
|
||||
files in the current directory.
|
||||
|
||||
## Support
|
||||
|
||||
The tmux mailing list for general discussion and bug reports is:
|
||||
|
||||
https://groups.google.com/forum/#!forum/tmux-users
|
||||
|
||||
Subscribe by sending an email to:
|
||||
|
||||
tmux-users+subscribe@googlegroups.com
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -18,3 +18,4 @@ Makefile.in
|
||||
configure
|
||||
tmux.1.*
|
||||
*.dSYM
|
||||
cmd-parse.c
|
||||
|
||||
22
.travis.yml
22
.travis.yml
@@ -1,10 +1,16 @@
|
||||
language: c
|
||||
matrix:
|
||||
include:
|
||||
- compiler: gcc
|
||||
- compiler: clang
|
||||
env: CFLAGS="-g -O2"
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get -y install debhelper autotools-dev dh-autoreconf file libncurses5-dev libevent-dev pkg-config libutempter-dev build-essential
|
||||
script: (CFLAGS= ./autogen.sh) && ./configure --enable-debug && make
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -y install bison autotools-dev libncurses5-dev libevent-dev pkg-config libutempter-dev build-essential; fi
|
||||
|
||||
script:
|
||||
- ./autogen.sh && ./configure && make
|
||||
|
||||
66
CHANGES
66
CHANGES
@@ -1,3 +1,69 @@
|
||||
CHANGES FROM 2.9 to 3.0
|
||||
|
||||
* INCOMPATIBLE: Add a new {} syntax to the configuration file. This is a string
|
||||
similar to single quotes but also includes newlines and allows commands that
|
||||
take other commands as string arguments to be expressed more clearly and
|
||||
without additional escaping.
|
||||
|
||||
A literal { and } or a string containing { or } must now be escaped or
|
||||
quoted, for example '{' and '}' instead of { or }, or 'X#{foo}' instead of
|
||||
X#{foo}.
|
||||
|
||||
* New <, >, <= and >= comparison operators for formats.
|
||||
|
||||
* Improve escaping of special characters in list-keys output.
|
||||
|
||||
* INCOMPATIBLE: tmux's configuration parsing has changed to use yacc(1). There
|
||||
is one incompatible change: a \ on its own must be escaped or quoted as
|
||||
either \\ or '\' (the latter works on older tmux versions).
|
||||
|
||||
Entirely the same parser is now used for parsing the configuration file
|
||||
and for string commands. This means that constructs previously only
|
||||
available in .tmux.conf, such as %if, can now be used in string commands
|
||||
(for example, those given to if-shell - not commands invoked from the
|
||||
shell, they are still parsed by the shell itself).
|
||||
|
||||
* Add support for the overline attribute (SGR 53). The Smol capability is
|
||||
needed in terminal-overrides.
|
||||
|
||||
* Add the ability to create simple menus. Introduces new command
|
||||
display-menu. Default menus are bound to MouseDown3 on the status line;
|
||||
MouseDown3 or M-MouseDown3 on panes; MouseDown3 in tree, client and
|
||||
buffer modes; and C-b C-m and C-b M-m.
|
||||
|
||||
* Allow panes to be empty (no command). They can be created either by piping to
|
||||
split-window -I, or by passing an empty command ('') to split-window. Output
|
||||
can be sent to an existing empty window with display-message -I.
|
||||
|
||||
* Add keys to jump between matching brackets (emacs C-M-f and C-M-b, vi %).
|
||||
|
||||
* Add a -e flag to new-window, split-window, respawn-window, respawn-pane to
|
||||
pass environment variables into the newly created process.
|
||||
|
||||
* Hooks are now stored in the options tree as array options, allowing them to
|
||||
have multiple separate commands. set-hook and show-hooks remain but
|
||||
set-option and show-options can now also be used (show-options will only show
|
||||
hooks if given the -H flag). Hooks with multiple commands are run in index
|
||||
order.
|
||||
|
||||
* Automatically scroll if dragging to create a selection with the mouse and the
|
||||
cursor reaches the top or bottom line.
|
||||
|
||||
* Add -no-clear variants of copy-selection and copy-pipe which do not clear the
|
||||
selection after copying. Make copy-pipe clear the selection by default to be
|
||||
consistent with copy-selection.
|
||||
|
||||
* Add an argument to copy commands to set the prefix for the buffer name, this
|
||||
(for example) allows buffers for different sessions to be named separately.
|
||||
|
||||
* Update session activity on focus event.
|
||||
|
||||
* Pass target from source-file into the config file parser so formats in %if
|
||||
and %endif have access to more useful variables.
|
||||
|
||||
* Add the ability to infer an option type (server, session, window) from its
|
||||
name to show-options (it was already present in set-option).
|
||||
|
||||
CHANGES FROM 2.9 to 2.9a
|
||||
|
||||
* Fix bugs in select-pane and the main-horizontal and main-vertical layouts.
|
||||
|
||||
33
CONTRIBUTING
33
CONTRIBUTING
@@ -1,33 +0,0 @@
|
||||
When reporting issues:
|
||||
|
||||
YOU MUST INCLUDE THE TMUX VERSION
|
||||
|
||||
DO NOT OPEN AN ISSUE THAT DOES NOT MENTION THE TMUX VERSION
|
||||
|
||||
Please also include:
|
||||
|
||||
- your platform (Linux, OS X, or whatever);
|
||||
- a brief description of the problem with steps to reproduce;
|
||||
- a minimal tmux config, if you can't reproduce without a config;
|
||||
- your terminal, and $TERM inside and outside of tmux;
|
||||
- logs from tmux (see below);
|
||||
- at most one or two screenshots, if helpful.
|
||||
|
||||
This should include at least the output of:
|
||||
|
||||
$ uname -sp && tmux -V && echo $TERM
|
||||
|
||||
Please do not report bugs (crashes, incorrect behaviour) without reproducing on
|
||||
a tmux built from the latest code in Git.
|
||||
|
||||
Note that TERM inside tmux must be a variant of screen or tmux (for example:
|
||||
screen or screen-256color, tmux or tmux-256color). Please ensure this is the
|
||||
case before opening an issue.
|
||||
|
||||
To run tmux without a config and get logs, run:
|
||||
|
||||
tmux -Ltest kill-server
|
||||
tmux -vv -Ltest -f/dev/null new
|
||||
|
||||
Then reproduce the problem, exit tmux, and attach the tmux-server-*.log file
|
||||
from the current directory to the issue.
|
||||
7
COPYING
7
COPYING
@@ -1,10 +1,7 @@
|
||||
THIS IS FOR INFORMATION ONLY, CODE IS UNDER THE LICENCE AT THE TOP OF ITS FILE.
|
||||
|
||||
The README, CHANGES, FAQ and TODO files are licensed under the ISC
|
||||
license. Files under examples/ remain copyright their authors unless otherwise
|
||||
stated in the file but permission has been received to distribute them with
|
||||
tmux. All other files have a license and copyright notice at their start,
|
||||
typically:
|
||||
The README, CHANGES, FAQ and TODO files are licensed under the ISC license. All
|
||||
other files have a license and copyright notice at their start, typically:
|
||||
|
||||
Copyright (c) <author>
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Please read https://raw.githubusercontent.com/tmux/tmux/master/CONTRIBUTING
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Obvious program stuff.
|
||||
bin_PROGRAMS = tmux
|
||||
CLEANFILES = tmux.1.mdoc tmux.1.man
|
||||
CLEANFILES = tmux.1.mdoc tmux.1.man cmd-parse.c
|
||||
|
||||
# Distribution tarball options.
|
||||
EXTRA_DIST = \
|
||||
@@ -71,6 +71,7 @@ dist_tmux_SOURCES = \
|
||||
cmd-confirm-before.c \
|
||||
cmd-copy-mode.c \
|
||||
cmd-detach-client.c \
|
||||
cmd-display-menu.c \
|
||||
cmd-display-message.c \
|
||||
cmd-display-panes.c \
|
||||
cmd-find-window.c \
|
||||
@@ -93,6 +94,7 @@ dist_tmux_SOURCES = \
|
||||
cmd-move-window.c \
|
||||
cmd-new-session.c \
|
||||
cmd-new-window.c \
|
||||
cmd-parse.y \
|
||||
cmd-paste-buffer.c \
|
||||
cmd-pipe-pane.c \
|
||||
cmd-queue.c \
|
||||
@@ -112,14 +114,12 @@ dist_tmux_SOURCES = \
|
||||
cmd-send-keys.c \
|
||||
cmd-set-buffer.c \
|
||||
cmd-set-environment.c \
|
||||
cmd-set-hook.c \
|
||||
cmd-set-option.c \
|
||||
cmd-show-environment.c \
|
||||
cmd-show-messages.c \
|
||||
cmd-show-options.c \
|
||||
cmd-source-file.c \
|
||||
cmd-split-window.c \
|
||||
cmd-string.c \
|
||||
cmd-swap-pane.c \
|
||||
cmd-swap-window.c \
|
||||
cmd-switch-client.c \
|
||||
@@ -135,7 +135,6 @@ dist_tmux_SOURCES = \
|
||||
format-draw.c \
|
||||
grid-view.c \
|
||||
grid.c \
|
||||
hooks.c \
|
||||
input-keys.c \
|
||||
input.c \
|
||||
job.c \
|
||||
@@ -145,6 +144,7 @@ dist_tmux_SOURCES = \
|
||||
layout-set.c \
|
||||
layout.c \
|
||||
log.c \
|
||||
menu.c \
|
||||
mode-tree.c \
|
||||
names.c \
|
||||
notify.c \
|
||||
@@ -160,6 +160,7 @@ dist_tmux_SOURCES = \
|
||||
server-fn.c \
|
||||
server.c \
|
||||
session.c \
|
||||
spawn.c \
|
||||
status.c \
|
||||
style.c \
|
||||
tmux.c \
|
||||
|
||||
72
README
72
README
@@ -6,13 +6,17 @@ screen and continue running in the background, then later reattached.
|
||||
|
||||
This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.
|
||||
|
||||
tmux depends on libevent 2.x. Download it from:
|
||||
* Dependencies
|
||||
|
||||
http://libevent.org
|
||||
tmux depends on libevent 2.x, available from:
|
||||
|
||||
https://github.com/libevent/libevent/releases/latest
|
||||
|
||||
It also depends on ncurses, available from:
|
||||
|
||||
http://invisible-island.net/ncurses/
|
||||
https://invisible-mirror.net/archives/ncurses/
|
||||
|
||||
* Installation
|
||||
|
||||
To build and install tmux from a release tarball, use:
|
||||
|
||||
@@ -32,40 +36,42 @@ To get and build the latest from version control:
|
||||
(Note that this requires at least a working C compiler, make, autoconf,
|
||||
automake, pkg-config as well as libevent and ncurses libraries and headers.)
|
||||
|
||||
For more information see http://git-scm.com. Patches should be sent by email to
|
||||
the mailing list at tmux-users@googlegroups.com or submitted through GitHub at
|
||||
https://github.com/tmux/tmux/issues.
|
||||
|
||||
For documentation on using tmux, see the tmux.1 manpage. It can be viewed from
|
||||
the source tree with:
|
||||
|
||||
$ nroff -mdoc tmux.1|less
|
||||
|
||||
A small example configuration in example_tmux.conf.
|
||||
|
||||
And a bash(1) completion file at:
|
||||
|
||||
https://github.com/imomaliev/tmux-bash-completion
|
||||
|
||||
For debugging, running tmux with -v or -vv will generate server and client log
|
||||
files in the current directory.
|
||||
|
||||
tmux mailing lists are available. For general discussion and bug reports:
|
||||
|
||||
https://groups.google.com/forum/#!forum/tmux-users
|
||||
|
||||
And for Git commit emails:
|
||||
|
||||
https://groups.google.com/forum/#!forum/tmux-git
|
||||
|
||||
Subscribe by sending an email to <tmux-users+subscribe@googlegroups.com>.
|
||||
* Contributing
|
||||
|
||||
Bug reports, feature suggestions and especially code contributions are most
|
||||
welcome. Please send by email to:
|
||||
|
||||
tmux-users@googlegroups.com
|
||||
|
||||
This file and the CHANGES, FAQ, SYNCING and TODO files are licensed under the
|
||||
ISC license. All other files have a license and copyright notice at their start.
|
||||
Or open a GitHub issue or pull request.
|
||||
|
||||
-- Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
* Documentation
|
||||
|
||||
For documentation on using tmux, see the tmux.1 manpage. View it from the
|
||||
source tree with:
|
||||
|
||||
$ nroff -mdoc tmux.1|less
|
||||
|
||||
A small example configuration is in example_tmux.conf.
|
||||
|
||||
A bash(1) completion file is at:
|
||||
|
||||
https://github.com/imomaliev/tmux-bash-completion
|
||||
|
||||
For debugging, run tmux with -v and -vv to generate server and client log files
|
||||
in the current directory.
|
||||
|
||||
* Support
|
||||
|
||||
The tmux mailing list for general discussion and bug reports is:
|
||||
|
||||
https://groups.google.com/forum/#!forum/tmux-users
|
||||
|
||||
Subscribe by sending an email to:
|
||||
|
||||
tmux-users+subscribe@googlegroups.com
|
||||
|
||||
* License
|
||||
|
||||
This file and the CHANGES files are licensed under the ISC license. All other
|
||||
files have a license and copyright notice at their start.
|
||||
|
||||
161
TODO
161
TODO
@@ -1,161 +0,0 @@
|
||||
- command bits and pieces:
|
||||
* allow multiple targets: fnmatch for -t/-c, for example detach all
|
||||
clients with -t*
|
||||
* ' and " should be parsed the same (eg "\e" vs '\e') in config
|
||||
and command prompt
|
||||
* last-pane across sessions
|
||||
* resize-pane -p to match split-window -p
|
||||
* flag to wait-for to have a timeout and/or to stop waiting when the
|
||||
client gets a signal
|
||||
|
||||
- make command sequences more usable
|
||||
* don't require space after ;
|
||||
* options for error handling: && and ||?
|
||||
|
||||
- options bits and pieces:
|
||||
* way to set socket path from config file
|
||||
|
||||
- format improvements:
|
||||
* some way to pad # stuff with spaces
|
||||
* formats to show if a window is linked into multiple sessions, into
|
||||
multiple attached sessions, and is the active window in multiple
|
||||
attached sessions?
|
||||
* comparison operators like < and > (for #{version}?)
|
||||
|
||||
- improve monitor-*:
|
||||
* straighten out rules for multiple clients
|
||||
* think about what happens across sessions
|
||||
* monitor changes within a region
|
||||
* perhaps monitor /all/ panes in the window not just one
|
||||
|
||||
- improve mouse support:
|
||||
* bind commands to mouse in different areas?
|
||||
* commands executed when clicking on a pattern (URL)
|
||||
|
||||
- warts on current naming:
|
||||
* display-time but message-fg/bg/attr
|
||||
* list-* vs show-*
|
||||
|
||||
- copy/paste improvements:
|
||||
* paste w/o trailing whitespace
|
||||
* command to toggle selection not to move it in copy-mode
|
||||
* regex searching
|
||||
* searching in copy mode should unwrap lines, so if you search for "foobar"
|
||||
then it should be found even if it is now "foo\nbar" (if the WRAP flag
|
||||
is set on the line)
|
||||
* capture-pane option to preserve spaces but not join lines
|
||||
* improve word and line selection in copy mode (for example when
|
||||
dragging it should select by word. compare how xterm works. GitHub
|
||||
issue 682)
|
||||
* key to search for word under cursor (GitHub issue 1240)
|
||||
* when entering copy mode, should copy grid so that input does not
|
||||
need to be suspended
|
||||
* allow the prefix for automatic buffers to be specified as part of the
|
||||
key binding to allow session buffers or similar (GitHub issue 1501)
|
||||
* copy-pipe should be synchronous (GitHub issue 1517)
|
||||
|
||||
- layout stuff
|
||||
* way to tag a layout as a number/name
|
||||
* maybe keep last layout + size around and if size reverts just put it
|
||||
back
|
||||
* revamp layouts: they are too complicated, should be more closely
|
||||
integrated, should support hints, layout sets should just be a
|
||||
special case of custom layouts, and we should support panes that are
|
||||
not attached to a cell at all. this could be the time to introduce
|
||||
panelink to replace layout_cell
|
||||
* way to set hints/limits about pane size for resizing
|
||||
* a mode where one application can cross two panes (ie x|y, width =
|
||||
COLUMNS/2 but height = ROWS * 2)
|
||||
* separate active panes for different clients
|
||||
* way to choose where the freed space goes when a pane is killed:
|
||||
option to kill-pane? GitHub issue 918
|
||||
|
||||
- code cleanup
|
||||
* instead of separate window and session options, just one master
|
||||
options list with each option having a type (window or session), then
|
||||
options on window, on session, and global. for window options we look
|
||||
window->session->global, and for session we look session->global.
|
||||
problem: what about windows in multiple sessions? there are contexts
|
||||
where we do not know which session, or where multiple choices makes
|
||||
no sense... could at least have one global list for all types of
|
||||
global options and keep separate window,session lists
|
||||
* the way pane, window, session destroy is handled is too complicated
|
||||
and the distinction between session.c, window.c and server-fn.c
|
||||
functions is not clear. could we just have kill_pane(),
|
||||
kill_window(), unlink_window(), kill_session() that fix up all data
|
||||
structures (flagging sessions as dead) and return a value to say
|
||||
whether clients need to be checked for dead sessions? sort of like
|
||||
session_detach now but more so. or some other scheme to make it
|
||||
simpler and clearer? also would be nice to remove/rename server-fn.c
|
||||
* more readable way to work out the various things commands need to
|
||||
know about the client, notably:
|
||||
- is this the config file? (cmdq->c == NULL)
|
||||
- is this a command client? (cmdq->c != NULL &&
|
||||
cmdq->c->session == NULL)
|
||||
- is this a control client?
|
||||
- can i do stdin or stdout to this client?
|
||||
or even guarantee that cmdq->c != NULL and provide a better way to
|
||||
tell when in the config file - then we use cmdq->c if we need a
|
||||
client w/o a session else cmd_current_client
|
||||
|
||||
- miscellaneous
|
||||
* link panes into multiple windows
|
||||
* live update: server started with -U connects to server, requests
|
||||
sessions and windows, receives file descriptors
|
||||
* there are inconsistencies in what we get from old shell and what
|
||||
comes from config for new sessions and windows. likewise, panes and
|
||||
jobs and run-shell and lock command all start with slightly different
|
||||
environments
|
||||
* multiline status line? separate command prompt and status line?
|
||||
* automatic pane logging
|
||||
* marks in history, automatically add (move?) one when pane is changed
|
||||
* this doesn't work, need pane reference count probably:
|
||||
bind -n DoubleClick3Status confirm-before -p "kill-window #I? (y/n)" kill-window
|
||||
* marker lines in history (GitHub issue 1042)
|
||||
* tree mode stuff: make command prompt (:) common code so all modes get it,
|
||||
predefined filters, tag-all key, ...
|
||||
* drag panes and windows around to move/swap them in choose mode
|
||||
* flag to specify environment to new-window, split-window,
|
||||
new-session (issue 1498)
|
||||
* multiple column panes (issue 1503)
|
||||
* support for ZERO WIDTH JOINER U+200D
|
||||
* individual pane synchronize-panes (with pane options?); issue 1638
|
||||
|
||||
- hooks
|
||||
* more hooks for various things
|
||||
* finish after hooks for special commands. these do not have a hook at
|
||||
the moment:
|
||||
attach-session detach-client kill-server respawn-window
|
||||
swap-window break-pane find-window kill-session rotate-window
|
||||
switch-client choose-tree if-shell kill-window run-shell
|
||||
wait-for command-prompt join-pane move-window source-file
|
||||
confirm-before kill-pane respawn-pane swap-pane
|
||||
at the moment AFTERHOOK uses current only if target is not valid,
|
||||
but target is ALWAYS valid - it should use current if no -t flag?
|
||||
then select-* could use AFTERHOOK
|
||||
* multiple hooks with the same name?
|
||||
* finish hooks for notifys
|
||||
* for session_closed, if no sessions at all, perhaps fake up a
|
||||
temporary one
|
||||
|
||||
- pan
|
||||
* tty_window_offset should try to keep as much off active pane
|
||||
visible as possible
|
||||
* rather than centering cursor it might be better if only
|
||||
moved offset when it gets close to an edge?
|
||||
|
||||
----
|
||||
|
||||
TODO soonish maybe:
|
||||
|
||||
- Store hooks as options, issue 1619.
|
||||
- Support buffer prefixes, issue 1501.
|
||||
- copy-pipe should be synchronous, issue 1517.
|
||||
- -E flag to pass environment to new-*, issue 1498.
|
||||
- Copy mode searching is slow when there is a big history, issue 1545.
|
||||
- Grid "block" stuff, issue 1269. Can be used potentially for compression of
|
||||
history (bit silly really though), reflow performance (can reflow blocks on
|
||||
demand). It would possibly be good if history-limit could be global and
|
||||
collected LRU.
|
||||
- Command aliases should be able to override builtin commands in order to add
|
||||
default flags (some mechanism needed to avoid recursion). GitHub issue 1630.
|
||||
176
arguments.c
176
arguments.c
@@ -28,9 +28,15 @@
|
||||
* Manipulate command arguments.
|
||||
*/
|
||||
|
||||
struct args_value {
|
||||
char *value;
|
||||
TAILQ_ENTRY(args_value) entry;
|
||||
};
|
||||
TAILQ_HEAD(args_values, args_value);
|
||||
|
||||
struct args_entry {
|
||||
u_char flag;
|
||||
char *value;
|
||||
struct args_values values;
|
||||
RB_ENTRY(args_entry) entry;
|
||||
};
|
||||
|
||||
@@ -92,12 +98,18 @@ args_free(struct args *args)
|
||||
{
|
||||
struct args_entry *entry;
|
||||
struct args_entry *entry1;
|
||||
struct args_value *value;
|
||||
struct args_value *value1;
|
||||
|
||||
cmd_free_argv(args->argc, args->argv);
|
||||
|
||||
RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
|
||||
RB_REMOVE(args_tree, &args->tree, entry);
|
||||
free(entry->value);
|
||||
TAILQ_FOREACH_SAFE(value, &entry->values, entry, value1) {
|
||||
TAILQ_REMOVE(&entry->values, value, entry);
|
||||
free(value->value);
|
||||
free(value);
|
||||
}
|
||||
free(entry);
|
||||
}
|
||||
|
||||
@@ -123,22 +135,53 @@ args_print_add(char **buf, size_t *len, const char *fmt, ...)
|
||||
free(s);
|
||||
}
|
||||
|
||||
/* Add value to string. */
|
||||
static void
|
||||
args_print_add_value(char **buf, size_t *len, struct args_entry *entry,
|
||||
struct args_value *value)
|
||||
{
|
||||
char *escaped;
|
||||
|
||||
if (**buf != '\0')
|
||||
args_print_add(buf, len, " -%c ", entry->flag);
|
||||
else
|
||||
args_print_add(buf, len, "-%c ", entry->flag);
|
||||
|
||||
escaped = args_escape(value->value);
|
||||
args_print_add(buf, len, "%s", escaped);
|
||||
free(escaped);
|
||||
}
|
||||
|
||||
/* Add argument to string. */
|
||||
static void
|
||||
args_print_add_argument(char **buf, size_t *len, const char *argument)
|
||||
{
|
||||
char *escaped;
|
||||
|
||||
if (**buf != '\0')
|
||||
args_print_add(buf, len, " ");
|
||||
|
||||
escaped = args_escape(argument);
|
||||
args_print_add(buf, len, "%s", escaped);
|
||||
free(escaped);
|
||||
}
|
||||
|
||||
/* Print a set of arguments. */
|
||||
char *
|
||||
args_print(struct args *args)
|
||||
{
|
||||
size_t len;
|
||||
char *buf, *escaped;
|
||||
int i, flags;
|
||||
char *buf;
|
||||
int i;
|
||||
struct args_entry *entry;
|
||||
static const char quoted[] = " #\"';$";
|
||||
struct args_value *value;
|
||||
|
||||
len = 1;
|
||||
buf = xcalloc(1, len);
|
||||
|
||||
/* Process the flags first. */
|
||||
RB_FOREACH(entry, args_tree, &args->tree) {
|
||||
if (entry->value != NULL)
|
||||
if (!TAILQ_EMPTY(&entry->values))
|
||||
continue;
|
||||
|
||||
if (*buf == '\0')
|
||||
@@ -148,44 +191,52 @@ args_print(struct args *args)
|
||||
|
||||
/* Then the flags with arguments. */
|
||||
RB_FOREACH(entry, args_tree, &args->tree) {
|
||||
if (entry->value == NULL)
|
||||
continue;
|
||||
|
||||
if (*buf != '\0')
|
||||
args_print_add(&buf, &len, " -%c ", entry->flag);
|
||||
else
|
||||
args_print_add(&buf, &len, "-%c ", entry->flag);
|
||||
|
||||
flags = VIS_OCTAL|VIS_TAB|VIS_NL;
|
||||
if (entry->value[strcspn(entry->value, quoted)] != '\0')
|
||||
flags |= VIS_DQ;
|
||||
utf8_stravis(&escaped, entry->value, flags);
|
||||
if (flags & VIS_DQ)
|
||||
args_print_add(&buf, &len, "\"%s\"", escaped);
|
||||
else
|
||||
args_print_add(&buf, &len, "%s", escaped);
|
||||
free(escaped);
|
||||
TAILQ_FOREACH(value, &entry->values, entry)
|
||||
args_print_add_value(&buf, &len, entry, value);
|
||||
}
|
||||
|
||||
/* And finally the argument vector. */
|
||||
for (i = 0; i < args->argc; i++) {
|
||||
if (*buf != '\0')
|
||||
args_print_add(&buf, &len, " ");
|
||||
|
||||
flags = VIS_OCTAL|VIS_TAB|VIS_NL;
|
||||
if (args->argv[i][strcspn(args->argv[i], quoted)] != '\0')
|
||||
flags |= VIS_DQ;
|
||||
utf8_stravis(&escaped, args->argv[i], flags);
|
||||
if (flags & VIS_DQ)
|
||||
args_print_add(&buf, &len, "\"%s\"", escaped);
|
||||
else
|
||||
args_print_add(&buf, &len, "%s", escaped);
|
||||
free(escaped);
|
||||
}
|
||||
for (i = 0; i < args->argc; i++)
|
||||
args_print_add_argument(&buf, &len, args->argv[i]);
|
||||
|
||||
return (buf);
|
||||
}
|
||||
|
||||
/* Escape an argument. */
|
||||
char *
|
||||
args_escape(const char *s)
|
||||
{
|
||||
static const char quoted[] = " #\"';${}";
|
||||
char *escaped, *result;
|
||||
int flags;
|
||||
|
||||
if (*s == '\0')
|
||||
return (xstrdup(s));
|
||||
if ((strchr(quoted, s[0]) != NULL || s[0] == '~') && s[1] == '\0') {
|
||||
xasprintf(&escaped, "\\%c", s[0]);
|
||||
return (escaped);
|
||||
}
|
||||
|
||||
flags = VIS_OCTAL|VIS_TAB|VIS_NL;
|
||||
if (s[strcspn(s, quoted)] != '\0')
|
||||
flags |= VIS_DQ;
|
||||
utf8_stravis(&escaped, s, flags);
|
||||
|
||||
if (flags & VIS_DQ) {
|
||||
if (*escaped == '~')
|
||||
xasprintf(&result, "\"\\%s\"", escaped);
|
||||
else
|
||||
xasprintf(&result, "\"%s\"", escaped);
|
||||
} else {
|
||||
if (*escaped == '~')
|
||||
xasprintf(&result, "\\%s", escaped);
|
||||
else
|
||||
result = xstrdup(escaped);
|
||||
}
|
||||
free(escaped);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Return if an argument is present. */
|
||||
int
|
||||
args_has(struct args *args, u_char ch)
|
||||
@@ -195,22 +246,24 @@ args_has(struct args *args, u_char ch)
|
||||
|
||||
/* Set argument value in the arguments tree. */
|
||||
void
|
||||
args_set(struct args *args, u_char ch, const char *value)
|
||||
args_set(struct args *args, u_char ch, const char *s)
|
||||
{
|
||||
struct args_entry *entry;
|
||||
struct args_value *value;
|
||||
|
||||
/* Replace existing argument. */
|
||||
if ((entry = args_find(args, ch)) != NULL) {
|
||||
free(entry->value);
|
||||
entry->value = NULL;
|
||||
} else {
|
||||
entry = args_find(args, ch);
|
||||
if (entry == NULL) {
|
||||
entry = xcalloc(1, sizeof *entry);
|
||||
entry->flag = ch;
|
||||
TAILQ_INIT(&entry->values);
|
||||
RB_INSERT(args_tree, &args->tree, entry);
|
||||
}
|
||||
|
||||
if (value != NULL)
|
||||
entry->value = xstrdup(value);
|
||||
if (s != NULL) {
|
||||
value = xcalloc(1, sizeof *value);
|
||||
value->value = xstrdup(s);
|
||||
TAILQ_INSERT_TAIL(&entry->values, value, entry);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get argument value. Will be NULL if it isn't present. */
|
||||
@@ -221,7 +274,34 @@ args_get(struct args *args, u_char ch)
|
||||
|
||||
if ((entry = args_find(args, ch)) == NULL)
|
||||
return (NULL);
|
||||
return (entry->value);
|
||||
return (TAILQ_LAST(&entry->values, args_values)->value);
|
||||
}
|
||||
|
||||
/* Get first value in argument. */
|
||||
const char *
|
||||
args_first_value(struct args *args, u_char ch, struct args_value **value)
|
||||
{
|
||||
struct args_entry *entry;
|
||||
|
||||
if ((entry = args_find(args, ch)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
*value = TAILQ_FIRST(&entry->values);
|
||||
if (*value == NULL)
|
||||
return (NULL);
|
||||
return ((*value)->value);
|
||||
}
|
||||
|
||||
/* Get next value in argument. */
|
||||
const char *
|
||||
args_next_value(struct args_value **value)
|
||||
{
|
||||
if (*value == NULL)
|
||||
return (NULL);
|
||||
*value = TAILQ_NEXT(*value, entry);
|
||||
if (*value == NULL)
|
||||
return (NULL);
|
||||
return ((*value)->value);
|
||||
}
|
||||
|
||||
/* Convert an argument value to a number. */
|
||||
@@ -232,13 +312,15 @@ args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
|
||||
const char *errstr;
|
||||
long long ll;
|
||||
struct args_entry *entry;
|
||||
struct args_value *value;
|
||||
|
||||
if ((entry = args_find(args, ch)) == NULL) {
|
||||
*cause = xstrdup("missing");
|
||||
return (0);
|
||||
}
|
||||
value = TAILQ_LAST(&entry->values, args_values);
|
||||
|
||||
ll = strtonum(entry->value, minval, maxval, &errstr);
|
||||
ll = strtonum(value->value, minval, maxval, &errstr);
|
||||
if (errstr != NULL) {
|
||||
*cause = xstrdup(errstr);
|
||||
return (0);
|
||||
|
||||
@@ -31,7 +31,7 @@ attributes_tostring(int attr)
|
||||
if (attr == 0)
|
||||
return ("none");
|
||||
|
||||
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
(attr & GRID_ATTR_BRIGHT) ? "bright," : "",
|
||||
(attr & GRID_ATTR_DIM) ? "dim," : "",
|
||||
(attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "",
|
||||
@@ -43,7 +43,8 @@ attributes_tostring(int attr)
|
||||
(attr & GRID_ATTR_UNDERSCORE_2) ? "double-underscore," : "",
|
||||
(attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "",
|
||||
(attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-underscore," : "",
|
||||
(attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : "");
|
||||
(attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : "",
|
||||
(attr & GRID_ATTR_OVERLINE) ? "overline," : "");
|
||||
if (len > 0)
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
@@ -73,7 +74,8 @@ attributes_fromstring(const char *str)
|
||||
{ "double-underscore", GRID_ATTR_UNDERSCORE_2 },
|
||||
{ "curly-underscore", GRID_ATTR_UNDERSCORE_3 },
|
||||
{ "dotted-underscore", GRID_ATTR_UNDERSCORE_4 },
|
||||
{ "dashed-underscore", GRID_ATTR_UNDERSCORE_5 }
|
||||
{ "dashed-underscore", GRID_ATTR_UNDERSCORE_5 },
|
||||
{ "overline", GRID_ATTR_OVERLINE }
|
||||
};
|
||||
|
||||
if (*str == '\0' || strcspn(str, delimiters) == 0)
|
||||
|
||||
234
cfg.c
234
cfg.c
@@ -26,17 +26,6 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Condition for %if, %elif, %else and %endif. */
|
||||
struct cfg_cond {
|
||||
size_t line; /* line number of %if */
|
||||
int met; /* condition was met */
|
||||
int skip; /* skip later %elif/%else */
|
||||
int saw_else; /* saw a %else */
|
||||
|
||||
TAILQ_ENTRY(cfg_cond) entry;
|
||||
};
|
||||
TAILQ_HEAD(cfg_conds, cfg_cond);
|
||||
|
||||
struct client *cfg_client;
|
||||
static char *cfg_file;
|
||||
int cfg_finished;
|
||||
@@ -81,13 +70,12 @@ void
|
||||
start_cfg(void)
|
||||
{
|
||||
const char *home;
|
||||
int quiet = 0;
|
||||
int flags = 0;
|
||||
struct client *c;
|
||||
|
||||
/*
|
||||
* Configuration files are loaded without a client, so NULL is passed
|
||||
* into load_cfg() and commands run in the global queue with
|
||||
* item->client NULL.
|
||||
* Configuration files are loaded without a client, so commands are run
|
||||
* in the global queue with item->client NULL.
|
||||
*
|
||||
* However, we must block the initial client (but just the initial
|
||||
* client) so that its command runs after the configuration is loaded.
|
||||
@@ -101,210 +89,68 @@ start_cfg(void)
|
||||
cmdq_append(c, cfg_item);
|
||||
}
|
||||
|
||||
load_cfg(TMUX_CONF, NULL, NULL, 1);
|
||||
if (cfg_file == NULL)
|
||||
load_cfg(TMUX_CONF, NULL, NULL, CMD_PARSE_QUIET, NULL);
|
||||
|
||||
if (cfg_file == NULL && (home = find_home()) != NULL) {
|
||||
xasprintf(&cfg_file, "%s/.tmux.conf", home);
|
||||
quiet = 1;
|
||||
flags = CMD_PARSE_QUIET;
|
||||
}
|
||||
if (cfg_file != NULL)
|
||||
load_cfg(cfg_file, NULL, NULL, quiet);
|
||||
load_cfg(cfg_file, NULL, NULL, flags, NULL);
|
||||
|
||||
cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
|
||||
}
|
||||
|
||||
static int
|
||||
cfg_check_condition(const char *path, size_t line, const char *p, int *skip)
|
||||
{
|
||||
struct format_tree *ft;
|
||||
char *s;
|
||||
int result;
|
||||
|
||||
while (isspace((u_char)*p))
|
||||
p++;
|
||||
if (p[0] == '\0') {
|
||||
cfg_add_cause("%s:%zu: invalid condition", path, line);
|
||||
*skip = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
ft = format_create(NULL, NULL, FORMAT_NONE, FORMAT_NOJOBS);
|
||||
s = format_expand(ft, p);
|
||||
result = format_true(s);
|
||||
free(s);
|
||||
format_free(ft);
|
||||
|
||||
*skip = result;
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
cfg_handle_if(const char *path, size_t line, struct cfg_conds *conds,
|
||||
const char *p)
|
||||
{
|
||||
struct cfg_cond *cond;
|
||||
struct cfg_cond *parent = TAILQ_FIRST(conds);
|
||||
|
||||
/*
|
||||
* Add a new condition. If a previous condition exists and isn't
|
||||
* currently met, this new one also can't be met.
|
||||
*/
|
||||
cond = xcalloc(1, sizeof *cond);
|
||||
cond->line = line;
|
||||
if (parent == NULL || parent->met)
|
||||
cond->met = cfg_check_condition(path, line, p, &cond->skip);
|
||||
else
|
||||
cond->skip = 1;
|
||||
cond->saw_else = 0;
|
||||
TAILQ_INSERT_HEAD(conds, cond, entry);
|
||||
}
|
||||
|
||||
static void
|
||||
cfg_handle_elif(const char *path, size_t line, struct cfg_conds *conds,
|
||||
const char *p)
|
||||
{
|
||||
struct cfg_cond *cond = TAILQ_FIRST(conds);
|
||||
|
||||
/*
|
||||
* If a previous condition exists and wasn't met, check this
|
||||
* one instead and change the state.
|
||||
*/
|
||||
if (cond == NULL || cond->saw_else)
|
||||
cfg_add_cause("%s:%zu: unexpected %%elif", path, line);
|
||||
else if (!cond->skip)
|
||||
cond->met = cfg_check_condition(path, line, p, &cond->skip);
|
||||
else
|
||||
cond->met = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cfg_handle_else(const char *path, size_t line, struct cfg_conds *conds)
|
||||
{
|
||||
struct cfg_cond *cond = TAILQ_FIRST(conds);
|
||||
|
||||
/*
|
||||
* If a previous condition exists and wasn't met and wasn't already
|
||||
* %else, use this one instead.
|
||||
*/
|
||||
if (cond == NULL || cond->saw_else) {
|
||||
cfg_add_cause("%s:%zu: unexpected %%else", path, line);
|
||||
return;
|
||||
}
|
||||
cond->saw_else = 1;
|
||||
cond->met = !cond->skip;
|
||||
cond->skip = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
cfg_handle_endif(const char *path, size_t line, struct cfg_conds *conds)
|
||||
{
|
||||
struct cfg_cond *cond = TAILQ_FIRST(conds);
|
||||
|
||||
/*
|
||||
* Remove previous condition if one exists.
|
||||
*/
|
||||
if (cond == NULL) {
|
||||
cfg_add_cause("%s:%zu: unexpected %%endif", path, line);
|
||||
return;
|
||||
}
|
||||
TAILQ_REMOVE(conds, cond, entry);
|
||||
free(cond);
|
||||
}
|
||||
|
||||
static void
|
||||
cfg_handle_directive(const char *p, const char *path, size_t line,
|
||||
struct cfg_conds *conds)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
while (p[n] != '\0' && !isspace((u_char)p[n]))
|
||||
n++;
|
||||
if (strncmp(p, "%if", n) == 0)
|
||||
cfg_handle_if(path, line, conds, p + n);
|
||||
else if (strncmp(p, "%elif", n) == 0)
|
||||
cfg_handle_elif(path, line, conds, p + n);
|
||||
else if (strcmp(p, "%else") == 0)
|
||||
cfg_handle_else(path, line, conds);
|
||||
else if (strcmp(p, "%endif") == 0)
|
||||
cfg_handle_endif(path, line, conds);
|
||||
else
|
||||
cfg_add_cause("%s:%zu: invalid directive: %s", path, line, p);
|
||||
}
|
||||
|
||||
int
|
||||
load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
|
||||
load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
|
||||
struct cmdq_item **new_item)
|
||||
{
|
||||
FILE *f;
|
||||
const char delim[3] = { '\\', '\\', '\0' };
|
||||
u_int found = 0;
|
||||
size_t line = 0;
|
||||
char *buf, *cause1, *p, *q;
|
||||
struct cmd_list *cmdlist;
|
||||
struct cmdq_item *new_item;
|
||||
struct cfg_cond *cond, *cond1;
|
||||
struct cfg_conds conds;
|
||||
struct cmd_parse_input pi;
|
||||
struct cmd_parse_result *pr;
|
||||
struct cmdq_item *new_item0;
|
||||
|
||||
TAILQ_INIT(&conds);
|
||||
if (new_item != NULL)
|
||||
*new_item = NULL;
|
||||
|
||||
log_debug("loading %s", path);
|
||||
if ((f = fopen(path, "rb")) == NULL) {
|
||||
if (errno == ENOENT && quiet)
|
||||
if (errno == ENOENT && (flags & CMD_PARSE_QUIET))
|
||||
return (0);
|
||||
cfg_add_cause("%s: %s", path, strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
while ((buf = fparseln(f, NULL, &line, delim, 0)) != NULL) {
|
||||
log_debug("%s: %s", path, buf);
|
||||
memset(&pi, 0, sizeof pi);
|
||||
pi.flags = flags;
|
||||
pi.file = path;
|
||||
pi.line = 1;
|
||||
|
||||
p = buf;
|
||||
while (isspace((u_char)*p))
|
||||
p++;
|
||||
if (*p == '\0') {
|
||||
free(buf);
|
||||
continue;
|
||||
}
|
||||
q = p + strlen(p) - 1;
|
||||
while (q != p && isspace((u_char)*q))
|
||||
*q-- = '\0';
|
||||
|
||||
if (*p == '%') {
|
||||
cfg_handle_directive(p, path, line, &conds);
|
||||
continue;
|
||||
}
|
||||
cond = TAILQ_FIRST(&conds);
|
||||
if (cond != NULL && !cond->met)
|
||||
continue;
|
||||
|
||||
cmdlist = cmd_string_parse(p, path, line, &cause1);
|
||||
if (cmdlist == NULL) {
|
||||
free(buf);
|
||||
if (cause1 == NULL)
|
||||
continue;
|
||||
cfg_add_cause("%s:%zu: %s", path, line, cause1);
|
||||
free(cause1);
|
||||
continue;
|
||||
}
|
||||
free(buf);
|
||||
|
||||
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
|
||||
if (item != NULL)
|
||||
cmdq_insert_after(item, new_item);
|
||||
else
|
||||
cmdq_append(c, new_item);
|
||||
cmd_list_free(cmdlist);
|
||||
|
||||
found++;
|
||||
}
|
||||
pr = cmd_parse_from_file(f, &pi);
|
||||
fclose(f);
|
||||
|
||||
TAILQ_FOREACH_REVERSE_SAFE(cond, &conds, cfg_conds, entry, cond1) {
|
||||
cfg_add_cause("%s:%zu: unterminated %%if", path, cond->line);
|
||||
TAILQ_REMOVE(&conds, cond, entry);
|
||||
free(cond);
|
||||
if (pr->status == CMD_PARSE_EMPTY)
|
||||
return (0);
|
||||
if (pr->status == CMD_PARSE_ERROR) {
|
||||
cfg_add_cause("%s", pr->error);
|
||||
free(pr->error);
|
||||
return (-1);
|
||||
}
|
||||
if (flags & CMD_PARSE_PARSEONLY) {
|
||||
cmd_list_free(pr->cmdlist);
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (found);
|
||||
new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
|
||||
if (item != NULL)
|
||||
cmdq_insert_after(item, new_item0);
|
||||
else
|
||||
cmdq_append(c, new_item0);
|
||||
cmd_list_free(pr->cmdlist);
|
||||
|
||||
if (new_item != NULL)
|
||||
*new_item = new_item0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
14
client.c
14
client.c
@@ -215,14 +215,13 @@ client_exit_message(void)
|
||||
int
|
||||
client_main(struct event_base *base, int argc, char **argv, int flags)
|
||||
{
|
||||
struct cmd_parse_result *pr;
|
||||
struct cmd *cmd;
|
||||
struct cmd_list *cmdlist;
|
||||
struct msg_command_data *data;
|
||||
int cmdflags, fd, i;
|
||||
const char *ttynam, *cwd;
|
||||
pid_t ppid;
|
||||
enum msgtype msg;
|
||||
char *cause;
|
||||
struct termios tio, saved_tio;
|
||||
size_t size;
|
||||
|
||||
@@ -248,14 +247,15 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
|
||||
* later in server) but it is necessary to get the start server
|
||||
* flag.
|
||||
*/
|
||||
cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause);
|
||||
if (cmdlist != NULL) {
|
||||
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
|
||||
pr = cmd_parse_from_arguments(argc, argv, NULL);
|
||||
if (pr->status == CMD_PARSE_SUCCESS) {
|
||||
TAILQ_FOREACH(cmd, &pr->cmdlist->list, qentry) {
|
||||
if (cmd->entry->flags & CMD_STARTSERVER)
|
||||
cmdflags |= CMD_STARTSERVER;
|
||||
}
|
||||
cmd_list_free(cmdlist);
|
||||
}
|
||||
cmd_list_free(pr->cmdlist);
|
||||
} else
|
||||
free(pr->error);
|
||||
}
|
||||
|
||||
/* Create client process structure (starts logging). */
|
||||
|
||||
@@ -87,7 +87,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
|
||||
|
||||
if (wl != NULL) {
|
||||
if (wp != NULL)
|
||||
window_set_active_pane(wp->window, wp);
|
||||
window_set_active_pane(wp->window, wp, 1);
|
||||
session_set_current(s, wl);
|
||||
if (wp != NULL)
|
||||
cmd_find_from_winlink_pane(current, wl, wp, 0);
|
||||
|
||||
@@ -44,15 +44,16 @@ const struct cmd_entry cmd_bind_key_entry = {
|
||||
static enum cmd_retval
|
||||
cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
char *cause;
|
||||
struct cmd_list *cmdlist;
|
||||
key_code key;
|
||||
const char *tablename;
|
||||
struct args *args = self->args;
|
||||
key_code key;
|
||||
const char *tablename;
|
||||
struct cmd_parse_result *pr;
|
||||
char **argv = args->argv;
|
||||
int argc = args->argc;
|
||||
|
||||
key = key_string_lookup_string(args->argv[0]);
|
||||
key = key_string_lookup_string(argv[0]);
|
||||
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
|
||||
cmdq_error(item, "unknown key: %s", args->argv[0]);
|
||||
cmdq_error(item, "unknown key: %s", argv[0]);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
@@ -63,14 +64,21 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
|
||||
else
|
||||
tablename = "prefix";
|
||||
|
||||
cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0,
|
||||
&cause);
|
||||
if (cmdlist == NULL) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
if (argc == 2)
|
||||
pr = cmd_parse_from_string(argv[1], NULL);
|
||||
else
|
||||
pr = cmd_parse_from_arguments(argc - 1, argv + 1, NULL);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_EMPTY:
|
||||
cmdq_error(item, "empty command");
|
||||
return (CMD_RETURN_ERROR);
|
||||
case CMD_PARSE_ERROR:
|
||||
cmdq_error(item, "%s", pr->error);
|
||||
free(pr->error);
|
||||
return (CMD_RETURN_ERROR);
|
||||
case CMD_PARSE_SUCCESS:
|
||||
break;
|
||||
}
|
||||
|
||||
key_bindings_add(tablename, key, args_has(args, 'r'), cmdlist);
|
||||
key_bindings_add(tablename, key, args_has(args, 'r'), pr->cmdlist);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -129,26 +129,15 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_command_prompt_error(struct cmdq_item *item, void *data)
|
||||
{
|
||||
char *error = data;
|
||||
|
||||
cmdq_error(item, "%s", error);
|
||||
free(error);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_command_prompt_callback(struct client *c, void *data, const char *s,
|
||||
int done)
|
||||
{
|
||||
struct cmd_command_prompt_cdata *cdata = data;
|
||||
struct cmd_list *cmdlist;
|
||||
struct cmdq_item *new_item;
|
||||
char *cause, *new_template, *prompt, *ptr;
|
||||
char *new_template, *prompt, *ptr;
|
||||
char *input = NULL;
|
||||
struct cmd_parse_result *pr;
|
||||
|
||||
if (s == NULL)
|
||||
return (0);
|
||||
@@ -175,20 +164,22 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
|
||||
return (1);
|
||||
}
|
||||
|
||||
cmdlist = cmd_string_parse(new_template, NULL, 0, &cause);
|
||||
if (cmdlist == NULL) {
|
||||
if (cause != NULL) {
|
||||
new_item = cmdq_get_callback(cmd_command_prompt_error,
|
||||
cause);
|
||||
} else
|
||||
new_item = NULL;
|
||||
} else {
|
||||
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
|
||||
cmd_list_free(cmdlist);
|
||||
}
|
||||
|
||||
if (new_item != NULL)
|
||||
pr = cmd_parse_from_string(new_template, NULL);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_EMPTY:
|
||||
new_item = NULL;
|
||||
break;
|
||||
case CMD_PARSE_ERROR:
|
||||
new_item = cmdq_get_error(pr->error);
|
||||
free(pr->error);
|
||||
cmdq_append(c, new_item);
|
||||
break;
|
||||
case CMD_PARSE_SUCCESS:
|
||||
new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
|
||||
cmd_list_free(pr->cmdlist);
|
||||
cmdq_append(c, new_item);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!done)
|
||||
free(new_template);
|
||||
|
||||
@@ -82,48 +82,38 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_confirm_before_error(struct cmdq_item *item, void *data)
|
||||
{
|
||||
char *error = data;
|
||||
|
||||
cmdq_error(item, "%s", error);
|
||||
free(error);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_confirm_before_callback(struct client *c, void *data, const char *s,
|
||||
__unused int done)
|
||||
{
|
||||
struct cmd_confirm_before_data *cdata = data;
|
||||
struct cmd_list *cmdlist;
|
||||
struct cmdq_item *new_item;
|
||||
char *cause;
|
||||
struct cmd_parse_result *pr;
|
||||
|
||||
if (c->flags & CLIENT_DEAD)
|
||||
return (0);
|
||||
|
||||
if (s == NULL || *s == '\0')
|
||||
return (0);
|
||||
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
|
||||
if (tolower((u_char)s[0]) != 'y' || s[1] != '\0')
|
||||
return (0);
|
||||
|
||||
cmdlist = cmd_string_parse(cdata->cmd, NULL, 0, &cause);
|
||||
if (cmdlist == NULL) {
|
||||
if (cause != NULL) {
|
||||
new_item = cmdq_get_callback(cmd_confirm_before_error,
|
||||
cause);
|
||||
} else
|
||||
new_item = NULL;
|
||||
} else {
|
||||
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
|
||||
cmd_list_free(cmdlist);
|
||||
}
|
||||
|
||||
if (new_item != NULL)
|
||||
pr = cmd_parse_from_string(cdata->cmd, NULL);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_EMPTY:
|
||||
new_item = NULL;
|
||||
break;
|
||||
case CMD_PARSE_ERROR:
|
||||
new_item = cmdq_get_error(pr->error);
|
||||
free(pr->error);
|
||||
cmdq_append(c, new_item);
|
||||
break;
|
||||
case CMD_PARSE_SUCCESS:
|
||||
new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
|
||||
cmd_list_free(pr->cmdlist);
|
||||
cmdq_append(c, new_item);
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -73,10 +73,10 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (window_pane_set_mode(wp, &window_copy_mode, NULL, args) != 0)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (args_has(args, 'M'))
|
||||
window_copy_start_drag(c, &shared->mouse);
|
||||
if (!window_pane_set_mode(wp, &window_copy_mode, NULL, args)) {
|
||||
if (args_has(args, 'M'))
|
||||
window_copy_start_drag(c, &shared->mouse);
|
||||
}
|
||||
if (args_has(self->args, 'u'))
|
||||
window_copy_pageup(wp, 0);
|
||||
|
||||
|
||||
178
cmd-display-menu.c
Normal file
178
cmd-display-menu.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* Display a menu on a client.
|
||||
*/
|
||||
|
||||
static enum cmd_retval cmd_display_menu_exec(struct cmd *,
|
||||
struct cmdq_item *);
|
||||
|
||||
const struct cmd_entry cmd_display_menu_entry = {
|
||||
.name = "display-menu",
|
||||
.alias = "menu",
|
||||
|
||||
.args = { "c:t:T:x:y:", 1, -1 },
|
||||
.usage = "[-c target-client] " CMD_TARGET_PANE_USAGE " [-T title] "
|
||||
"[-x position] [-y position] name key command ...",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.exec = cmd_display_menu_exec
|
||||
};
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
struct client *c;
|
||||
struct session *s = item->target.s;
|
||||
struct winlink *wl = item->target.wl;
|
||||
struct window_pane *wp = item->target.wp;
|
||||
struct cmd_find_state *fs = &item->target;
|
||||
struct menu *menu = NULL;
|
||||
struct style_range *sr;
|
||||
struct menu_item menu_item;
|
||||
const char *xp, *yp, *key;
|
||||
char *title, *name;
|
||||
int at, flags, i;
|
||||
u_int px, py, ox, oy, sx, sy;
|
||||
|
||||
if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
|
||||
return (CMD_RETURN_ERROR);
|
||||
if (c->overlay_draw != NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
at = status_at_line(c);
|
||||
|
||||
if (args_has(args, 'T'))
|
||||
title = format_single(NULL, args_get(args, 'T'), c, s, wl, wp);
|
||||
else
|
||||
title = xstrdup("");
|
||||
|
||||
menu = menu_create(title);
|
||||
|
||||
for (i = 0; i != args->argc; /* nothing */) {
|
||||
name = args->argv[i++];
|
||||
if (*name == '\0') {
|
||||
menu_add_item(menu, NULL, item, c, fs);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (args->argc - i < 2) {
|
||||
cmdq_error(item, "not enough arguments");
|
||||
free(title);
|
||||
menu_free(menu);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
key = args->argv[i++];
|
||||
|
||||
menu_item.name = name;
|
||||
menu_item.key = key_string_lookup_string(key);
|
||||
menu_item.command = args->argv[i++];
|
||||
|
||||
menu_add_item(menu, &menu_item, item, c, fs);
|
||||
}
|
||||
free(title);
|
||||
if (menu == NULL) {
|
||||
cmdq_error(item, "invalid menu arguments");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (menu->count == 0) {
|
||||
menu_free(menu);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
xp = args_get(args, 'x');
|
||||
if (xp == NULL)
|
||||
px = 0;
|
||||
else if (strcmp(xp, "R") == 0)
|
||||
px = c->tty.sx - 1;
|
||||
else if (strcmp(xp, "P") == 0) {
|
||||
tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
|
||||
if (wp->xoff >= ox)
|
||||
px = wp->xoff - ox;
|
||||
else
|
||||
px = 0;
|
||||
} else if (strcmp(xp, "M") == 0 && item->shared->mouse.valid) {
|
||||
if (item->shared->mouse.x > (menu->width + 4) / 2)
|
||||
px = item->shared->mouse.x - (menu->width + 4) / 2;
|
||||
else
|
||||
px = 0;
|
||||
}
|
||||
else if (strcmp(xp, "W") == 0) {
|
||||
if (at == -1)
|
||||
px = 0;
|
||||
else {
|
||||
TAILQ_FOREACH(sr, &c->status.entries[0].ranges, entry) {
|
||||
if (sr->type != STYLE_RANGE_WINDOW)
|
||||
continue;
|
||||
if (sr->argument == (u_int)wl->idx)
|
||||
break;
|
||||
}
|
||||
if (sr != NULL)
|
||||
px = sr->start;
|
||||
else
|
||||
px = 0;
|
||||
}
|
||||
} else
|
||||
px = strtoul(xp, NULL, 10);
|
||||
if (px + menu->width + 4 >= c->tty.sx)
|
||||
px = c->tty.sx - menu->width - 4;
|
||||
|
||||
yp = args_get(args, 'y');
|
||||
if (yp == NULL)
|
||||
py = 0;
|
||||
else if (strcmp(yp, "P") == 0) {
|
||||
tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
|
||||
if (wp->yoff + wp->sy >= oy)
|
||||
py = wp->yoff + wp->sy - oy;
|
||||
else
|
||||
py = 0;
|
||||
} else if (strcmp(yp, "M") == 0 && item->shared->mouse.valid)
|
||||
py = item->shared->mouse.y + menu->count + 2;
|
||||
else if (strcmp(yp, "S") == 0) {
|
||||
if (at == -1)
|
||||
py = c->tty.sy;
|
||||
else if (at == 0)
|
||||
py = status_line_size(c) + menu->count + 2;
|
||||
else
|
||||
py = at;
|
||||
} else
|
||||
py = strtoul(yp, NULL, 10);
|
||||
if (py < menu->count + 2)
|
||||
py = 0;
|
||||
else
|
||||
py -= menu->count + 2;
|
||||
if (py + menu->count + 2 >= c->tty.sy)
|
||||
py = c->tty.sy - menu->count - 2;
|
||||
|
||||
flags = 0;
|
||||
if (!item->shared->mouse.valid)
|
||||
flags |= MENU_NOMOUSE;
|
||||
if (menu_display(menu, flags, item, px, py, c, fs, NULL, NULL) != 0)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
return (CMD_RETURN_WAIT);
|
||||
}
|
||||
@@ -39,8 +39,8 @@ const struct cmd_entry cmd_display_message_entry = {
|
||||
.name = "display-message",
|
||||
.alias = "display",
|
||||
|
||||
.args = { "ac:pt:F:v", 0, 1 },
|
||||
.usage = "[-apv] [-c target-client] [-F format] "
|
||||
.args = { "ac:Ipt:F:v", 0, 1 },
|
||||
.usage = "[-aIpv] [-c target-client] [-F format] "
|
||||
CMD_TARGET_PANE_USAGE " [message]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
@@ -66,10 +66,19 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct winlink *wl = item->target.wl;
|
||||
struct window_pane *wp = item->target.wp;
|
||||
const char *template;
|
||||
char *msg;
|
||||
char *msg, *cause;
|
||||
struct format_tree *ft;
|
||||
int flags;
|
||||
|
||||
if (args_has(args, 'I')) {
|
||||
if (window_pane_start_input(wp, item, &cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
return (CMD_RETURN_WAIT);
|
||||
}
|
||||
|
||||
if (args_has(args, 'F') && args->argc != 0) {
|
||||
cmdq_error(item, "only one of -F or argument must be given");
|
||||
return (CMD_RETURN_ERROR);
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
@@ -30,9 +30,6 @@
|
||||
static enum cmd_retval cmd_display_panes_exec(struct cmd *,
|
||||
struct cmdq_item *);
|
||||
|
||||
static void cmd_display_panes_callback(struct client *,
|
||||
struct window_pane *);
|
||||
|
||||
const struct cmd_entry cmd_display_panes_entry = {
|
||||
.name = "display-panes",
|
||||
.alias = "displayp",
|
||||
@@ -44,32 +41,218 @@ const struct cmd_entry cmd_display_panes_entry = {
|
||||
.exec = cmd_display_panes_exec
|
||||
};
|
||||
|
||||
struct cmd_display_panes_data {
|
||||
struct cmdq_item *item;
|
||||
char *command;
|
||||
};
|
||||
|
||||
static void
|
||||
cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
||||
struct window_pane *wp)
|
||||
{
|
||||
struct client *c = ctx->c;
|
||||
struct tty *tty = &c->tty;
|
||||
struct session *s = c->session;
|
||||
struct options *oo = s->options;
|
||||
struct window *w = wp->window;
|
||||
struct grid_cell gc;
|
||||
u_int idx, px, py, i, j, xoff, yoff, sx, sy;
|
||||
int colour, active_colour;
|
||||
char buf[16], *ptr;
|
||||
size_t len;
|
||||
|
||||
if (wp->xoff + wp->sx <= ctx->ox ||
|
||||
wp->xoff >= ctx->ox + ctx->sx ||
|
||||
wp->yoff + wp->sy <= ctx->oy ||
|
||||
wp->yoff >= ctx->oy + ctx->sy)
|
||||
return;
|
||||
|
||||
if (wp->xoff >= ctx->ox && wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
|
||||
/* All visible. */
|
||||
xoff = wp->xoff - ctx->ox;
|
||||
sx = wp->sx;
|
||||
} else if (wp->xoff < ctx->ox &&
|
||||
wp->xoff + wp->sx > ctx->ox + ctx->sx) {
|
||||
/* Both left and right not visible. */
|
||||
xoff = 0;
|
||||
sx = ctx->sx;
|
||||
} else if (wp->xoff < ctx->ox) {
|
||||
/* Left not visible. */
|
||||
xoff = 0;
|
||||
sx = wp->sx - (ctx->ox - wp->xoff);
|
||||
} else {
|
||||
/* Right not visible. */
|
||||
xoff = wp->xoff - ctx->ox;
|
||||
sx = wp->sx - xoff;
|
||||
}
|
||||
if (wp->yoff >= ctx->oy && wp->yoff + wp->sy <= ctx->oy + ctx->sy) {
|
||||
/* All visible. */
|
||||
yoff = wp->yoff - ctx->oy;
|
||||
sy = wp->sy;
|
||||
} else if (wp->yoff < ctx->oy &&
|
||||
wp->yoff + wp->sy > ctx->oy + ctx->sy) {
|
||||
/* Both top and bottom not visible. */
|
||||
yoff = 0;
|
||||
sy = ctx->sy;
|
||||
} else if (wp->yoff < ctx->oy) {
|
||||
/* Top not visible. */
|
||||
yoff = 0;
|
||||
sy = wp->sy - (ctx->oy - wp->yoff);
|
||||
} else {
|
||||
/* Bottom not visible. */
|
||||
yoff = wp->yoff - ctx->oy;
|
||||
sy = wp->sy - yoff;
|
||||
}
|
||||
|
||||
if (ctx->statustop)
|
||||
yoff += ctx->statuslines;
|
||||
px = sx / 2;
|
||||
py = sy / 2;
|
||||
|
||||
if (window_pane_index(wp, &idx) != 0)
|
||||
fatalx("index not found");
|
||||
len = xsnprintf(buf, sizeof buf, "%u", idx);
|
||||
|
||||
if (sx < len)
|
||||
return;
|
||||
colour = options_get_number(oo, "display-panes-colour");
|
||||
active_colour = options_get_number(oo, "display-panes-active-colour");
|
||||
|
||||
if (sx < len * 6 || sy < 5) {
|
||||
tty_cursor(tty, xoff + px - len / 2, yoff + py);
|
||||
goto draw_text;
|
||||
}
|
||||
|
||||
px -= len * 3;
|
||||
py -= 2;
|
||||
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
if (w->active == wp)
|
||||
gc.bg = active_colour;
|
||||
else
|
||||
gc.bg = colour;
|
||||
gc.flags |= GRID_FLAG_NOPALETTE;
|
||||
|
||||
tty_attributes(tty, &gc, wp);
|
||||
for (ptr = buf; *ptr != '\0'; ptr++) {
|
||||
if (*ptr < '0' || *ptr > '9')
|
||||
continue;
|
||||
idx = *ptr - '0';
|
||||
|
||||
for (j = 0; j < 5; j++) {
|
||||
for (i = px; i < px + 5; i++) {
|
||||
tty_cursor(tty, xoff + i, yoff + py + j);
|
||||
if (window_clock_table[idx][j][i - px])
|
||||
tty_putc(tty, ' ');
|
||||
}
|
||||
}
|
||||
px += 6;
|
||||
}
|
||||
|
||||
len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy);
|
||||
if (sx < len || sy < 6)
|
||||
return;
|
||||
tty_cursor(tty, xoff + sx - len, yoff);
|
||||
|
||||
draw_text:
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
if (w->active == wp)
|
||||
gc.fg = active_colour;
|
||||
else
|
||||
gc.fg = colour;
|
||||
gc.flags |= GRID_FLAG_NOPALETTE;
|
||||
|
||||
tty_attributes(tty, &gc, wp);
|
||||
tty_puts(tty, buf);
|
||||
|
||||
tty_cursor(tty, 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_display_panes_draw(struct client *c, struct screen_redraw_ctx *ctx)
|
||||
{
|
||||
struct window *w = c->session->curw->window;
|
||||
struct window_pane *wp;
|
||||
|
||||
log_debug("%s: %s @%u", __func__, c->name, w->id);
|
||||
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (window_pane_visible(wp))
|
||||
cmd_display_panes_draw_pane(ctx, wp);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_display_panes_free(struct client *c)
|
||||
{
|
||||
struct cmd_display_panes_data *cdata = c->overlay_data;
|
||||
|
||||
if (cdata->item != NULL)
|
||||
cdata->item->flags &= ~CMDQ_WAITING;
|
||||
free(cdata->command);
|
||||
free(cdata);
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_display_panes_key(struct client *c, struct key_event *event)
|
||||
{
|
||||
struct cmd_display_panes_data *cdata = c->overlay_data;
|
||||
struct cmdq_item *new_item;
|
||||
char *cmd, *expanded;
|
||||
struct window *w = c->session->curw->window;
|
||||
struct window_pane *wp;
|
||||
struct cmd_parse_result *pr;
|
||||
|
||||
if (event->key < '0' || event->key > '9')
|
||||
return (1);
|
||||
|
||||
wp = window_pane_at_index(w, event->key - '0');
|
||||
if (wp == NULL)
|
||||
return (1);
|
||||
window_unzoom(w);
|
||||
|
||||
xasprintf(&expanded, "%%%u", wp->id);
|
||||
cmd = cmd_template_replace(cdata->command, expanded, 1);
|
||||
|
||||
pr = cmd_parse_from_string(cmd, NULL);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_EMPTY:
|
||||
new_item = NULL;
|
||||
break;
|
||||
case CMD_PARSE_ERROR:
|
||||
new_item = cmdq_get_error(pr->error);
|
||||
free(pr->error);
|
||||
cmdq_append(c, new_item);
|
||||
break;
|
||||
case CMD_PARSE_SUCCESS:
|
||||
new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
|
||||
cmd_list_free(pr->cmdlist);
|
||||
cmdq_append(c, new_item);
|
||||
break;
|
||||
}
|
||||
|
||||
free(cmd);
|
||||
free(expanded);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
u_int delay;
|
||||
char *cause;
|
||||
struct args *args = self->args;
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
u_int delay;
|
||||
char *cause;
|
||||
struct cmd_display_panes_data *cdata;
|
||||
|
||||
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
|
||||
return (CMD_RETURN_ERROR);
|
||||
s = c->session;
|
||||
|
||||
if (c->identify_callback != NULL)
|
||||
if (c->overlay_draw != NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
c->identify_callback = cmd_display_panes_callback;
|
||||
if (args->argc != 0)
|
||||
c->identify_callback_data = xstrdup(args->argv[0]);
|
||||
else
|
||||
c->identify_callback_data = xstrdup("select-pane -t '%%'");
|
||||
if (args_has(args, 'b'))
|
||||
c->identify_callback_item = NULL;
|
||||
else
|
||||
c->identify_callback_item = item;
|
||||
|
||||
if (args_has(args, 'd')) {
|
||||
delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause);
|
||||
if (cause != NULL) {
|
||||
@@ -79,65 +262,21 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
} else
|
||||
delay = options_get_number(s->options, "display-panes-time");
|
||||
server_client_set_identify(c, delay);
|
||||
|
||||
cdata = xmalloc(sizeof *cdata);
|
||||
if (args->argc != 0)
|
||||
cdata->command = xstrdup(args->argv[0]);
|
||||
else
|
||||
cdata->command = xstrdup("select-pane -t '%%'");
|
||||
if (args_has(args, 'b'))
|
||||
cdata->item = NULL;
|
||||
else
|
||||
cdata->item = item;
|
||||
|
||||
server_client_set_overlay(c, delay, cmd_display_panes_draw,
|
||||
cmd_display_panes_key, cmd_display_panes_free, cdata);
|
||||
|
||||
if (args_has(args, 'b'))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
return (CMD_RETURN_WAIT);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_display_panes_error(struct cmdq_item *item, void *data)
|
||||
{
|
||||
char *error = data;
|
||||
|
||||
cmdq_error(item, "%s", error);
|
||||
free(error);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_display_panes_callback(struct client *c, struct window_pane *wp)
|
||||
{
|
||||
struct cmd_list *cmdlist;
|
||||
struct cmdq_item *new_item;
|
||||
char *cmd, *expanded, *cause;
|
||||
|
||||
if (wp == NULL)
|
||||
goto out;
|
||||
|
||||
xasprintf(&expanded, "%%%u", wp->id);
|
||||
cmd = cmd_template_replace(c->identify_callback_data, expanded, 1);
|
||||
|
||||
cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);
|
||||
if (cmdlist == NULL && cause != NULL)
|
||||
new_item = cmdq_get_callback(cmd_display_panes_error, cause);
|
||||
else if (cmdlist == NULL)
|
||||
new_item = NULL;
|
||||
else {
|
||||
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
|
||||
cmd_list_free(cmdlist);
|
||||
}
|
||||
|
||||
if (new_item != NULL) {
|
||||
if (c->identify_callback_item != NULL)
|
||||
cmdq_insert_after(c->identify_callback_item, new_item);
|
||||
else
|
||||
cmdq_append(c, new_item);
|
||||
}
|
||||
|
||||
free(cmd);
|
||||
free(expanded);
|
||||
|
||||
out:
|
||||
if (c->identify_callback_item != NULL) {
|
||||
c->identify_callback_item->flags &= ~CMDQ_WAITING;
|
||||
c->identify_callback_item = NULL;
|
||||
}
|
||||
|
||||
free(c->identify_callback_data);
|
||||
c->identify_callback_data = NULL;
|
||||
|
||||
c->identify_callback = NULL;
|
||||
}
|
||||
|
||||
@@ -1039,12 +1039,16 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
|
||||
switch (type) {
|
||||
case CMD_FIND_PANE:
|
||||
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
|
||||
if (fs->wp != NULL)
|
||||
if (fs->wp != NULL) {
|
||||
fs->w = fs->wl->window;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case CMD_FIND_WINDOW:
|
||||
case CMD_FIND_SESSION:
|
||||
fs->wl = cmd_mouse_window(m, &fs->s);
|
||||
if (fs->wl == NULL && fs->s != NULL)
|
||||
fs->wl = fs->s->curw;
|
||||
if (fs->wl != NULL) {
|
||||
fs->w = fs->wl->window;
|
||||
fs->wp = fs->w->active;
|
||||
|
||||
@@ -49,8 +49,7 @@ const struct cmd_entry cmd_if_shell_entry = {
|
||||
};
|
||||
|
||||
struct cmd_if_shell_data {
|
||||
char *file;
|
||||
u_int line;
|
||||
struct cmd_parse_input input;
|
||||
|
||||
char *cmd_if;
|
||||
char *cmd_else;
|
||||
@@ -64,51 +63,62 @@ static enum cmd_retval
|
||||
cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
struct cmdq_shared *shared = item->shared;
|
||||
struct mouse_event *m = &item->shared->mouse;
|
||||
struct cmd_if_shell_data *cdata;
|
||||
char *shellcmd, *cmd, *cause;
|
||||
struct cmd_list *cmdlist;
|
||||
char *shellcmd, *cmd;
|
||||
struct cmdq_item *new_item;
|
||||
struct client *c = cmd_find_client(item, NULL, 1);
|
||||
struct session *s = item->target.s;
|
||||
struct winlink *wl = item->target.wl;
|
||||
struct window_pane *wp = item->target.wp;
|
||||
struct cmd_parse_input pi;
|
||||
struct cmd_parse_result *pr;
|
||||
|
||||
shellcmd = format_single(item, args->argv[0], c, s, wl, wp);
|
||||
if (args_has(args, 'F')) {
|
||||
cmd = NULL;
|
||||
if (*shellcmd != '0' && *shellcmd != '\0')
|
||||
cmd = args->argv[1];
|
||||
else if (args->argc == 3)
|
||||
cmd = args->argv[2];
|
||||
else
|
||||
cmd = NULL;
|
||||
free(shellcmd);
|
||||
if (cmd == NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);
|
||||
if (cmdlist == NULL) {
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
}
|
||||
|
||||
memset(&pi, 0, sizeof pi);
|
||||
if (self->file != NULL)
|
||||
pi.file = self->file;
|
||||
pi.line = self->line;
|
||||
pi.item = item;
|
||||
pi.c = c;
|
||||
cmd_find_copy_state(&pi.fs, &item->target);
|
||||
|
||||
pr = cmd_parse_from_string(cmd, &pi);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_EMPTY:
|
||||
break;
|
||||
case CMD_PARSE_ERROR:
|
||||
cmdq_error(item, "%s", pr->error);
|
||||
free(pr->error);
|
||||
return (CMD_RETURN_ERROR);
|
||||
case CMD_PARSE_SUCCESS:
|
||||
new_item = cmdq_get_command(pr->cmdlist, NULL, m, 0);
|
||||
cmdq_insert_after(item, new_item);
|
||||
cmd_list_free(pr->cmdlist);
|
||||
break;
|
||||
}
|
||||
new_item = cmdq_get_command(cmdlist, NULL, &shared->mouse, 0);
|
||||
cmdq_insert_after(item, new_item);
|
||||
cmd_list_free(cmdlist);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
cdata = xcalloc(1, sizeof *cdata);
|
||||
if (self->file != NULL) {
|
||||
cdata->file = xstrdup(self->file);
|
||||
cdata->line = self->line;
|
||||
}
|
||||
|
||||
cdata->cmd_if = xstrdup(args->argv[1]);
|
||||
if (args->argc == 3)
|
||||
cdata->cmd_else = xstrdup(args->argv[2]);
|
||||
else
|
||||
cdata->cmd_else = NULL;
|
||||
memcpy(&cdata->mouse, m, sizeof cdata->mouse);
|
||||
|
||||
cdata->client = item->client;
|
||||
if (cdata->client != NULL)
|
||||
@@ -118,7 +128,16 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cdata->item = item;
|
||||
else
|
||||
cdata->item = NULL;
|
||||
memcpy(&cdata->mouse, &shared->mouse, sizeof cdata->mouse);
|
||||
|
||||
memset(&cdata->input, 0, sizeof cdata->input);
|
||||
if (self->file != NULL)
|
||||
cdata->input.file = xstrdup(self->file);
|
||||
cdata->input.line = self->line;
|
||||
cdata->input.item = cdata->item;
|
||||
cdata->input.c = c;
|
||||
if (cdata->input.c != NULL)
|
||||
cdata->input.c->references++;
|
||||
cmd_find_copy_state(&cdata->input.fs, &item->target);
|
||||
|
||||
if (job_run(shellcmd, s, server_client_get_cwd(item->client, s), NULL,
|
||||
cmd_if_shell_callback, cmd_if_shell_free, cdata, 0) == NULL) {
|
||||
@@ -139,11 +158,11 @@ cmd_if_shell_callback(struct job *job)
|
||||
{
|
||||
struct cmd_if_shell_data *cdata = job_get_data(job);
|
||||
struct client *c = cdata->client;
|
||||
struct cmd_list *cmdlist;
|
||||
struct cmdq_item *new_item;
|
||||
char *cause, *cmd, *file = cdata->file;
|
||||
u_int line = cdata->line;
|
||||
struct mouse_event *m = &cdata->mouse;
|
||||
struct cmdq_item *new_item = NULL;
|
||||
char *cmd;
|
||||
int status;
|
||||
struct cmd_parse_result *pr;
|
||||
|
||||
status = job_get_status(job);
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||
@@ -153,17 +172,20 @@ cmd_if_shell_callback(struct job *job)
|
||||
if (cmd == NULL)
|
||||
goto out;
|
||||
|
||||
cmdlist = cmd_string_parse(cmd, file, line, &cause);
|
||||
if (cmdlist == NULL) {
|
||||
if (cause != NULL && cdata->item != NULL)
|
||||
cmdq_error(cdata->item, "%s", cause);
|
||||
free(cause);
|
||||
new_item = NULL;
|
||||
} else {
|
||||
new_item = cmdq_get_command(cmdlist, NULL, &cdata->mouse, 0);
|
||||
cmd_list_free(cmdlist);
|
||||
pr = cmd_parse_from_string(cmd, &cdata->input);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_EMPTY:
|
||||
break;
|
||||
case CMD_PARSE_ERROR:
|
||||
if (cdata->item != NULL)
|
||||
cmdq_error(cdata->item, "%s", pr->error);
|
||||
free(pr->error);
|
||||
break;
|
||||
case CMD_PARSE_SUCCESS:
|
||||
new_item = cmdq_get_command(pr->cmdlist, NULL, m, 0);
|
||||
cmd_list_free(pr->cmdlist);
|
||||
break;
|
||||
}
|
||||
|
||||
if (new_item != NULL) {
|
||||
if (cdata->item == NULL)
|
||||
cmdq_append(c, new_item);
|
||||
@@ -187,6 +209,9 @@ cmd_if_shell_free(void *data)
|
||||
free(cdata->cmd_else);
|
||||
free(cdata->cmd_if);
|
||||
|
||||
free(cdata->file);
|
||||
if (cdata->input.c != NULL)
|
||||
server_client_unref(cdata->input.c);
|
||||
free((void *)cdata->input.file);
|
||||
|
||||
free(cdata);
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
int size, percentage, dst_idx;
|
||||
enum layout_type type;
|
||||
struct layout_cell *lc;
|
||||
int not_same_window;
|
||||
int not_same_window, flags;
|
||||
|
||||
if (self->entry == &cmd_join_pane_entry)
|
||||
not_same_window = 1;
|
||||
@@ -123,7 +123,11 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
else
|
||||
size = (dst_wp->sx * percentage) / 100;
|
||||
}
|
||||
lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b'), 0);
|
||||
if (args_has(args, 'b'))
|
||||
flags = SPAWN_BEFORE;
|
||||
else
|
||||
flags = 0;
|
||||
lc = layout_split_pane(dst_wp, type, size, flags);
|
||||
if (lc == NULL) {
|
||||
cmdq_error(item, "create pane failed: pane too small");
|
||||
return (CMD_RETURN_ERROR);
|
||||
@@ -144,7 +148,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
server_redraw_window(dst_w);
|
||||
|
||||
if (!args_has(args, 'd')) {
|
||||
window_set_active_pane(dst_w, src_wp);
|
||||
window_set_active_pane(dst_w, src_wp, 1);
|
||||
session_select(dst_s, dst_idx);
|
||||
cmd_find_from_session(current, dst_s, 0);
|
||||
server_redraw_session(dst_s);
|
||||
|
||||
@@ -61,12 +61,12 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) {
|
||||
if (sloop != s) {
|
||||
server_destroy_session(sloop);
|
||||
session_destroy(sloop, __func__);
|
||||
session_destroy(sloop, 1, __func__);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
server_destroy_session(s);
|
||||
session_destroy(s, __func__);
|
||||
session_destroy(s, 1, __func__);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct args *args = self->args;
|
||||
struct key_table *table;
|
||||
struct key_binding *bd;
|
||||
const char *key, *tablename, *r;
|
||||
char *cp, tmp[BUFSIZ];
|
||||
const char *tablename, *r;
|
||||
char *key, *cp, tmp[BUFSIZ];
|
||||
int repeat, width, tablewidth, keywidth;
|
||||
|
||||
if (self->entry == &cmd_list_commands_entry)
|
||||
@@ -83,7 +83,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
bd = key_bindings_first(table);
|
||||
while (bd != NULL) {
|
||||
key = key_string_lookup_key(bd->key);
|
||||
key = args_escape(key_string_lookup_key(bd->key));
|
||||
|
||||
if (bd->flags & KEY_BINDING_REPEAT)
|
||||
repeat = 1;
|
||||
@@ -95,6 +95,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (width > keywidth)
|
||||
keywidth = width;
|
||||
|
||||
free(key);
|
||||
bd = key_bindings_next(table, bd);
|
||||
}
|
||||
table = key_bindings_next_table(table);
|
||||
@@ -108,7 +109,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
bd = key_bindings_first(table);
|
||||
while (bd != NULL) {
|
||||
key = key_string_lookup_key(bd->key);
|
||||
key = args_escape(key_string_lookup_key(bd->key));
|
||||
|
||||
if (!repeat)
|
||||
r = "";
|
||||
@@ -128,11 +129,13 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
strlcat(tmp, " ", sizeof tmp);
|
||||
free(cp);
|
||||
|
||||
cp = cmd_list_print(bd->cmdlist);
|
||||
cp = cmd_list_print(bd->cmdlist, 1);
|
||||
strlcat(tmp, cp, sizeof tmp);
|
||||
free(cp);
|
||||
|
||||
cmdq_print(item, "bind-key %s", tmp);
|
||||
|
||||
free(key);
|
||||
bd = key_bindings_next(table, bd);
|
||||
}
|
||||
table = key_bindings_next_table(table);
|
||||
|
||||
85
cmd-list.c
85
cmd-list.c
@@ -23,62 +23,37 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
static u_int cmd_list_next_group = 1;
|
||||
|
||||
struct cmd_list *
|
||||
cmd_list_parse(int argc, char **argv, const char *file, u_int line,
|
||||
char **cause)
|
||||
cmd_list_new(void)
|
||||
{
|
||||
struct cmd_list *cmdlist;
|
||||
struct cmd *cmd;
|
||||
int i, lastsplit;
|
||||
size_t arglen, new_argc;
|
||||
char **copy_argv, **new_argv;
|
||||
|
||||
copy_argv = cmd_copy_argv(argc, argv);
|
||||
|
||||
cmdlist = xcalloc(1, sizeof *cmdlist);
|
||||
cmdlist->references = 1;
|
||||
cmdlist->group = cmd_list_next_group++;
|
||||
TAILQ_INIT(&cmdlist->list);
|
||||
|
||||
lastsplit = 0;
|
||||
for (i = 0; i < argc; i++) {
|
||||
arglen = strlen(copy_argv[i]);
|
||||
if (arglen == 0 || copy_argv[i][arglen - 1] != ';')
|
||||
continue;
|
||||
copy_argv[i][arglen - 1] = '\0';
|
||||
|
||||
if (arglen > 1 && copy_argv[i][arglen - 2] == '\\') {
|
||||
copy_argv[i][arglen - 2] = ';';
|
||||
continue;
|
||||
}
|
||||
|
||||
new_argc = i - lastsplit;
|
||||
new_argv = copy_argv + lastsplit;
|
||||
if (arglen != 1)
|
||||
new_argc++;
|
||||
|
||||
cmd = cmd_parse(new_argc, new_argv, file, line, cause);
|
||||
if (cmd == NULL)
|
||||
goto bad;
|
||||
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
|
||||
|
||||
lastsplit = i + 1;
|
||||
}
|
||||
|
||||
if (lastsplit != argc) {
|
||||
cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit,
|
||||
file, line, cause);
|
||||
if (cmd == NULL)
|
||||
goto bad;
|
||||
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
|
||||
}
|
||||
|
||||
cmd_free_argv(argc, copy_argv);
|
||||
return (cmdlist);
|
||||
}
|
||||
|
||||
bad:
|
||||
cmd_list_free(cmdlist);
|
||||
cmd_free_argv(argc, copy_argv);
|
||||
return (NULL);
|
||||
void
|
||||
cmd_list_append(struct cmd_list *cmdlist, struct cmd *cmd)
|
||||
{
|
||||
cmd->group = cmdlist->group;
|
||||
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_list_move(struct cmd_list *cmdlist, struct cmd_list *from)
|
||||
{
|
||||
struct cmd *cmd, *cmd1;
|
||||
|
||||
TAILQ_FOREACH_SAFE(cmd, &from->list, qentry, cmd1) {
|
||||
TAILQ_REMOVE(&from->list, cmd, qentry);
|
||||
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
|
||||
}
|
||||
cmdlist->group = cmd_list_next_group++;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -91,16 +66,14 @@ cmd_list_free(struct cmd_list *cmdlist)
|
||||
|
||||
TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) {
|
||||
TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
|
||||
args_free(cmd->args);
|
||||
free(cmd->file);
|
||||
free(cmd);
|
||||
cmd_free(cmd);
|
||||
}
|
||||
|
||||
free(cmdlist);
|
||||
}
|
||||
|
||||
char *
|
||||
cmd_list_print(struct cmd_list *cmdlist)
|
||||
cmd_list_print(struct cmd_list *cmdlist, int escaped)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
char *buf, *this;
|
||||
@@ -112,12 +85,16 @@ cmd_list_print(struct cmd_list *cmdlist)
|
||||
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
|
||||
this = cmd_print(cmd);
|
||||
|
||||
len += strlen(this) + 3;
|
||||
len += strlen(this) + 4;
|
||||
buf = xrealloc(buf, len);
|
||||
|
||||
strlcat(buf, this, len);
|
||||
if (TAILQ_NEXT(cmd, qentry) != NULL)
|
||||
strlcat(buf, " ; ", len);
|
||||
if (TAILQ_NEXT(cmd, qentry) != NULL) {
|
||||
if (escaped)
|
||||
strlcat(buf, " \\; ", len);
|
||||
else
|
||||
strlcat(buf, " ; ", len);
|
||||
}
|
||||
|
||||
free(this);
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_WAIT);
|
||||
}
|
||||
|
||||
file = server_client_get_path(c, path);
|
||||
file = server_client_get_path(item->client, path);
|
||||
free(path);
|
||||
|
||||
f = fopen(file, "rb");
|
||||
|
||||
@@ -69,20 +69,17 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct args *args = self->args;
|
||||
struct client *c = item->client;
|
||||
struct session *s, *as, *groupwith;
|
||||
struct window *w;
|
||||
struct environ *env;
|
||||
struct options *oo;
|
||||
struct termios tio, *tiop;
|
||||
struct session_group *sg;
|
||||
const char *errstr, *template, *group, *prefix;
|
||||
const char *path, *cmd, *tmp, *value;
|
||||
char **argv, *cause, *cp, *newname, *cwd = NULL;
|
||||
int detached, already_attached, idx, argc;
|
||||
int is_control = 0;
|
||||
u_int sx, sy, dsx = 80, dsy = 24;
|
||||
struct environ_entry *envent;
|
||||
struct cmd_find_state fs;
|
||||
const char *errstr, *template, *group, *prefix, *tmp;
|
||||
char *cause, *cwd = NULL, *cp, *newname = NULL;
|
||||
int detached, already_attached, is_control = 0;
|
||||
u_int sx, sy, dsx, dsy;
|
||||
struct spawn_context sc;
|
||||
enum cmd_retval retval;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
if (self->entry == &cmd_has_session_entry) {
|
||||
/*
|
||||
@@ -97,13 +94,12 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
newname = NULL;
|
||||
if (args_has(args, 's')) {
|
||||
newname = format_single(item, args_get(args, 's'), c, NULL,
|
||||
NULL, NULL);
|
||||
if (!session_check_name(newname)) {
|
||||
cmdq_error(item, "bad session name: %s", newname);
|
||||
goto error;
|
||||
goto fail;
|
||||
}
|
||||
if ((as = session_find(newname)) != NULL) {
|
||||
if (args_has(args, 'A')) {
|
||||
@@ -114,7 +110,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (retval);
|
||||
}
|
||||
cmdq_error(item, "duplicate session: %s", newname);
|
||||
goto error;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +121,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (groupwith == NULL) {
|
||||
if (!session_check_name(group)) {
|
||||
cmdq_error(item, "bad group name: %s", group);
|
||||
goto error;
|
||||
goto fail;
|
||||
}
|
||||
sg = session_group_find(group);
|
||||
} else
|
||||
@@ -173,7 +169,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (server_client_check_nested(item->client)) {
|
||||
cmdq_error(item, "sessions should be nested with care, "
|
||||
"unset $TMUX to force");
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
if (tcgetattr(c->tty.fd, &tio) != 0)
|
||||
fatal("tcgetattr failed");
|
||||
@@ -186,7 +182,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (server_client_open(c, &cause) != 0) {
|
||||
cmdq_error(item, "open terminal failed: %s", cause);
|
||||
free(cause);
|
||||
goto error;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,11 +192,13 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (strcmp(tmp, "-") == 0) {
|
||||
if (c != NULL)
|
||||
dsx = c->tty.sx;
|
||||
else
|
||||
dsx = 80;
|
||||
} else {
|
||||
dsx = strtonum(tmp, 1, USHRT_MAX, &errstr);
|
||||
if (errstr != NULL) {
|
||||
cmdq_error(item, "width %s", errstr);
|
||||
goto error;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,11 +207,13 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (strcmp(tmp, "-") == 0) {
|
||||
if (c != NULL)
|
||||
dsy = c->tty.sy;
|
||||
else
|
||||
dsy = 24;
|
||||
} else {
|
||||
dsy = strtonum(tmp, 1, USHRT_MAX, &errstr);
|
||||
if (errstr != NULL) {
|
||||
cmdq_error(item, "height %s", errstr);
|
||||
goto error;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -225,8 +225,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (sy > 0 && options_get_number(global_s_options, "status"))
|
||||
sy--;
|
||||
} else {
|
||||
value = options_get_string(global_s_options, "default-size");
|
||||
if (sscanf(value, "%ux%u", &sx, &sy) != 2) {
|
||||
tmp = options_get_string(global_s_options, "default-size");
|
||||
if (sscanf(tmp, "%ux%u", &sx, &sy) != 2) {
|
||||
sx = 80;
|
||||
sy = 24;
|
||||
}
|
||||
@@ -240,59 +240,39 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (sy == 0)
|
||||
sy = 1;
|
||||
|
||||
/* Figure out the command for the new window. */
|
||||
argc = -1;
|
||||
argv = NULL;
|
||||
if (!args_has(args, 't') && args->argc != 0) {
|
||||
argc = args->argc;
|
||||
argv = args->argv;
|
||||
} else if (sg == NULL && groupwith == NULL) {
|
||||
cmd = options_get_string(global_s_options, "default-command");
|
||||
if (cmd != NULL && *cmd != '\0') {
|
||||
argc = 1;
|
||||
argv = (char **)&cmd;
|
||||
} else {
|
||||
argc = 0;
|
||||
argv = NULL;
|
||||
}
|
||||
/* Create the new session. */
|
||||
oo = options_create(global_s_options);
|
||||
if (args_has(args, 'x') || args_has(args, 'y')) {
|
||||
if (!args_has(args, 'x'))
|
||||
dsx = sx;
|
||||
if (!args_has(args, 'y'))
|
||||
dsy = sy;
|
||||
options_set_string(oo, "default-size", 0, "%ux%u", dsx, dsy);
|
||||
}
|
||||
|
||||
path = NULL;
|
||||
if (c != NULL && c->session == NULL)
|
||||
envent = environ_find(c->environ, "PATH");
|
||||
else
|
||||
envent = environ_find(global_environ, "PATH");
|
||||
if (envent != NULL)
|
||||
path = envent->value;
|
||||
|
||||
/* Construct the environment. */
|
||||
env = environ_create();
|
||||
if (c != NULL && !args_has(args, 'E'))
|
||||
environ_update(global_s_options, c->environ, env);
|
||||
s = session_create(prefix, newname, cwd, env, oo, tiop);
|
||||
|
||||
/* Set up the options. */
|
||||
oo = options_create(global_s_options);
|
||||
if (args_has(args, 'x') || args_has(args, 'y'))
|
||||
options_set_string(oo, "default-size", 0, "%ux%u", dsx, dsy);
|
||||
/* Spawn the initial window. */
|
||||
memset(&sc, 0, sizeof sc);
|
||||
sc.item = item;
|
||||
sc.s = s;
|
||||
|
||||
/* Create the new session. */
|
||||
idx = -1 - options_get_number(global_s_options, "base-index");
|
||||
s = session_create(prefix, newname, argc, argv, path, cwd, env, oo,
|
||||
tiop, idx, &cause);
|
||||
environ_free(env);
|
||||
if (s == NULL) {
|
||||
cmdq_error(item, "create session failed: %s", cause);
|
||||
sc.name = args_get(args, 'n');
|
||||
sc.argc = args->argc;
|
||||
sc.argv = args->argv;
|
||||
|
||||
sc.idx = -1;
|
||||
sc.cwd = args_get(args, 'c');
|
||||
|
||||
sc.flags = 0;
|
||||
|
||||
if (spawn_window(&sc, &cause) == NULL) {
|
||||
session_destroy(s, 0, __func__);
|
||||
cmdq_error(item, "create window failed: %s", cause);
|
||||
free(cause);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Set the initial window name if one given. */
|
||||
if (argc >= 0 && (tmp = args_get(args, 'n')) != NULL) {
|
||||
cp = format_single(item, tmp, c, s, NULL, NULL);
|
||||
w = s->curw->window;
|
||||
window_set_name(w, cp);
|
||||
options_set_number(w->options, "automatic-rename", 0);
|
||||
free(cp);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -358,13 +338,13 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
|
||||
cmd_find_from_session(&fs, s, 0);
|
||||
hooks_insert(s->hooks, item, &fs, "after-new-session");
|
||||
cmdq_insert_hook(s, item, &fs, "after-new-session");
|
||||
|
||||
free(cwd);
|
||||
free(newname);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
error:
|
||||
fail:
|
||||
free(cwd);
|
||||
free(newname);
|
||||
return (CMD_RETURN_ERROR);
|
||||
|
||||
120
cmd-new-window.c
120
cmd-new-window.c
@@ -38,9 +38,9 @@ const struct cmd_entry cmd_new_window_entry = {
|
||||
.name = "new-window",
|
||||
.alias = "neww",
|
||||
|
||||
.args = { "ac:dF:kn:Pt:", 0, -1 },
|
||||
.usage = "[-adkP] [-c start-directory] [-F format] [-n window-name] "
|
||||
CMD_TARGET_WINDOW_USAGE " [command]",
|
||||
.args = { "ac:de:F:kn:Pt:", 0, -1 },
|
||||
.usage = "[-adkP] [-c start-directory] [-e environment] [-F format] "
|
||||
"[-n window-name] " CMD_TARGET_WINDOW_USAGE " [command]",
|
||||
|
||||
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
|
||||
|
||||
@@ -53,87 +53,53 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
struct cmd_find_state *current = &item->shared->current;
|
||||
struct spawn_context sc;
|
||||
struct client *c = cmd_find_client(item, NULL, 1);
|
||||
struct session *s = item->target.s;
|
||||
struct winlink *wl = item->target.wl;
|
||||
struct client *c = cmd_find_client(item, NULL, 1);
|
||||
int idx = item->target.idx;
|
||||
const char *cmd, *path, *template, *tmp;
|
||||
char **argv, *cause, *cp, *cwd, *name;
|
||||
int argc, detached;
|
||||
struct environ_entry *envent;
|
||||
struct winlink *new_wl;
|
||||
char *cause = NULL, *cp;
|
||||
const char *template, *add;
|
||||
struct cmd_find_state fs;
|
||||
struct args_value *value;
|
||||
|
||||
if (args_has(args, 'a') && wl != NULL) {
|
||||
if ((idx = winlink_shuffle_up(s, wl)) == -1) {
|
||||
cmdq_error(item, "no free window indexes");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
detached = args_has(args, 'd');
|
||||
|
||||
if (args->argc == 0) {
|
||||
cmd = options_get_string(s->options, "default-command");
|
||||
if (cmd != NULL && *cmd != '\0') {
|
||||
argc = 1;
|
||||
argv = (char **)&cmd;
|
||||
} else {
|
||||
argc = 0;
|
||||
argv = NULL;
|
||||
}
|
||||
} else {
|
||||
argc = args->argc;
|
||||
argv = args->argv;
|
||||
if (args_has(args, 'a') && (idx = winlink_shuffle_up(s, wl)) == -1) {
|
||||
cmdq_error(item, "couldn't get a window index");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
path = NULL;
|
||||
if (item->client != NULL && item->client->session == NULL)
|
||||
envent = environ_find(item->client->environ, "PATH");
|
||||
else
|
||||
envent = environ_find(s->environ, "PATH");
|
||||
if (envent != NULL)
|
||||
path = envent->value;
|
||||
memset(&sc, 0, sizeof sc);
|
||||
sc.item = item;
|
||||
sc.s = s;
|
||||
|
||||
if ((tmp = args_get(args, 'c')) != NULL)
|
||||
cwd = format_single(item, tmp, c, s, NULL, NULL);
|
||||
else
|
||||
cwd = xstrdup(server_client_get_cwd(item->client, s));
|
||||
sc.name = args_get(args, 'n');
|
||||
sc.argc = args->argc;
|
||||
sc.argv = args->argv;
|
||||
sc.environ = environ_create();
|
||||
|
||||
if ((tmp = args_get(args, 'n')) != NULL)
|
||||
name = format_single(item, tmp, c, s, NULL, NULL);
|
||||
else
|
||||
name = NULL;
|
||||
|
||||
if (idx != -1)
|
||||
wl = winlink_find_by_index(&s->windows, idx);
|
||||
if (wl != NULL && args_has(args, 'k')) {
|
||||
/*
|
||||
* Can't use session_detach as it will destroy session if this
|
||||
* makes it empty.
|
||||
*/
|
||||
notify_session_window("window-unlinked", s, wl->window);
|
||||
wl->flags &= ~WINLINK_ALERTFLAGS;
|
||||
winlink_stack_remove(&s->lastw, wl);
|
||||
winlink_remove(&s->windows, wl);
|
||||
|
||||
/* Force select/redraw if current. */
|
||||
if (wl == s->curw) {
|
||||
detached = 0;
|
||||
s->curw = NULL;
|
||||
}
|
||||
add = args_first_value(args, 'e', &value);
|
||||
while (add != NULL) {
|
||||
environ_put(sc.environ, add);
|
||||
add = args_next_value(&value);
|
||||
}
|
||||
|
||||
if (idx == -1)
|
||||
idx = -1 - options_get_number(s->options, "base-index");
|
||||
wl = session_new(s, name, argc, argv, path, cwd, idx,
|
||||
&cause);
|
||||
if (wl == NULL) {
|
||||
sc.idx = idx;
|
||||
sc.cwd = args_get(args, 'c');
|
||||
|
||||
sc.flags = 0;
|
||||
if (args_has(args, 'd'))
|
||||
sc.flags |= SPAWN_DETACHED;
|
||||
if (args_has(args, 'k'))
|
||||
sc.flags |= SPAWN_KILL;
|
||||
|
||||
if ((new_wl = spawn_window(&sc, &cause)) == NULL) {
|
||||
cmdq_error(item, "create window failed: %s", cause);
|
||||
free(cause);
|
||||
goto error;
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (!detached) {
|
||||
session_select(s, wl->idx);
|
||||
cmd_find_from_winlink(current, wl, 0);
|
||||
if (!args_has(args, 'd') || new_wl == s->curw) {
|
||||
cmd_find_from_winlink(current, new_wl, 0);
|
||||
server_redraw_session_group(s);
|
||||
} else
|
||||
server_status_session_group(s);
|
||||
@@ -141,20 +107,14 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'P')) {
|
||||
if ((template = args_get(args, 'F')) == NULL)
|
||||
template = NEW_WINDOW_TEMPLATE;
|
||||
cp = format_single(item, template, c, s, wl, NULL);
|
||||
cp = format_single(item, template, c, s, new_wl, NULL);
|
||||
cmdq_print(item, "%s", cp);
|
||||
free(cp);
|
||||
}
|
||||
|
||||
cmd_find_from_winlink(&fs, wl, 0);
|
||||
hooks_insert(s->hooks, item, &fs, "after-new-window");
|
||||
cmd_find_from_winlink(&fs, new_wl, 0);
|
||||
cmdq_insert_hook(s, item, &fs, "after-new-window");
|
||||
|
||||
free(name);
|
||||
free(cwd);
|
||||
environ_free(sc.environ);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
error:
|
||||
free(name);
|
||||
free(cwd);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
1471
cmd-parse.y
Normal file
1471
cmd-parse.y
Normal file
File diff suppressed because it is too large
Load Diff
156
cmd-queue.c
156
cmd-queue.c
@@ -32,11 +32,14 @@ static struct cmdq_list global_queue = TAILQ_HEAD_INITIALIZER(global_queue);
|
||||
static const char *
|
||||
cmdq_name(struct client *c)
|
||||
{
|
||||
static char s[32];
|
||||
static char s[256];
|
||||
|
||||
if (c == NULL)
|
||||
return ("<global>");
|
||||
xsnprintf(s, sizeof s, "<%p>", c);
|
||||
if (c->name != NULL)
|
||||
xsnprintf(s, sizeof s, "<%s>", c->name);
|
||||
else
|
||||
xsnprintf(s, sizeof s, "<%p>", c);
|
||||
return (s);
|
||||
}
|
||||
|
||||
@@ -66,6 +69,7 @@ cmdq_append(struct client *c, struct cmdq_item *item)
|
||||
|
||||
item->queue = queue;
|
||||
TAILQ_INSERT_TAIL(queue, item, entry);
|
||||
log_debug("%s %s: %s", __func__, cmdq_name(c), item->name);
|
||||
|
||||
item = next;
|
||||
} while (item != NULL);
|
||||
@@ -81,23 +85,77 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
|
||||
|
||||
do {
|
||||
next = item->next;
|
||||
item->next = NULL;
|
||||
item->next = after->next;
|
||||
after->next = item;
|
||||
|
||||
if (c != NULL)
|
||||
c->references++;
|
||||
item->client = c;
|
||||
|
||||
item->queue = queue;
|
||||
if (after->next != NULL)
|
||||
TAILQ_INSERT_AFTER(queue, after->next, item, entry);
|
||||
else
|
||||
TAILQ_INSERT_AFTER(queue, after, item, entry);
|
||||
after->next = item;
|
||||
TAILQ_INSERT_AFTER(queue, after, item, entry);
|
||||
log_debug("%s %s: %s after %s", __func__, cmdq_name(c),
|
||||
item->name, after->name);
|
||||
|
||||
after = item;
|
||||
item = next;
|
||||
} while (item != NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Insert a hook. */
|
||||
void
|
||||
cmdq_insert_hook(struct session *s, struct cmdq_item *item,
|
||||
struct cmd_find_state *fs, const char *fmt, ...)
|
||||
{
|
||||
struct options *oo;
|
||||
va_list ap;
|
||||
char *name;
|
||||
struct cmdq_item *new_item;
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
struct cmd_list *cmdlist;
|
||||
|
||||
if (item->flags & CMDQ_NOHOOKS)
|
||||
return;
|
||||
if (s == NULL)
|
||||
oo = global_s_options;
|
||||
else
|
||||
oo = s->options;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&name, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
o = options_get(oo, name);
|
||||
if (o == NULL) {
|
||||
free(name);
|
||||
return;
|
||||
}
|
||||
log_debug("running hook %s (parent %p)", name, item);
|
||||
|
||||
a = options_array_first(o);
|
||||
while (a != NULL) {
|
||||
cmdlist = options_array_item_value(a)->cmdlist;
|
||||
if (cmdlist == NULL) {
|
||||
a = options_array_next(a);
|
||||
continue;
|
||||
}
|
||||
|
||||
new_item = cmdq_get_command(cmdlist, fs, NULL, CMDQ_NOHOOKS);
|
||||
cmdq_format(new_item, "hook", "%s", name);
|
||||
if (item != NULL) {
|
||||
cmdq_insert_after(item, new_item);
|
||||
item = new_item;
|
||||
} else
|
||||
cmdq_append(NULL, new_item);
|
||||
|
||||
a = options_array_next(a);
|
||||
}
|
||||
|
||||
free(name);
|
||||
}
|
||||
|
||||
/* Remove an item. */
|
||||
static void
|
||||
cmdq_remove(struct cmdq_item *item)
|
||||
@@ -111,30 +169,23 @@ cmdq_remove(struct cmdq_item *item)
|
||||
if (item->client != NULL)
|
||||
server_client_unref(item->client);
|
||||
|
||||
if (item->type == CMDQ_COMMAND)
|
||||
if (item->cmdlist != NULL)
|
||||
cmd_list_free(item->cmdlist);
|
||||
|
||||
TAILQ_REMOVE(item->queue, item, entry);
|
||||
|
||||
free((void *)item->name);
|
||||
free(item->name);
|
||||
free(item);
|
||||
}
|
||||
|
||||
/* Set command group. */
|
||||
static u_int
|
||||
cmdq_next_group(void)
|
||||
{
|
||||
static u_int group;
|
||||
|
||||
return (++group);
|
||||
}
|
||||
|
||||
/* Remove all subsequent items that match this item's group. */
|
||||
static void
|
||||
cmdq_remove_group(struct cmdq_item *item)
|
||||
{
|
||||
struct cmdq_item *this, *next;
|
||||
|
||||
if (item->group == 0)
|
||||
return;
|
||||
this = TAILQ_NEXT(item, entry);
|
||||
while (this != NULL) {
|
||||
next = TAILQ_NEXT(this, entry);
|
||||
@@ -151,32 +202,34 @@ cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
|
||||
{
|
||||
struct cmdq_item *item, *first = NULL, *last = NULL;
|
||||
struct cmd *cmd;
|
||||
u_int group = cmdq_next_group();
|
||||
char *tmp;
|
||||
struct cmdq_shared *shared;
|
||||
|
||||
shared = xcalloc(1, sizeof *shared);
|
||||
if (current != NULL)
|
||||
cmd_find_copy_state(&shared->current, current);
|
||||
else
|
||||
cmd_find_clear_state(&shared->current, 0);
|
||||
if (m != NULL)
|
||||
memcpy(&shared->mouse, m, sizeof shared->mouse);
|
||||
struct cmdq_shared *shared = NULL;
|
||||
u_int group = 0;
|
||||
|
||||
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
|
||||
xasprintf(&tmp, "command[%s]", cmd->entry->name);
|
||||
if (cmd->group != group) {
|
||||
shared = xcalloc(1, sizeof *shared);
|
||||
if (current != NULL)
|
||||
cmd_find_copy_state(&shared->current, current);
|
||||
else
|
||||
cmd_find_clear_state(&shared->current, 0);
|
||||
if (m != NULL)
|
||||
memcpy(&shared->mouse, m, sizeof shared->mouse);
|
||||
group = cmd->group;
|
||||
}
|
||||
|
||||
item = xcalloc(1, sizeof *item);
|
||||
item->name = tmp;
|
||||
xasprintf(&item->name, "[%s/%p]", cmd->entry->name, item);
|
||||
item->type = CMDQ_COMMAND;
|
||||
|
||||
item->group = group;
|
||||
item->group = cmd->group;
|
||||
item->flags = flags;
|
||||
|
||||
item->shared = shared;
|
||||
item->cmdlist = cmdlist;
|
||||
item->cmd = cmd;
|
||||
|
||||
log_debug("%s: %s group %u", __func__, item->name, item->group);
|
||||
|
||||
shared->references++;
|
||||
cmdlist->references++;
|
||||
|
||||
@@ -214,13 +267,22 @@ static enum cmd_retval
|
||||
cmdq_fire_command(struct cmdq_item *item)
|
||||
{
|
||||
struct client *c = item->client;
|
||||
const char *name = cmdq_name(c);
|
||||
struct cmdq_shared *shared = item->shared;
|
||||
struct cmd *cmd = item->cmd;
|
||||
const struct cmd_entry *entry = cmd->entry;
|
||||
enum cmd_retval retval;
|
||||
struct cmd_find_state *fsp, fs;
|
||||
int flags;
|
||||
char *tmp;
|
||||
|
||||
flags = !!(cmd->flags & CMD_CONTROL);
|
||||
if (log_get_level() > 1) {
|
||||
tmp = cmd_print(cmd);
|
||||
log_debug("%s %s: (%u) %s", __func__, name, item->group, tmp);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
flags = !!(shared->flags & CMDQ_SHARED_CONTROL);
|
||||
cmdq_guard(item, "begin", flags);
|
||||
|
||||
if (item->client == NULL)
|
||||
@@ -245,7 +307,7 @@ cmdq_fire_command(struct cmdq_item *item)
|
||||
fsp = &fs;
|
||||
else
|
||||
goto out;
|
||||
hooks_insert(fsp->s->hooks, item, fsp, "after-%s", entry->name);
|
||||
cmdq_insert_hook(fsp->s, item, fsp, "after-%s", entry->name);
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -262,12 +324,9 @@ struct cmdq_item *
|
||||
cmdq_get_callback1(const char *name, cmdq_cb cb, void *data)
|
||||
{
|
||||
struct cmdq_item *item;
|
||||
char *tmp;
|
||||
|
||||
xasprintf(&tmp, "callback[%s]", name);
|
||||
|
||||
item = xcalloc(1, sizeof *item);
|
||||
item->name = tmp;
|
||||
xasprintf(&item->name, "[%s/%p]", name, item);
|
||||
item->type = CMDQ_CALLBACK;
|
||||
|
||||
item->group = 0;
|
||||
@@ -279,6 +338,25 @@ cmdq_get_callback1(const char *name, cmdq_cb cb, void *data)
|
||||
return (item);
|
||||
}
|
||||
|
||||
/* Generic error callback. */
|
||||
static enum cmd_retval
|
||||
cmdq_error_callback(struct cmdq_item *item, void *data)
|
||||
{
|
||||
char *error = data;
|
||||
|
||||
cmdq_error(item, "%s", error);
|
||||
free(error);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
/* Get an error callback for the command queue. */
|
||||
struct cmdq_item *
|
||||
cmdq_get_error(const char *error)
|
||||
{
|
||||
return (cmdq_get_callback(cmdq_error_callback, xstrdup(error)));
|
||||
}
|
||||
|
||||
/* Fire callback on callback queue. */
|
||||
static enum cmd_retval
|
||||
cmdq_fire_callback(struct cmdq_item *item)
|
||||
|
||||
@@ -143,12 +143,12 @@ cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m)
|
||||
}
|
||||
w = wl->window;
|
||||
|
||||
y = m->y; x = m->x;
|
||||
y = m->y + m->oy; x = m->x + m->ox;
|
||||
if (m->statusat == 0 && y > 0)
|
||||
y--;
|
||||
else if (m->statusat > 0 && y >= (u_int)m->statusat)
|
||||
y = m->statusat - 1;
|
||||
ly = m->ly; lx = m->lx;
|
||||
ly = m->ly + m->oy; lx = m->lx + m->ox;
|
||||
if (m->statusat == 0 && ly > 0)
|
||||
ly--;
|
||||
else if (m->statusat > 0 && ly >= (u_int)m->statusat)
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
@@ -34,9 +34,9 @@ const struct cmd_entry cmd_respawn_pane_entry = {
|
||||
.name = "respawn-pane",
|
||||
.alias = "respawnp",
|
||||
|
||||
.args = { "c:kt:", 0, -1 },
|
||||
.usage = "[-c start-directory] [-k] " CMD_TARGET_PANE_USAGE
|
||||
" [command]",
|
||||
.args = { "c:e:kt:", 0, -1 },
|
||||
.usage = "[-k] [-c start-directory] [-e environment] "
|
||||
CMD_TARGET_PANE_USAGE " [command]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
@@ -48,53 +48,49 @@ static enum cmd_retval
|
||||
cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
struct winlink *wl = item->target.wl;
|
||||
struct window *w = wl->window;
|
||||
struct window_pane *wp = item->target.wp;
|
||||
struct client *c = cmd_find_client(item, NULL, 1);
|
||||
struct spawn_context sc;
|
||||
struct session *s = item->target.s;
|
||||
struct environ *env;
|
||||
const char *path = NULL, *cp;
|
||||
char *cause, *cwd = NULL;
|
||||
u_int idx;
|
||||
struct environ_entry *envent;
|
||||
struct winlink *wl = item->target.wl;
|
||||
struct window_pane *wp = item->target.wp;
|
||||
char *cause = NULL;
|
||||
const char *add;
|
||||
struct args_value *value;
|
||||
|
||||
if (!args_has(self->args, 'k') && wp->fd != -1) {
|
||||
if (window_pane_index(wp, &idx) != 0)
|
||||
fatalx("index not found");
|
||||
cmdq_error(item, "pane still active: %s:%d.%u",
|
||||
s->name, wl->idx, idx);
|
||||
return (CMD_RETURN_ERROR);
|
||||
memset(&sc, 0, sizeof sc);
|
||||
sc.item = item;
|
||||
sc.s = s;
|
||||
sc.wl = wl;
|
||||
|
||||
sc.wp0 = wp;
|
||||
sc.lc = NULL;
|
||||
|
||||
sc.name = NULL;
|
||||
sc.argc = args->argc;
|
||||
sc.argv = args->argv;
|
||||
sc.environ = environ_create();
|
||||
|
||||
add = args_first_value(args, 'e', &value);
|
||||
while (add != NULL) {
|
||||
environ_put(sc.environ, add);
|
||||
add = args_next_value(&value);
|
||||
}
|
||||
|
||||
window_pane_reset_mode_all(wp);
|
||||
screen_reinit(&wp->base);
|
||||
input_init(wp);
|
||||
sc.idx = -1;
|
||||
sc.cwd = args_get(args, 'c');
|
||||
|
||||
if (item->client != NULL && item->client->session == NULL)
|
||||
envent = environ_find(item->client->environ, "PATH");
|
||||
else
|
||||
envent = environ_find(s->environ, "PATH");
|
||||
if (envent != NULL)
|
||||
path = envent->value;
|
||||
sc.flags = SPAWN_RESPAWN;
|
||||
if (args_has(args, 'k'))
|
||||
sc.flags |= SPAWN_KILL;
|
||||
|
||||
if ((cp = args_get(args, 'c')) != NULL)
|
||||
cwd = format_single(item, cp, c, s, NULL, NULL);
|
||||
|
||||
env = environ_for_session(s, 0);
|
||||
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, cwd, env,
|
||||
s->tio, &cause) != 0) {
|
||||
if (spawn_pane(&sc, &cause) == NULL) {
|
||||
cmdq_error(item, "respawn pane failed: %s", cause);
|
||||
free(cause);
|
||||
environ_free(env);
|
||||
free(cwd);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
environ_free(env);
|
||||
free(cwd);
|
||||
|
||||
wp->flags |= PANE_REDRAW;
|
||||
server_status_window(w);
|
||||
server_status_window(wp->window);
|
||||
|
||||
environ_free(sc.environ);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
@@ -34,9 +34,9 @@ const struct cmd_entry cmd_respawn_window_entry = {
|
||||
.name = "respawn-window",
|
||||
.alias = "respawnw",
|
||||
|
||||
.args = { "c:kt:", 0, -1 },
|
||||
.usage = "[-c start-directory] [-k] " CMD_TARGET_WINDOW_USAGE
|
||||
" [command]",
|
||||
.args = { "c:e:kt:", 0, -1 },
|
||||
.usage = "[-k] [-c start-directory] [-e environment] "
|
||||
CMD_TARGET_WINDOW_USAGE " [command]",
|
||||
|
||||
.target = { 't', CMD_FIND_WINDOW, 0 },
|
||||
|
||||
@@ -48,64 +48,44 @@ static enum cmd_retval
|
||||
cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
struct spawn_context sc;
|
||||
struct session *s = item->target.s;
|
||||
struct winlink *wl = item->target.wl;
|
||||
struct window *w = wl->window;
|
||||
struct window_pane *wp;
|
||||
struct client *c = cmd_find_client(item, NULL, 1);
|
||||
struct environ *env;
|
||||
const char *path = NULL, *cp;
|
||||
char *cause, *cwd = NULL;
|
||||
struct environ_entry *envent;
|
||||
char *cause = NULL;
|
||||
const char *add;
|
||||
struct args_value *value;
|
||||
|
||||
if (!args_has(self->args, 'k')) {
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (wp->fd == -1)
|
||||
continue;
|
||||
cmdq_error(item, "window still active: %s:%d", s->name,
|
||||
wl->idx);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
memset(&sc, 0, sizeof sc);
|
||||
sc.item = item;
|
||||
sc.s = s;
|
||||
sc.wl = wl;
|
||||
|
||||
sc.name = NULL;
|
||||
sc.argc = args->argc;
|
||||
sc.argv = args->argv;
|
||||
sc.environ = environ_create();
|
||||
|
||||
add = args_first_value(args, 'e', &value);
|
||||
while (add != NULL) {
|
||||
environ_put(sc.environ, add);
|
||||
add = args_next_value(&value);
|
||||
}
|
||||
|
||||
wp = TAILQ_FIRST(&w->panes);
|
||||
TAILQ_REMOVE(&w->panes, wp, entry);
|
||||
layout_free(w);
|
||||
window_destroy_panes(w);
|
||||
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
|
||||
window_pane_resize(wp, w->sx, w->sy);
|
||||
sc.idx = -1;
|
||||
sc.cwd = args_get(args, 'c');
|
||||
|
||||
if (item->client != NULL && item->client->session == NULL)
|
||||
envent = environ_find(item->client->environ, "PATH");
|
||||
else
|
||||
envent = environ_find(s->environ, "PATH");
|
||||
if (envent != NULL)
|
||||
path = envent->value;
|
||||
sc.flags = SPAWN_RESPAWN;
|
||||
if (args_has(args, 'k'))
|
||||
sc.flags |= SPAWN_KILL;
|
||||
|
||||
if ((cp = args_get(args, 'c')) != NULL)
|
||||
cwd = format_single(item, cp, c, s, NULL, NULL);
|
||||
|
||||
env = environ_for_session(s, 0);
|
||||
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, cwd, env,
|
||||
s->tio, &cause) != 0) {
|
||||
if (spawn_window(&sc, &cause) == NULL) {
|
||||
cmdq_error(item, "respawn window failed: %s", cause);
|
||||
free(cause);
|
||||
environ_free(env);
|
||||
free(cwd);
|
||||
server_destroy_pane(wp, 0);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
environ_free(env);
|
||||
free(cwd);
|
||||
|
||||
layout_init(w, wp);
|
||||
window_pane_reset_mode_all(wp);
|
||||
screen_reinit(&wp->base);
|
||||
input_init(wp);
|
||||
window_set_active_pane(w, wp);
|
||||
|
||||
recalculate_sizes();
|
||||
server_redraw_window(w);
|
||||
server_redraw_window(wl->window);
|
||||
|
||||
environ_free(sc.environ);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL)
|
||||
wp = TAILQ_LAST(&w->panes, window_panes);
|
||||
window_set_active_pane(w, wp);
|
||||
window_set_active_pane(w, wp, 1);
|
||||
cmd_find_from_winlink_pane(current, wl, wp, 0);
|
||||
server_redraw_window(w);
|
||||
} else {
|
||||
@@ -105,7 +105,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
if ((wp = TAILQ_NEXT(w->active, entry)) == NULL)
|
||||
wp = TAILQ_FIRST(&w->panes);
|
||||
window_set_active_pane(w, wp);
|
||||
window_set_active_pane(w, wp, 1);
|
||||
cmd_find_from_winlink_pane(current, wl, wp, 0);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(self->args, 'a'))
|
||||
flags = "ab";
|
||||
|
||||
file = server_client_get_path(c, path);
|
||||
file = server_client_get_path(item->client, path);
|
||||
free(path);
|
||||
|
||||
f = fopen(file, flags);
|
||||
|
||||
@@ -112,7 +112,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
else {
|
||||
server_unzoom_window(w);
|
||||
window_redraw_active_switch(w, lastwp);
|
||||
if (window_set_active_pane(w, lastwp)) {
|
||||
if (window_set_active_pane(w, lastwp, 1)) {
|
||||
cmd_find_from_winlink(current, wl, 0);
|
||||
cmd_select_pane_redraw(w);
|
||||
}
|
||||
@@ -194,9 +194,9 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
server_unzoom_window(wp->window);
|
||||
window_redraw_active_switch(w, wp);
|
||||
if (window_set_active_pane(w, wp)) {
|
||||
if (window_set_active_pane(w, wp, 1)) {
|
||||
cmd_find_from_winlink_pane(current, wl, wp, 0);
|
||||
hooks_insert(s->hooks, item, current, "after-select-pane");
|
||||
cmdq_insert_hook(s, item, current, "after-select-pane");
|
||||
cmd_select_pane_redraw(w);
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
cmd_find_from_session(current, s, 0);
|
||||
server_redraw_session(s);
|
||||
hooks_insert(s->hooks, item, current, "after-select-window");
|
||||
cmdq_insert_hook(s, item, current, "after-select-window");
|
||||
} else {
|
||||
/*
|
||||
* If -T and select-window is invoked on same window as
|
||||
@@ -137,7 +137,7 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cmd_find_from_session(current, s, 0);
|
||||
server_redraw_session(s);
|
||||
}
|
||||
hooks_insert(s->hooks, item, current, "after-select-window");
|
||||
cmdq_insert_hook(s, item, current, "after-select-window");
|
||||
}
|
||||
recalculate_sizes();
|
||||
|
||||
|
||||
@@ -55,31 +55,30 @@ const struct cmd_entry cmd_send_prefix_entry = {
|
||||
.exec = cmd_send_keys_exec
|
||||
};
|
||||
|
||||
static void
|
||||
cmd_send_keys_inject(struct client *c, struct cmdq_item *item, key_code key)
|
||||
static struct cmdq_item *
|
||||
cmd_send_keys_inject(struct client *c, struct cmd_find_state *fs,
|
||||
struct cmdq_item *item, key_code key)
|
||||
{
|
||||
struct window_pane *wp = item->target.wp;
|
||||
struct session *s = item->target.s;
|
||||
struct winlink *wl = item->target.wl;
|
||||
struct window_mode_entry *wme;
|
||||
struct key_table *table;
|
||||
struct key_binding *bd;
|
||||
|
||||
wme = TAILQ_FIRST(&wp->modes);
|
||||
wme = TAILQ_FIRST(&fs->wp->modes);
|
||||
if (wme == NULL || wme->mode->key_table == NULL) {
|
||||
if (options_get_number(wp->window->options, "xterm-keys"))
|
||||
if (options_get_number(fs->wp->window->options, "xterm-keys"))
|
||||
key |= KEYC_XTERM;
|
||||
window_pane_key(wp, NULL, s, wl, key, NULL);
|
||||
return;
|
||||
window_pane_key(fs->wp, item->client, fs->s, fs->wl, key, NULL);
|
||||
return (item);
|
||||
}
|
||||
table = key_bindings_get_table(wme->mode->key_table(wme), 1);
|
||||
|
||||
bd = key_bindings_get(table, key & ~KEYC_XTERM);
|
||||
if (bd != NULL) {
|
||||
table->references++;
|
||||
key_bindings_dispatch(bd, item, c, NULL, &item->target);
|
||||
item = key_bindings_dispatch(bd, item, c, NULL, &item->target);
|
||||
key_bindings_unref_table(table);
|
||||
}
|
||||
return (item);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
@@ -91,6 +90,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct session *s = item->target.s;
|
||||
struct winlink *wl = item->target.wl;
|
||||
struct mouse_event *m = &item->shared->mouse;
|
||||
struct cmd_find_state *fs = &item->target;
|
||||
struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
|
||||
struct utf8_data *ud, *uc;
|
||||
wchar_t wc;
|
||||
@@ -132,7 +132,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cmdq_error(item, "no mouse target");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
window_pane_key(wp, NULL, s, wl, m->key, m);
|
||||
window_pane_key(wp, item->client, s, wl, m->key, m);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
key = options_get_number(s->options, "prefix2");
|
||||
else
|
||||
key = options_get_number(s->options, "prefix");
|
||||
cmd_send_keys_inject(c, item, key);
|
||||
cmd_send_keys_inject(c, fs, item, key);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -155,9 +155,10 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
literal = args_has(args, 'l');
|
||||
if (!literal) {
|
||||
key = key_string_lookup_string(args->argv[i]);
|
||||
if (key != KEYC_NONE && key != KEYC_UNKNOWN)
|
||||
cmd_send_keys_inject(c, item, key);
|
||||
else
|
||||
if (key != KEYC_NONE && key != KEYC_UNKNOWN) {
|
||||
item = cmd_send_keys_inject(c, fs, item,
|
||||
key);
|
||||
} else
|
||||
literal = 1;
|
||||
}
|
||||
if (literal) {
|
||||
@@ -165,7 +166,8 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
for (uc = ud; uc->size != 0; uc++) {
|
||||
if (utf8_combine(uc, &wc) != UTF8_DONE)
|
||||
continue;
|
||||
cmd_send_keys_inject(c, item, wc);
|
||||
item = cmd_send_keys_inject(c, fs, item,
|
||||
wc);
|
||||
}
|
||||
free(ud);
|
||||
}
|
||||
|
||||
133
cmd-set-hook.c
133
cmd-set-hook.c
@@ -1,133 +0,0 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* Set or show global or session hooks.
|
||||
*/
|
||||
|
||||
static enum cmd_retval cmd_set_hook_exec(struct cmd *, struct cmdq_item *);
|
||||
|
||||
const struct cmd_entry cmd_set_hook_entry = {
|
||||
.name = "set-hook",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "gRt:u", 1, 2 },
|
||||
.usage = "[-gRu] " CMD_TARGET_SESSION_USAGE " hook-name [command]",
|
||||
|
||||
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.exec = cmd_set_hook_exec
|
||||
};
|
||||
|
||||
const struct cmd_entry cmd_show_hooks_entry = {
|
||||
.name = "show-hooks",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "gt:", 0, 1 },
|
||||
.usage = "[-g] " CMD_TARGET_SESSION_USAGE,
|
||||
|
||||
.target = { 't', CMD_FIND_SESSION, 0 },
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.exec = cmd_set_hook_exec
|
||||
};
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_set_hook_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
struct cmd_list *cmdlist;
|
||||
struct hooks *hooks;
|
||||
struct hook *hook;
|
||||
char *cause, *tmp;
|
||||
const char *name, *cmd, *target;
|
||||
|
||||
if (args_has(args, 'g'))
|
||||
hooks = global_hooks;
|
||||
else {
|
||||
if (item->target.s == NULL) {
|
||||
target = args_get(args, 't');
|
||||
if (target != NULL)
|
||||
cmdq_error(item, "no such session: %s", target);
|
||||
else
|
||||
cmdq_error(item, "no current session");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
hooks = item->target.s->hooks;
|
||||
}
|
||||
|
||||
if (self->entry == &cmd_show_hooks_entry) {
|
||||
hook = hooks_first(hooks);
|
||||
while (hook != NULL) {
|
||||
tmp = cmd_list_print(hook->cmdlist);
|
||||
cmdq_print(item, "%s -> %s", hook->name, tmp);
|
||||
free(tmp);
|
||||
|
||||
hook = hooks_next(hook);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
name = args->argv[0];
|
||||
if (*name == '\0') {
|
||||
cmdq_error(item, "invalid hook name");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (args->argc < 2)
|
||||
cmd = NULL;
|
||||
else
|
||||
cmd = args->argv[1];
|
||||
|
||||
if (cmd != NULL && (args_has(args, 'R') || args_has(args, 'u'))) {
|
||||
cmdq_error(item, "no command allowed");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (args_has(args, 'R')) {
|
||||
notify_hook(item, name);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
if (args_has(args, 'u')) {
|
||||
hooks_remove(hooks, name);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (cmd == NULL) {
|
||||
cmdq_error(item, "no command given");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);
|
||||
if (cmdlist == NULL) {
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
}
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
hooks_add(hooks, name, cmdlist);
|
||||
cmd_list_free(cmdlist);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
@@ -65,6 +65,19 @@ const struct cmd_entry cmd_set_window_option_entry = {
|
||||
.exec = cmd_set_option_exec
|
||||
};
|
||||
|
||||
const struct cmd_entry cmd_set_hook_entry = {
|
||||
.name = "set-hook",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "agRt:u", 1, 2 },
|
||||
.usage = "[-agRu] " CMD_TARGET_SESSION_USAGE " hook [command]",
|
||||
|
||||
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.exec = cmd_set_option_exec
|
||||
};
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
@@ -87,6 +100,11 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
c = cmd_find_client(item, NULL, 1);
|
||||
argument = format_single(item, args->argv[0], c, s, wl, NULL);
|
||||
|
||||
if (self->entry == &cmd_set_hook_entry && args_has(args, 'R')) {
|
||||
notify_hook(item, argument);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
/* Parse option name and index. */
|
||||
name = options_match(argument, &idx, &ambiguous);
|
||||
if (name == NULL) {
|
||||
@@ -200,8 +218,11 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
options_default(oo, options_table_entry(o));
|
||||
else
|
||||
options_remove(o);
|
||||
} else
|
||||
options_array_set(o, idx, NULL, 0);
|
||||
} else if (options_array_set(o, idx, NULL, 0, &cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
goto fail;
|
||||
}
|
||||
} else if (*name == '@') {
|
||||
if (value == NULL) {
|
||||
cmdq_error(item, "empty value");
|
||||
@@ -222,9 +243,15 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (idx == -1) {
|
||||
if (!append)
|
||||
options_array_clear(o);
|
||||
options_array_assign(o, value);
|
||||
} else if (options_array_set(o, idx, value, append) != 0) {
|
||||
cmdq_error(item, "invalid index: %s", argument);
|
||||
if (options_array_assign(o, value, &cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
goto fail;
|
||||
}
|
||||
} else if (options_array_set(o, idx, value, append,
|
||||
&cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@@ -366,7 +393,7 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
case OPTIONS_TABLE_ARRAY:
|
||||
case OPTIONS_TABLE_COMMAND:
|
||||
break;
|
||||
}
|
||||
return (-1);
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
|
||||
static enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmdq_item *);
|
||||
|
||||
static enum cmd_retval cmd_show_options_one(struct cmd *, struct cmdq_item *,
|
||||
struct options *);
|
||||
static void cmd_show_options_print(struct cmd *, struct cmdq_item *,
|
||||
struct options_entry *, int);
|
||||
static enum cmd_retval cmd_show_options_all(struct cmd *, struct cmdq_item *,
|
||||
struct options *);
|
||||
|
||||
@@ -38,8 +38,8 @@ const struct cmd_entry cmd_show_options_entry = {
|
||||
.name = "show-options",
|
||||
.alias = "show",
|
||||
|
||||
.args = { "gqst:vw", 0, 1 },
|
||||
.usage = "[-gqsvw] [-t target-session|target-window] [option]",
|
||||
.args = { "gHqst:vw", 0, 1 },
|
||||
.usage = "[-gHqsvw] [-t target-session|target-window] [option]",
|
||||
|
||||
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
|
||||
|
||||
@@ -60,28 +60,120 @@ const struct cmd_entry cmd_show_window_options_entry = {
|
||||
.exec = cmd_show_options_exec
|
||||
};
|
||||
|
||||
const struct cmd_entry cmd_show_hooks_entry = {
|
||||
.name = "show-hooks",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "gt:", 0, 1 },
|
||||
.usage = "[-g] " CMD_TARGET_SESSION_USAGE,
|
||||
|
||||
.target = { 't', CMD_FIND_SESSION, 0 },
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.exec = cmd_show_options_exec
|
||||
};
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
struct cmd_find_state *fs = &item->target;
|
||||
struct client *c = cmd_find_client(item, NULL, 1);
|
||||
struct session *s = item->target.s;
|
||||
struct winlink *wl = item->target.wl;
|
||||
struct options *oo;
|
||||
enum options_table_scope scope;
|
||||
char *cause;
|
||||
int window;
|
||||
char *argument, *name = NULL, *cause;
|
||||
const char *target;
|
||||
int window, idx, ambiguous;
|
||||
struct options_entry *o;
|
||||
|
||||
window = (self->entry == &cmd_show_window_options_entry);
|
||||
scope = options_scope_from_flags(args, window, fs, &oo, &cause);
|
||||
if (args->argc == 0) {
|
||||
scope = options_scope_from_flags(args, window, fs, &oo, &cause);
|
||||
if (scope == OPTIONS_TABLE_NONE) {
|
||||
if (args_has(args, 'q'))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
return (cmd_show_options_all(self, item, oo));
|
||||
}
|
||||
argument = format_single(item, args->argv[0], c, s, wl, NULL);
|
||||
|
||||
name = options_match(argument, &idx, &ambiguous);
|
||||
if (name == NULL) {
|
||||
if (args_has(args, 'q'))
|
||||
goto fail;
|
||||
if (ambiguous)
|
||||
cmdq_error(item, "ambiguous option: %s", argument);
|
||||
else
|
||||
cmdq_error(item, "invalid option: %s", argument);
|
||||
goto fail;
|
||||
}
|
||||
if (*name == '@')
|
||||
scope = options_scope_from_flags(args, window, fs, &oo, &cause);
|
||||
else {
|
||||
if (options_get_only(global_options, name) != NULL)
|
||||
scope = OPTIONS_TABLE_SERVER;
|
||||
else if (options_get_only(global_s_options, name) != NULL)
|
||||
scope = OPTIONS_TABLE_SESSION;
|
||||
else if (options_get_only(global_w_options, name) != NULL)
|
||||
scope = OPTIONS_TABLE_WINDOW;
|
||||
else {
|
||||
scope = OPTIONS_TABLE_NONE;
|
||||
xasprintf(&cause, "unknown option: %s", argument);
|
||||
}
|
||||
if (scope == OPTIONS_TABLE_SERVER)
|
||||
oo = global_options;
|
||||
else if (scope == OPTIONS_TABLE_SESSION) {
|
||||
if (args_has(self->args, 'g'))
|
||||
oo = global_s_options;
|
||||
else if (s == NULL) {
|
||||
target = args_get(args, 't');
|
||||
if (target != NULL) {
|
||||
cmdq_error(item, "no such session: %s",
|
||||
target);
|
||||
} else
|
||||
cmdq_error(item, "no current session");
|
||||
goto fail;
|
||||
} else
|
||||
oo = s->options;
|
||||
} else if (scope == OPTIONS_TABLE_WINDOW) {
|
||||
if (args_has(self->args, 'g'))
|
||||
oo = global_w_options;
|
||||
else if (wl == NULL) {
|
||||
target = args_get(args, 't');
|
||||
if (target != NULL) {
|
||||
cmdq_error(item, "no such window: %s",
|
||||
target);
|
||||
} else
|
||||
cmdq_error(item, "no current window");
|
||||
goto fail;
|
||||
} else
|
||||
oo = wl->window->options;
|
||||
}
|
||||
}
|
||||
if (scope == OPTIONS_TABLE_NONE) {
|
||||
if (args_has(args, 'q'))
|
||||
goto fail;
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
o = options_get_only(oo, name);
|
||||
if (o != NULL)
|
||||
cmd_show_options_print(self, item, o, idx);
|
||||
|
||||
if (args->argc == 0)
|
||||
return (cmd_show_options_all(self, item, oo));
|
||||
else
|
||||
return (cmd_show_options_one(self, item, oo));
|
||||
free(name);
|
||||
free(argument);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
free(name);
|
||||
free(argument);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -89,15 +181,20 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
|
||||
struct options_entry *o, int idx)
|
||||
{
|
||||
struct options_array_item *a;
|
||||
const char *name, *value;
|
||||
char *tmp, *escaped;
|
||||
const char *name = options_name(o);
|
||||
char *value, *tmp = NULL, *escaped;
|
||||
|
||||
if (idx != -1) {
|
||||
xasprintf(&tmp, "%s[%d]", options_name(o), idx);
|
||||
xasprintf(&tmp, "%s[%d]", name, idx);
|
||||
name = tmp;
|
||||
} else {
|
||||
if (options_isarray(o)) {
|
||||
a = options_array_first(o);
|
||||
if (a == NULL) {
|
||||
if (!args_has(self->args, 'v'))
|
||||
cmdq_print(item, "%s", name);
|
||||
return;
|
||||
}
|
||||
while (a != NULL) {
|
||||
idx = options_array_item_index(a);
|
||||
cmd_show_options_print(self, item, o, idx);
|
||||
@@ -105,77 +202,50 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
|
||||
}
|
||||
return;
|
||||
}
|
||||
tmp = NULL;
|
||||
name = options_name(o);
|
||||
}
|
||||
|
||||
value = options_tostring(o, idx, 0);
|
||||
if (args_has(self->args, 'v'))
|
||||
cmdq_print(item, "%s", value);
|
||||
else if (options_isstring(o)) {
|
||||
utf8_stravis(&escaped, value, VIS_OCTAL|VIS_TAB|VIS_NL|VIS_DQ);
|
||||
cmdq_print(item, "%s \"%s\"", name, escaped);
|
||||
escaped = args_escape(value);
|
||||
cmdq_print(item, "%s %s", name, escaped);
|
||||
free(escaped);
|
||||
} else
|
||||
cmdq_print(item, "%s %s", name, value);
|
||||
free(value);
|
||||
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_show_options_one(struct cmd *self, struct cmdq_item *item,
|
||||
struct options *oo)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
struct client *c = cmd_find_client(item, NULL, 1);
|
||||
struct session *s = item->target.s;
|
||||
struct winlink *wl = item->target.wl;
|
||||
struct options_entry *o;
|
||||
int idx, ambiguous;
|
||||
char *name;
|
||||
|
||||
name = format_single(item, args->argv[0], c, s, wl, NULL);
|
||||
o = options_match_get(oo, name, &idx, 1, &ambiguous);
|
||||
if (o == NULL) {
|
||||
if (args_has(args, 'q')) {
|
||||
free(name);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
if (ambiguous) {
|
||||
cmdq_error(item, "ambiguous option: %s", name);
|
||||
free(name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (*name != '@' &&
|
||||
options_match_get(oo, name, &idx, 0, &ambiguous) != NULL) {
|
||||
free(name);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
cmdq_error(item, "unknown option: %s", name);
|
||||
free(name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
cmd_show_options_print(self, item, o, idx);
|
||||
free(name);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_show_options_all(struct cmd *self, struct cmdq_item *item,
|
||||
struct options *oo)
|
||||
{
|
||||
struct options_entry *o;
|
||||
const struct options_table_entry *oe;
|
||||
struct options_array_item *a;
|
||||
u_int idx;
|
||||
const struct options_table_entry *oe;
|
||||
|
||||
o = options_first(oo);
|
||||
while (o != NULL) {
|
||||
oe = options_table_entry(o);
|
||||
if ((self->entry != &cmd_show_hooks_entry &&
|
||||
!args_has(self->args, 'H') &&
|
||||
oe != NULL &&
|
||||
(oe->flags & OPTIONS_TABLE_IS_HOOK)) ||
|
||||
(self->entry == &cmd_show_hooks_entry &&
|
||||
(oe == NULL ||
|
||||
(~oe->flags & OPTIONS_TABLE_IS_HOOK)))) {
|
||||
o = options_next(o);
|
||||
continue;
|
||||
}
|
||||
if (!options_isarray(o))
|
||||
cmd_show_options_print(self, item, o, -1);
|
||||
else {
|
||||
a = options_array_first(o);
|
||||
else if ((a = options_array_first(o)) == NULL) {
|
||||
if (!args_has(self->args, 'v'))
|
||||
cmdq_print(item, "%s", options_name(o));
|
||||
} else {
|
||||
while (a != NULL) {
|
||||
idx = options_array_item_index(a);
|
||||
cmd_show_options_print(self, item, o, idx);
|
||||
|
||||
@@ -37,8 +37,8 @@ const struct cmd_entry cmd_source_file_entry = {
|
||||
.name = "source-file",
|
||||
.alias = "source",
|
||||
|
||||
.args = { "q", 1, 1 },
|
||||
.usage = "[-q] path",
|
||||
.args = { "nq", 1, -1 },
|
||||
.usage = "[-nq] path ...",
|
||||
|
||||
.flags = 0,
|
||||
.exec = cmd_source_file_exec
|
||||
@@ -48,45 +48,60 @@ static enum cmd_retval
|
||||
cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
int quiet = args_has(args, 'q');
|
||||
int flags = 0;
|
||||
struct client *c = item->client;
|
||||
struct cmdq_item *new_item;
|
||||
struct cmdq_item *new_item, *after;
|
||||
enum cmd_retval retval;
|
||||
char *pattern, *tmp;
|
||||
const char *path = args->argv[0];
|
||||
char *pattern, *cwd;
|
||||
const char *path, *error;
|
||||
glob_t g;
|
||||
u_int i;
|
||||
int i;
|
||||
u_int j;
|
||||
|
||||
if (*path == '/')
|
||||
pattern = xstrdup(path);
|
||||
else {
|
||||
utf8_stravis(&tmp, server_client_get_cwd(c, NULL), VIS_GLOB);
|
||||
xasprintf(&pattern, "%s/%s", tmp, path);
|
||||
free(tmp);
|
||||
}
|
||||
log_debug("%s: %s", __func__, pattern);
|
||||
if (args_has(args, 'q'))
|
||||
flags |= CMD_PARSE_QUIET;
|
||||
if (args_has(args, 'n'))
|
||||
flags |= CMD_PARSE_PARSEONLY;
|
||||
utf8_stravis(&cwd, server_client_get_cwd(c, NULL), VIS_GLOB);
|
||||
|
||||
retval = CMD_RETURN_NORMAL;
|
||||
if (glob(pattern, 0, NULL, &g) != 0) {
|
||||
if (!quiet || errno != ENOENT) {
|
||||
cmdq_error(item, "%s: %s", path, strerror(errno));
|
||||
retval = CMD_RETURN_ERROR;
|
||||
for (i = 0; i < args->argc; i++) {
|
||||
path = args->argv[i];
|
||||
if (*path == '/')
|
||||
pattern = xstrdup(path);
|
||||
else
|
||||
xasprintf(&pattern, "%s/%s", cwd, path);
|
||||
log_debug("%s: %s", __func__, pattern);
|
||||
|
||||
if (glob(pattern, 0, NULL, &g) != 0) {
|
||||
error = strerror(errno);
|
||||
if (errno != ENOENT || (~flags & CMD_PARSE_QUIET)) {
|
||||
cmdq_error(item, "%s: %s", path, error);
|
||||
retval = CMD_RETURN_ERROR;
|
||||
}
|
||||
free(pattern);
|
||||
continue;
|
||||
}
|
||||
free(pattern);
|
||||
return (retval);
|
||||
}
|
||||
free(pattern);
|
||||
|
||||
for (i = 0; i < (u_int)g.gl_pathc; i++) {
|
||||
if (load_cfg(g.gl_pathv[i], c, item, quiet) < 0)
|
||||
retval = CMD_RETURN_ERROR;
|
||||
after = item;
|
||||
for (j = 0; j < g.gl_pathc; j++) {
|
||||
path = g.gl_pathv[j];
|
||||
if (load_cfg(path, c, after, flags, &new_item) < 0)
|
||||
retval = CMD_RETURN_ERROR;
|
||||
else if (new_item != NULL)
|
||||
after = new_item;
|
||||
}
|
||||
globfree(&g);
|
||||
}
|
||||
if (cfg_finished) {
|
||||
if (retval == CMD_RETURN_ERROR && c->session == NULL)
|
||||
c->retval = 1;
|
||||
new_item = cmdq_get_callback(cmd_source_file_done, NULL);
|
||||
cmdq_insert_after(item, new_item);
|
||||
}
|
||||
|
||||
globfree(&g);
|
||||
free(cwd);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,9 +39,10 @@ const struct cmd_entry cmd_split_window_entry = {
|
||||
.name = "split-window",
|
||||
.alias = "splitw",
|
||||
|
||||
.args = { "bc:dfF:l:hp:Pt:v", 0, -1 },
|
||||
.usage = "[-bdfhvP] [-c start-directory] [-F format] "
|
||||
"[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]",
|
||||
.args = { "bc:de:fF:hIl:p:Pt:v", 0, -1 },
|
||||
.usage = "[-bdefhIPv] [-c start-directory] [-e environment] "
|
||||
"[-F format] [-p percentage|-l size] " CMD_TARGET_PANE_USAGE
|
||||
" [command]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
@@ -52,111 +53,106 @@ const struct cmd_entry cmd_split_window_entry = {
|
||||
static enum cmd_retval
|
||||
cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct cmd_find_state *current = &item->shared->current;
|
||||
struct args *args = self->args;
|
||||
struct cmd_find_state *current = &item->shared->current;
|
||||
struct spawn_context sc;
|
||||
struct client *c = cmd_find_client(item, NULL, 1);
|
||||
struct session *s = item->target.s;
|
||||
struct winlink *wl = item->target.wl;
|
||||
struct window *w = wl->window;
|
||||
struct window_pane *wp = item->target.wp, *new_wp = NULL;
|
||||
struct environ *env;
|
||||
const char *cmd, *path, *shell, *template, *tmp;
|
||||
char **argv, *cause, *new_cause, *cp, *cwd;
|
||||
u_int hlimit;
|
||||
int argc, size, percentage, before;
|
||||
struct window_pane *wp = item->target.wp, *new_wp;
|
||||
enum layout_type type;
|
||||
struct layout_cell *lc;
|
||||
struct environ_entry *envent;
|
||||
struct cmd_find_state fs;
|
||||
struct cmd_find_state fs;
|
||||
int size, percentage, flags, input;
|
||||
const char *template, *add;
|
||||
char *cause, *cp;
|
||||
struct args_value *value;
|
||||
|
||||
server_unzoom_window(w);
|
||||
|
||||
if (args->argc == 0) {
|
||||
cmd = options_get_string(s->options, "default-command");
|
||||
if (cmd != NULL && *cmd != '\0') {
|
||||
argc = 1;
|
||||
argv = (char **)&cmd;
|
||||
} else {
|
||||
argc = 0;
|
||||
argv = NULL;
|
||||
}
|
||||
} else {
|
||||
argc = args->argc;
|
||||
argv = args->argv;
|
||||
}
|
||||
|
||||
if ((tmp = args_get(args, 'c')) != NULL)
|
||||
cwd = format_single(item, tmp, c, s, NULL, NULL);
|
||||
else
|
||||
cwd = xstrdup(server_client_get_cwd(item->client, s));
|
||||
|
||||
type = LAYOUT_TOPBOTTOM;
|
||||
if (args_has(args, 'h'))
|
||||
type = LAYOUT_LEFTRIGHT;
|
||||
before = args_has(args, 'b');
|
||||
|
||||
size = -1;
|
||||
else
|
||||
type = LAYOUT_TOPBOTTOM;
|
||||
if (args_has(args, 'l')) {
|
||||
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
|
||||
if (cause != NULL) {
|
||||
xasprintf(&new_cause, "size %s", cause);
|
||||
cmdq_error(item, "create pane failed: -l %s", cause);
|
||||
free(cause);
|
||||
cause = new_cause;
|
||||
goto error;
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
} else if (args_has(args, 'p')) {
|
||||
percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause);
|
||||
if (cause != NULL) {
|
||||
xasprintf(&new_cause, "percentage %s", cause);
|
||||
cmdq_error(item, "create pane failed: -p %s", cause);
|
||||
free(cause);
|
||||
cause = new_cause;
|
||||
goto error;
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (type == LAYOUT_TOPBOTTOM)
|
||||
size = (wp->sy * percentage) / 100;
|
||||
else
|
||||
size = (wp->sx * percentage) / 100;
|
||||
}
|
||||
hlimit = options_get_number(s->options, "history-limit");
|
||||
|
||||
shell = options_get_string(s->options, "default-shell");
|
||||
if (*shell == '\0' || areshell(shell))
|
||||
shell = _PATH_BSHELL;
|
||||
|
||||
lc = layout_split_pane(wp, type, size, before, args_has(args, 'f'));
|
||||
if (lc == NULL) {
|
||||
cause = xstrdup("pane too small");
|
||||
goto error;
|
||||
}
|
||||
new_wp = window_add_pane(w, wp, before, args_has(args, 'f'), hlimit);
|
||||
layout_make_leaf(lc, new_wp);
|
||||
|
||||
path = NULL;
|
||||
if (item->client != NULL && item->client->session == NULL)
|
||||
envent = environ_find(item->client->environ, "PATH");
|
||||
else
|
||||
envent = environ_find(s->environ, "PATH");
|
||||
if (envent != NULL)
|
||||
path = envent->value;
|
||||
|
||||
env = environ_for_session(s, 0);
|
||||
if (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, env,
|
||||
s->tio, &cause) != 0) {
|
||||
environ_free(env);
|
||||
goto error;
|
||||
}
|
||||
environ_free(env);
|
||||
|
||||
layout_fix_panes(w);
|
||||
server_redraw_window(w);
|
||||
|
||||
if (!args_has(args, 'd')) {
|
||||
window_set_active_pane(w, new_wp);
|
||||
session_select(s, wl->idx);
|
||||
cmd_find_from_session(current, s, 0);
|
||||
server_redraw_session(s);
|
||||
} else
|
||||
server_status_session(s);
|
||||
size = -1;
|
||||
|
||||
server_unzoom_window(wp->window);
|
||||
input = (args_has(args, 'I') && args->argc == 0);
|
||||
|
||||
flags = 0;
|
||||
if (args_has(args, 'b'))
|
||||
flags |= SPAWN_BEFORE;
|
||||
if (args_has(args, 'f'))
|
||||
flags |= SPAWN_FULLSIZE;
|
||||
if (input || (args->argc == 1 && *args->argv[0] == '\0'))
|
||||
flags |= SPAWN_EMPTY;
|
||||
|
||||
lc = layout_split_pane(wp, type, size, flags);
|
||||
if (lc == NULL) {
|
||||
cmdq_error(item, "no space for new pane");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
memset(&sc, 0, sizeof sc);
|
||||
sc.item = item;
|
||||
sc.s = s;
|
||||
sc.wl = wl;
|
||||
|
||||
sc.wp0 = wp;
|
||||
sc.lc = lc;
|
||||
|
||||
sc.name = NULL;
|
||||
sc.argc = args->argc;
|
||||
sc.argv = args->argv;
|
||||
sc.environ = environ_create();
|
||||
|
||||
add = args_first_value(args, 'e', &value);
|
||||
while (add != NULL) {
|
||||
environ_put(sc.environ, add);
|
||||
add = args_next_value(&value);
|
||||
}
|
||||
|
||||
sc.idx = -1;
|
||||
sc.cwd = args_get(args, 'c');
|
||||
|
||||
sc.flags = flags;
|
||||
if (args_has(args, 'd'))
|
||||
sc.flags |= SPAWN_DETACHED;
|
||||
|
||||
if ((new_wp = spawn_pane(&sc, &cause)) == NULL) {
|
||||
layout_close_pane(new_wp);
|
||||
cmdq_error(item, "create pane failed: %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (input && window_pane_start_input(new_wp, item, &cause) != 0) {
|
||||
layout_close_pane(new_wp);
|
||||
window_remove_pane(wp->window, new_wp);
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (!args_has(args, 'd'))
|
||||
cmd_find_from_winlink_pane(current, wl, new_wp, 0);
|
||||
server_redraw_window(wp->window);
|
||||
server_status_session(s);
|
||||
|
||||
if (args_has(args, 'P')) {
|
||||
if ((template = args_get(args, 'F')) == NULL)
|
||||
@@ -165,22 +161,12 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cmdq_print(item, "%s", cp);
|
||||
free(cp);
|
||||
}
|
||||
notify_window("window-layout-changed", w);
|
||||
|
||||
cmd_find_from_winlink_pane(&fs, wl, new_wp, 0);
|
||||
hooks_insert(s->hooks, item, &fs, "after-split-window");
|
||||
cmdq_insert_hook(s, item, &fs, "after-split-window");
|
||||
|
||||
free(cwd);
|
||||
environ_free(sc.environ);
|
||||
if (input)
|
||||
return (CMD_RETURN_WAIT);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
error:
|
||||
if (new_wp != NULL) {
|
||||
layout_close_pane(new_wp);
|
||||
window_remove_pane(w, new_wp);
|
||||
}
|
||||
cmdq_error(item, "create pane failed: %s", cause);
|
||||
free(cause);
|
||||
|
||||
free(cwd);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
390
cmd-string.c
390
cmd-string.c
@@ -1,390 +0,0 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* Parse a command from a string.
|
||||
*/
|
||||
|
||||
static int cmd_string_getc(const char *, size_t *);
|
||||
static void cmd_string_ungetc(size_t *);
|
||||
static void cmd_string_copy(char **, char *, size_t *);
|
||||
static char *cmd_string_string(const char *, size_t *, char, int);
|
||||
static char *cmd_string_variable(const char *, size_t *);
|
||||
static char *cmd_string_expand_tilde(const char *, size_t *);
|
||||
|
||||
static int
|
||||
cmd_string_getc(const char *s, size_t *p)
|
||||
{
|
||||
const u_char *ucs = s;
|
||||
|
||||
if (ucs[*p] == '\0')
|
||||
return (EOF);
|
||||
return (ucs[(*p)++]);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_string_ungetc(size_t *p)
|
||||
{
|
||||
(*p)--;
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_string_unicode(wchar_t *wc, const char *s, size_t *p, char ch)
|
||||
{
|
||||
int size = (ch == 'u') ? 4 : 8;
|
||||
u_int tmp;
|
||||
|
||||
if (size == 4 && sscanf(s + *p, "%4x", &tmp) != 1)
|
||||
return (-1);
|
||||
if (size == 8 && sscanf(s + *p, "%8x", &tmp) != 1)
|
||||
return (-1);
|
||||
*p += size;
|
||||
|
||||
*wc = (wchar_t)tmp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
cmd_string_split(const char *s, int *rargc, char ***rargv)
|
||||
{
|
||||
size_t p = 0;
|
||||
int ch, argc = 0, append = 0;
|
||||
char **argv = NULL, *buf = NULL, *t;
|
||||
const char *whitespace, *equals;
|
||||
size_t len = 0;
|
||||
|
||||
for (;;) {
|
||||
ch = cmd_string_getc(s, &p);
|
||||
switch (ch) {
|
||||
case '\'':
|
||||
if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL)
|
||||
goto error;
|
||||
cmd_string_copy(&buf, t, &len);
|
||||
break;
|
||||
case '"':
|
||||
if ((t = cmd_string_string(s, &p, '"', 1)) == NULL)
|
||||
goto error;
|
||||
cmd_string_copy(&buf, t, &len);
|
||||
break;
|
||||
case '$':
|
||||
if ((t = cmd_string_variable(s, &p)) == NULL)
|
||||
goto error;
|
||||
cmd_string_copy(&buf, t, &len);
|
||||
break;
|
||||
case '#':
|
||||
/* Comment: discard rest of line. */
|
||||
while ((ch = cmd_string_getc(s, &p)) != EOF)
|
||||
;
|
||||
/* FALLTHROUGH */
|
||||
case EOF:
|
||||
case ' ':
|
||||
case '\t':
|
||||
if (buf != NULL) {
|
||||
buf = xrealloc(buf, len + 1);
|
||||
buf[len] = '\0';
|
||||
|
||||
argv = xreallocarray(argv, argc + 1,
|
||||
sizeof *argv);
|
||||
argv[argc++] = buf;
|
||||
|
||||
buf = NULL;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
if (ch != EOF)
|
||||
break;
|
||||
|
||||
while (argc != 0) {
|
||||
equals = strchr(argv[0], '=');
|
||||
whitespace = argv[0] + strcspn(argv[0], " \t");
|
||||
if (equals == NULL || equals > whitespace)
|
||||
break;
|
||||
environ_put(global_environ, argv[0]);
|
||||
argc--;
|
||||
memmove(argv, argv + 1, argc * (sizeof *argv));
|
||||
}
|
||||
goto done;
|
||||
case '~':
|
||||
if (buf != NULL) {
|
||||
append = 1;
|
||||
break;
|
||||
}
|
||||
t = cmd_string_expand_tilde(s, &p);
|
||||
if (t == NULL)
|
||||
goto error;
|
||||
cmd_string_copy(&buf, t, &len);
|
||||
break;
|
||||
default:
|
||||
append = 1;
|
||||
break;
|
||||
}
|
||||
if (append) {
|
||||
if (len >= SIZE_MAX - 2)
|
||||
goto error;
|
||||
buf = xrealloc(buf, len + 1);
|
||||
buf[len++] = ch;
|
||||
}
|
||||
append = 0;
|
||||
}
|
||||
|
||||
done:
|
||||
*rargc = argc;
|
||||
*rargv = argv;
|
||||
|
||||
free(buf);
|
||||
return (0);
|
||||
|
||||
error:
|
||||
if (argv != NULL)
|
||||
cmd_free_argv(argc, argv);
|
||||
free(buf);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
struct cmd_list *
|
||||
cmd_string_parse(const char *s, const char *file, u_int line, char **cause)
|
||||
{
|
||||
struct cmd_list *cmdlist = NULL;
|
||||
int argc;
|
||||
char **argv;
|
||||
|
||||
*cause = NULL;
|
||||
if (cmd_string_split(s, &argc, &argv) != 0) {
|
||||
xasprintf(cause, "invalid or unknown command: %s", s);
|
||||
return (NULL);
|
||||
}
|
||||
if (argc != 0) {
|
||||
cmdlist = cmd_list_parse(argc, argv, file, line, cause);
|
||||
if (cmdlist == NULL) {
|
||||
cmd_free_argv(argc, argv);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
cmd_free_argv(argc, argv);
|
||||
return (cmdlist);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_string_copy(char **dst, char *src, size_t *len)
|
||||
{
|
||||
size_t srclen;
|
||||
|
||||
srclen = strlen(src);
|
||||
|
||||
*dst = xrealloc(*dst, *len + srclen + 1);
|
||||
strlcpy(*dst + *len, src, srclen + 1);
|
||||
|
||||
*len += srclen;
|
||||
free(src);
|
||||
}
|
||||
|
||||
static char *
|
||||
cmd_string_string(const char *s, size_t *p, char endch, int esc)
|
||||
{
|
||||
int ch;
|
||||
wchar_t wc;
|
||||
struct utf8_data ud;
|
||||
char *buf = NULL, *t;
|
||||
size_t len = 0;
|
||||
|
||||
while ((ch = cmd_string_getc(s, p)) != endch) {
|
||||
switch (ch) {
|
||||
case EOF:
|
||||
goto error;
|
||||
case '\\':
|
||||
if (!esc)
|
||||
break;
|
||||
switch (ch = cmd_string_getc(s, p)) {
|
||||
case EOF:
|
||||
goto error;
|
||||
case 'e':
|
||||
ch = '\033';
|
||||
break;
|
||||
case 'r':
|
||||
ch = '\r';
|
||||
break;
|
||||
case 'n':
|
||||
ch = '\n';
|
||||
break;
|
||||
case 't':
|
||||
ch = '\t';
|
||||
break;
|
||||
case 'u':
|
||||
case 'U':
|
||||
if (cmd_string_unicode(&wc, s, p, ch) != 0)
|
||||
goto error;
|
||||
if (utf8_split(wc, &ud) != UTF8_DONE)
|
||||
goto error;
|
||||
if (len >= SIZE_MAX - ud.size - 1)
|
||||
goto error;
|
||||
buf = xrealloc(buf, len + ud.size);
|
||||
memcpy(buf + len, ud.data, ud.size);
|
||||
len += ud.size;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case '$':
|
||||
if (!esc)
|
||||
break;
|
||||
if ((t = cmd_string_variable(s, p)) == NULL)
|
||||
goto error;
|
||||
cmd_string_copy(&buf, t, &len);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len >= SIZE_MAX - 2)
|
||||
goto error;
|
||||
buf = xrealloc(buf, len + 1);
|
||||
buf[len++] = ch;
|
||||
}
|
||||
|
||||
buf = xrealloc(buf, len + 1);
|
||||
buf[len] = '\0';
|
||||
return (buf);
|
||||
|
||||
error:
|
||||
free(buf);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static char *
|
||||
cmd_string_variable(const char *s, size_t *p)
|
||||
{
|
||||
int ch, fch;
|
||||
char *buf, *t;
|
||||
size_t len;
|
||||
struct environ_entry *envent;
|
||||
|
||||
#define cmd_string_first(ch) ((ch) == '_' || \
|
||||
((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
|
||||
#define cmd_string_other(ch) ((ch) == '_' || \
|
||||
((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \
|
||||
((ch) >= '0' && (ch) <= '9'))
|
||||
|
||||
buf = NULL;
|
||||
len = 0;
|
||||
|
||||
fch = EOF;
|
||||
switch (ch = cmd_string_getc(s, p)) {
|
||||
case EOF:
|
||||
goto error;
|
||||
case '{':
|
||||
fch = '{';
|
||||
|
||||
ch = cmd_string_getc(s, p);
|
||||
if (!cmd_string_first(ch))
|
||||
goto error;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
if (!cmd_string_first(ch)) {
|
||||
xasprintf(&t, "$%c", ch);
|
||||
return (t);
|
||||
}
|
||||
|
||||
buf = xrealloc(buf, len + 1);
|
||||
buf[len++] = ch;
|
||||
|
||||
for (;;) {
|
||||
ch = cmd_string_getc(s, p);
|
||||
if (ch == EOF || !cmd_string_other(ch))
|
||||
break;
|
||||
else {
|
||||
if (len >= SIZE_MAX - 3)
|
||||
goto error;
|
||||
buf = xrealloc(buf, len + 1);
|
||||
buf[len++] = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fch == '{' && ch != '}')
|
||||
goto error;
|
||||
if (ch != EOF && fch != '{')
|
||||
cmd_string_ungetc(p); /* ch */
|
||||
|
||||
buf = xrealloc(buf, len + 1);
|
||||
buf[len] = '\0';
|
||||
|
||||
envent = environ_find(global_environ, buf);
|
||||
free(buf);
|
||||
if (envent == NULL)
|
||||
return (xstrdup(""));
|
||||
return (xstrdup(envent->value));
|
||||
|
||||
error:
|
||||
free(buf);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static char *
|
||||
cmd_string_expand_tilde(const char *s, size_t *p)
|
||||
{
|
||||
struct passwd *pw;
|
||||
struct environ_entry *envent;
|
||||
char *home, *path, *user, *cp;
|
||||
int last;
|
||||
|
||||
home = NULL;
|
||||
|
||||
last = cmd_string_getc(s, p);
|
||||
if (last == EOF || last == '/' || last == ' '|| last == '\t') {
|
||||
envent = environ_find(global_environ, "HOME");
|
||||
if (envent != NULL && *envent->value != '\0')
|
||||
home = envent->value;
|
||||
else if ((pw = getpwuid(getuid())) != NULL)
|
||||
home = pw->pw_dir;
|
||||
} else {
|
||||
cmd_string_ungetc(p);
|
||||
|
||||
cp = user = xmalloc(strlen(s));
|
||||
for (;;) {
|
||||
last = cmd_string_getc(s, p);
|
||||
if (last == EOF ||
|
||||
last == '/' ||
|
||||
last == ' '||
|
||||
last == '\t')
|
||||
break;
|
||||
*cp++ = last;
|
||||
}
|
||||
*cp = '\0';
|
||||
|
||||
if ((pw = getpwnam(user)) != NULL)
|
||||
home = pw->pw_dir;
|
||||
free(user);
|
||||
}
|
||||
|
||||
if (home == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (last != EOF)
|
||||
xasprintf(&path, "%s%c", home, last);
|
||||
else
|
||||
xasprintf(&path, "%s", home);
|
||||
return (path);
|
||||
}
|
||||
@@ -101,17 +101,17 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
if (!args_has(self->args, 'd')) {
|
||||
if (src_w != dst_w) {
|
||||
window_set_active_pane(src_w, dst_wp);
|
||||
window_set_active_pane(dst_w, src_wp);
|
||||
window_set_active_pane(src_w, dst_wp, 1);
|
||||
window_set_active_pane(dst_w, src_wp, 1);
|
||||
} else {
|
||||
tmp_wp = dst_wp;
|
||||
window_set_active_pane(src_w, tmp_wp);
|
||||
window_set_active_pane(src_w, tmp_wp, 1);
|
||||
}
|
||||
} else {
|
||||
if (src_w->active == src_wp)
|
||||
window_set_active_pane(src_w, dst_wp);
|
||||
window_set_active_pane(src_w, dst_wp, 1);
|
||||
if (dst_w->active == dst_wp)
|
||||
window_set_active_pane(dst_w, src_wp);
|
||||
window_set_active_pane(dst_w, src_wp, 1);
|
||||
}
|
||||
if (src_w != dst_w) {
|
||||
if (src_w->last == src_wp)
|
||||
|
||||
@@ -78,9 +78,9 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
TAILQ_INSERT_TAIL(&w_dst->winlinks, wl_src, wentry);
|
||||
|
||||
if (!args_has(self->args, 'd')) {
|
||||
session_select(dst, wl_dst->idx);
|
||||
session_select(src, wl_src->idx);
|
||||
if (src != dst)
|
||||
session_select(src, wl_src->idx);
|
||||
session_select(dst, wl_dst->idx);
|
||||
}
|
||||
session_group_synchronize_from(src);
|
||||
server_redraw_session_group(src);
|
||||
|
||||
@@ -61,7 +61,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
|
||||
return (CMD_RETURN_ERROR);
|
||||
|
||||
if (tflag != NULL && tflag[strcspn(tflag, ":.")] != '\0') {
|
||||
if (tflag != NULL && tflag[strcspn(tflag, ":.%")] != '\0') {
|
||||
type = CMD_FIND_PANE;
|
||||
flags = 0;
|
||||
} else {
|
||||
@@ -116,7 +116,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
server_unzoom_window(wl->window);
|
||||
if (wp != NULL) {
|
||||
window_redraw_active_switch(wp->window, wp);
|
||||
window_set_active_pane(wp->window, wp);
|
||||
window_set_active_pane(wp->window, wp, 1);
|
||||
}
|
||||
session_set_current(s, wl);
|
||||
cmd_find_from_session(&item->shared->current, s, 0);
|
||||
|
||||
238
cmd.c
238
cmd.c
@@ -41,6 +41,7 @@ extern const struct cmd_entry cmd_confirm_before_entry;
|
||||
extern const struct cmd_entry cmd_copy_mode_entry;
|
||||
extern const struct cmd_entry cmd_delete_buffer_entry;
|
||||
extern const struct cmd_entry cmd_detach_client_entry;
|
||||
extern const struct cmd_entry cmd_display_menu_entry;
|
||||
extern const struct cmd_entry cmd_display_message_entry;
|
||||
extern const struct cmd_entry cmd_display_panes_entry;
|
||||
extern const struct cmd_entry cmd_down_pane_entry;
|
||||
@@ -129,6 +130,7 @@ const struct cmd_entry *cmd_table[] = {
|
||||
&cmd_copy_mode_entry,
|
||||
&cmd_delete_buffer_entry,
|
||||
&cmd_detach_client_entry,
|
||||
&cmd_display_menu_entry,
|
||||
&cmd_display_message_entry,
|
||||
&cmd_display_panes_entry,
|
||||
&cmd_find_window_entry,
|
||||
@@ -202,13 +204,43 @@ const struct cmd_entry *cmd_table[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
cmd_log_argv(int argc, char **argv, const char *prefix)
|
||||
void printflike(3, 4)
|
||||
cmd_log_argv(int argc, char **argv, const char *fmt, ...)
|
||||
{
|
||||
int i;
|
||||
char *prefix;
|
||||
va_list ap;
|
||||
int i;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&prefix, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
log_debug("%s: argv[%d]=%s", prefix, i, argv[i]);
|
||||
free(prefix);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_prepend_argv(int *argc, char ***argv, char *arg)
|
||||
{
|
||||
char **new_argv;
|
||||
int i;
|
||||
|
||||
new_argv = xreallocarray(NULL, (*argc) + 1, sizeof *new_argv);
|
||||
new_argv[0] = xstrdup(arg);
|
||||
for (i = 0; i < *argc; i++)
|
||||
new_argv[1 + i] = (*argv)[i];
|
||||
|
||||
free(*argv);
|
||||
*argv = new_argv;
|
||||
(*argc)++;
|
||||
}
|
||||
|
||||
void
|
||||
cmd_append_argv(int *argc, char ***argv, char *arg)
|
||||
{
|
||||
*argv = xreallocarray(*argv, (*argc) + 1, sizeof **argv);
|
||||
(*argv)[(*argc)++] = xstrdup(arg);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -219,7 +251,7 @@ cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
|
||||
|
||||
if (argc == 0)
|
||||
return (0);
|
||||
cmd_log_argv(argc, argv, __func__);
|
||||
cmd_log_argv(argc, argv, "%s", __func__);
|
||||
|
||||
*buf = '\0';
|
||||
for (i = 0; i < argc; i++) {
|
||||
@@ -256,7 +288,7 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
|
||||
buf += arglen;
|
||||
len -= arglen;
|
||||
}
|
||||
cmd_log_argv(argc, *argv, __func__);
|
||||
cmd_log_argv(argc, *argv, "%s", __func__);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -315,107 +347,103 @@ cmd_stringify_argv(int argc, char **argv)
|
||||
return (buf);
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_try_alias(int *argc, char ***argv)
|
||||
char *
|
||||
cmd_get_alias(const char *name)
|
||||
{
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
int old_argc = *argc, new_argc, i;
|
||||
char **old_argv = *argv, **new_argv;
|
||||
size_t wanted;
|
||||
const char *s, *cp = NULL;
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
union options_value *ov;
|
||||
size_t wanted, n;
|
||||
const char *equals;
|
||||
|
||||
o = options_get_only(global_options, "command-alias");
|
||||
if (o == NULL)
|
||||
return (-1);
|
||||
wanted = strlen(old_argv[0]);
|
||||
return (NULL);
|
||||
wanted = strlen(name);
|
||||
|
||||
a = options_array_first(o);
|
||||
while (a != NULL) {
|
||||
s = options_array_item_value(a);
|
||||
if (s != NULL) {
|
||||
cp = strchr(s, '=');
|
||||
if (cp != NULL &&
|
||||
(size_t)(cp - s) == wanted &&
|
||||
strncmp(old_argv[0], s, wanted) == 0)
|
||||
break;
|
||||
ov = options_array_item_value(a);
|
||||
|
||||
equals = strchr(ov->string, '=');
|
||||
if (equals != NULL) {
|
||||
n = equals - ov->string;
|
||||
if (n == wanted && strncmp(name, ov->string, n) == 0)
|
||||
return (xstrdup(equals + 1));
|
||||
}
|
||||
|
||||
a = options_array_next(a);
|
||||
}
|
||||
if (a == NULL)
|
||||
return (-1);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (cmd_string_split(cp + 1, &new_argc, &new_argv) != 0)
|
||||
return (-1);
|
||||
static const struct cmd_entry *
|
||||
cmd_find(const char *name, char **cause)
|
||||
{
|
||||
const struct cmd_entry **loop, *entry, *found = NULL;
|
||||
int ambiguous;
|
||||
char s[BUFSIZ];
|
||||
|
||||
*argc = new_argc + old_argc - 1;
|
||||
*argv = xcalloc((*argc) + 1, sizeof **argv);
|
||||
ambiguous = 0;
|
||||
for (loop = cmd_table; *loop != NULL; loop++) {
|
||||
entry = *loop;
|
||||
if (entry->alias != NULL && strcmp(entry->alias, name) == 0) {
|
||||
ambiguous = 0;
|
||||
found = entry;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < new_argc; i++)
|
||||
(*argv)[i] = xstrdup(new_argv[i]);
|
||||
for (i = 1; i < old_argc; i++)
|
||||
(*argv)[new_argc + i - 1] = xstrdup(old_argv[i]);
|
||||
if (strncmp(entry->name, name, strlen(name)) != 0)
|
||||
continue;
|
||||
if (found != NULL)
|
||||
ambiguous = 1;
|
||||
found = entry;
|
||||
|
||||
log_debug("alias: %s=%s", old_argv[0], cp + 1);
|
||||
for (i = 0; i < *argc; i++)
|
||||
log_debug("alias: argv[%d] = %s", i, (*argv)[i]);
|
||||
if (strcmp(entry->name, name) == 0)
|
||||
break;
|
||||
}
|
||||
if (ambiguous)
|
||||
goto ambiguous;
|
||||
if (found == NULL) {
|
||||
xasprintf(cause, "unknown command: %s", name);
|
||||
return (NULL);
|
||||
}
|
||||
return (found);
|
||||
|
||||
cmd_free_argv(new_argc, new_argv);
|
||||
return (0);
|
||||
ambiguous:
|
||||
*s = '\0';
|
||||
for (loop = cmd_table; *loop != NULL; loop++) {
|
||||
entry = *loop;
|
||||
if (strncmp(entry->name, name, strlen(name)) != 0)
|
||||
continue;
|
||||
if (strlcat(s, entry->name, sizeof s) >= sizeof s)
|
||||
break;
|
||||
if (strlcat(s, ", ", sizeof s) >= sizeof s)
|
||||
break;
|
||||
}
|
||||
s[strlen(s) - 2] = '\0';
|
||||
xasprintf(cause, "ambiguous command: %s, could be: %s", name, s);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct cmd *
|
||||
cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause)
|
||||
{
|
||||
const struct cmd_entry *entry;
|
||||
const char *name;
|
||||
const struct cmd_entry **entryp, *entry;
|
||||
struct cmd *cmd;
|
||||
struct args *args;
|
||||
char s[BUFSIZ];
|
||||
int ambiguous, allocated = 0;
|
||||
|
||||
*cause = NULL;
|
||||
if (argc == 0) {
|
||||
xasprintf(cause, "no command");
|
||||
return (NULL);
|
||||
}
|
||||
name = argv[0];
|
||||
|
||||
retry:
|
||||
ambiguous = 0;
|
||||
entry = NULL;
|
||||
for (entryp = cmd_table; *entryp != NULL; entryp++) {
|
||||
if ((*entryp)->alias != NULL &&
|
||||
strcmp((*entryp)->alias, argv[0]) == 0) {
|
||||
ambiguous = 0;
|
||||
entry = *entryp;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0)
|
||||
continue;
|
||||
if (entry != NULL)
|
||||
ambiguous = 1;
|
||||
entry = *entryp;
|
||||
|
||||
/* Bail now if an exact match. */
|
||||
if (strcmp(entry->name, argv[0]) == 0)
|
||||
break;
|
||||
}
|
||||
if ((ambiguous || entry == NULL) &&
|
||||
server_proc != NULL &&
|
||||
!allocated &&
|
||||
cmd_try_alias(&argc, &argv) == 0) {
|
||||
allocated = 1;
|
||||
goto retry;
|
||||
}
|
||||
if (ambiguous)
|
||||
goto ambiguous;
|
||||
if (entry == NULL) {
|
||||
xasprintf(cause, "unknown command: %s", name);
|
||||
entry = cmd_find(name, cause);
|
||||
if (entry == NULL)
|
||||
return (NULL);
|
||||
}
|
||||
cmd_log_argv(argc, argv, entry->name);
|
||||
cmd_log_argv(argc, argv, "%s: %s", __func__, entry->name);
|
||||
|
||||
args = args_parse(entry->args.template, argc, argv);
|
||||
if (args == NULL)
|
||||
@@ -433,23 +461,11 @@ retry:
|
||||
cmd->file = xstrdup(file);
|
||||
cmd->line = line;
|
||||
|
||||
if (allocated)
|
||||
cmd_free_argv(argc, argv);
|
||||
return (cmd);
|
||||
cmd->alias = NULL;
|
||||
cmd->argc = argc;
|
||||
cmd->argv = cmd_copy_argv(argc, argv);
|
||||
|
||||
ambiguous:
|
||||
*s = '\0';
|
||||
for (entryp = cmd_table; *entryp != NULL; entryp++) {
|
||||
if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0)
|
||||
continue;
|
||||
if (strlcat(s, (*entryp)->name, sizeof s) >= sizeof s)
|
||||
break;
|
||||
if (strlcat(s, ", ", sizeof s) >= sizeof s)
|
||||
break;
|
||||
}
|
||||
s[strlen(s) - 2] = '\0';
|
||||
xasprintf(cause, "ambiguous command: %s, could be: %s", name, s);
|
||||
return (NULL);
|
||||
return (cmd);
|
||||
|
||||
usage:
|
||||
if (args != NULL)
|
||||
@@ -458,6 +474,18 @@ usage:
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_free(struct cmd *cmd)
|
||||
{
|
||||
free(cmd->alias);
|
||||
cmd_free_argv(cmd->argc, cmd->argv);
|
||||
|
||||
free(cmd->file);
|
||||
|
||||
args_free(cmd->args);
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
char *
|
||||
cmd_print(struct cmd *cmd)
|
||||
{
|
||||
@@ -481,17 +509,16 @@ cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
|
||||
u_int x, y;
|
||||
|
||||
if (last) {
|
||||
x = m->lx;
|
||||
y = m->ly;
|
||||
x = m->lx + m->ox;
|
||||
y = m->ly + m->oy;
|
||||
} else {
|
||||
x = m->x;
|
||||
y = m->y;
|
||||
x = m->x + m->ox;
|
||||
y = m->y + m->oy;
|
||||
}
|
||||
log_debug("%s: x=%u, y=%u%s", __func__, x, y, last ? " (last)" : "");
|
||||
|
||||
if (m->statusat == 0 && y > 0)
|
||||
y--;
|
||||
else if (m->statusat > 0 && y >= (u_int)m->statusat)
|
||||
y = m->statusat - 1;
|
||||
|
||||
if (x < wp->xoff || x >= wp->xoff + wp->sx)
|
||||
return (-1);
|
||||
@@ -511,17 +538,22 @@ cmd_mouse_window(struct mouse_event *m, struct session **sp)
|
||||
{
|
||||
struct session *s;
|
||||
struct window *w;
|
||||
struct winlink *wl;
|
||||
|
||||
if (!m->valid || m->s == -1 || m->w == -1)
|
||||
if (!m->valid)
|
||||
return (NULL);
|
||||
if ((s = session_find_by_id(m->s)) == NULL)
|
||||
if (m->s == -1 || (s = session_find_by_id(m->s)) == NULL)
|
||||
return (NULL);
|
||||
if ((w = window_find_by_id(m->w)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (m->w == -1)
|
||||
wl = s->curw;
|
||||
else {
|
||||
if ((w = window_find_by_id(m->w)) == NULL)
|
||||
return (NULL);
|
||||
wl = winlink_find_by_window(&s->windows, w);
|
||||
}
|
||||
if (sp != NULL)
|
||||
*sp = s;
|
||||
return (winlink_find_by_window(&s->windows, w));
|
||||
return (wl);
|
||||
}
|
||||
|
||||
/* Get current mouse pane if any. */
|
||||
|
||||
5
compat.h
5
compat.h
@@ -67,6 +67,7 @@ void warnx(const char *, ...);
|
||||
#define _PATH_DEVNULL "/dev/null"
|
||||
#define _PATH_TTY "/dev/tty"
|
||||
#define _PATH_DEV "/dev/"
|
||||
#define _PATH_DEFPATH "/usr/bin:/bin"
|
||||
#endif
|
||||
|
||||
#ifndef __OpenBSD__
|
||||
@@ -312,10 +313,6 @@ int vasprintf(char **, const char *, va_list);
|
||||
char *fgetln(FILE *, size_t *);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FPARSELN
|
||||
char *fparseln(FILE *, size_t *, size_t *, const char *, int);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SETENV
|
||||
/* setenv.c */
|
||||
int setenv(const char *, const char *, int);
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
/* $OpenBSD: fparseln.c,v 1.6 2005/08/02 21:46:23 espie Exp $ */
|
||||
/* $NetBSD: fparseln.c,v 1.7 1999/07/02 15:49:12 simonb Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997 Christos Zoulas. 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. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Christos Zoulas.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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/libutil/fparseln.c */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
/*
|
||||
* fparseln() specific operation flags.
|
||||
*/
|
||||
#define FPARSELN_UNESCESC 0x01
|
||||
#define FPARSELN_UNESCCONT 0x02
|
||||
#define FPARSELN_UNESCCOMM 0x04
|
||||
#define FPARSELN_UNESCREST 0x08
|
||||
#define FPARSELN_UNESCALL 0x0f
|
||||
|
||||
static int isescaped(const char *, const char *, int);
|
||||
|
||||
/* isescaped():
|
||||
* Return true if the character in *p that belongs to a string
|
||||
* that starts in *sp, is escaped by the escape character esc.
|
||||
*/
|
||||
static int
|
||||
isescaped(const char *sp, const char *p, int esc)
|
||||
{
|
||||
const char *cp;
|
||||
size_t ne;
|
||||
|
||||
/* No escape character */
|
||||
if (esc == '\0')
|
||||
return 1;
|
||||
|
||||
/* Count the number of escape characters that precede ours */
|
||||
for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++)
|
||||
continue;
|
||||
|
||||
/* Return true if odd number of escape characters */
|
||||
return (ne & 1) != 0;
|
||||
}
|
||||
|
||||
|
||||
/* fparseln():
|
||||
* Read a line from a file parsing continuations ending in \
|
||||
* and eliminating trailing newlines, or comments starting with
|
||||
* the comment char.
|
||||
*/
|
||||
char *
|
||||
fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3],
|
||||
int flags)
|
||||
{
|
||||
static const char dstr[3] = { '\\', '\\', '#' };
|
||||
char *buf = NULL, *ptr, *cp, esc, con, nl, com;
|
||||
size_t s, len = 0;
|
||||
int cnt = 1;
|
||||
|
||||
if (str == NULL)
|
||||
str = dstr;
|
||||
|
||||
esc = str[0];
|
||||
con = str[1];
|
||||
com = str[2];
|
||||
|
||||
/*
|
||||
* XXX: it would be cool to be able to specify the newline character,
|
||||
* but unfortunately, fgetln does not let us
|
||||
*/
|
||||
nl = '\n';
|
||||
|
||||
while (cnt) {
|
||||
cnt = 0;
|
||||
|
||||
if (lineno)
|
||||
(*lineno)++;
|
||||
|
||||
if ((ptr = fgetln(fp, &s)) == NULL)
|
||||
break;
|
||||
|
||||
if (s && com) { /* Check and eliminate comments */
|
||||
for (cp = ptr; cp < ptr + s; cp++)
|
||||
if (*cp == com && !isescaped(ptr, cp, esc)) {
|
||||
s = cp - ptr;
|
||||
cnt = s == 0 && buf == NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (s && nl) { /* Check and eliminate newlines */
|
||||
cp = &ptr[s - 1];
|
||||
|
||||
if (*cp == nl)
|
||||
s--; /* forget newline */
|
||||
}
|
||||
|
||||
if (s && con) { /* Check and eliminate continuations */
|
||||
cp = &ptr[s - 1];
|
||||
|
||||
if (*cp == con && !isescaped(ptr, cp, esc)) {
|
||||
s--; /* forget escape */
|
||||
cnt = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (s == 0 && buf != NULL)
|
||||
continue;
|
||||
|
||||
if ((cp = realloc(buf, len + s + 1)) == NULL) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
buf = cp;
|
||||
|
||||
(void) memcpy(buf + len, ptr, s);
|
||||
len += s;
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
||||
if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL &&
|
||||
strchr(buf, esc) != NULL) {
|
||||
ptr = cp = buf;
|
||||
while (cp[0] != '\0') {
|
||||
int skipesc;
|
||||
|
||||
while (cp[0] != '\0' && cp[0] != esc)
|
||||
*ptr++ = *cp++;
|
||||
if (cp[0] == '\0' || cp[1] == '\0')
|
||||
break;
|
||||
|
||||
skipesc = 0;
|
||||
if (cp[1] == com)
|
||||
skipesc += (flags & FPARSELN_UNESCCOMM);
|
||||
if (cp[1] == con)
|
||||
skipesc += (flags & FPARSELN_UNESCCONT);
|
||||
if (cp[1] == esc)
|
||||
skipesc += (flags & FPARSELN_UNESCESC);
|
||||
if (cp[1] != com && cp[1] != con && cp[1] != esc)
|
||||
skipesc = (flags & FPARSELN_UNESCREST);
|
||||
|
||||
if (skipesc)
|
||||
cp++;
|
||||
else
|
||||
*ptr++ = *cp++;
|
||||
*ptr++ = *cp++;
|
||||
}
|
||||
*ptr = '\0';
|
||||
len = strlen(buf);
|
||||
}
|
||||
|
||||
if (size)
|
||||
*size = len;
|
||||
return buf;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
int main(int, char **);
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
char *ptr;
|
||||
size_t size, line;
|
||||
|
||||
line = 0;
|
||||
while ((ptr = fparseln(stdin, &size, &line, NULL,
|
||||
FPARSELN_UNESCALL)) != NULL)
|
||||
printf("line %d (%d) |%s|\n", line, size, ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
# This is a test
|
||||
line 1
|
||||
line 2 \
|
||||
line 3 # Comment
|
||||
line 4 \# Not comment \\\\
|
||||
|
||||
# And a comment \
|
||||
line 5 \\\
|
||||
line 6
|
||||
|
||||
*/
|
||||
|
||||
#endif /* TEST */
|
||||
11
configure.ac
11
configure.ac
@@ -1,6 +1,6 @@
|
||||
# configure.ac
|
||||
|
||||
AC_INIT([tmux], 2.9a)
|
||||
AC_INIT([tmux], 3.0-rc3)
|
||||
AC_PREREQ([2.60])
|
||||
|
||||
AC_CONFIG_AUX_DIR(etc)
|
||||
@@ -28,6 +28,7 @@ AC_PROG_CC_C99
|
||||
AC_PROG_CPP
|
||||
AC_PROG_EGREP
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_YACC
|
||||
PKG_PROG_PKG_CONFIG
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
|
||||
@@ -457,14 +458,6 @@ else
|
||||
AC_LIBOBJ(getopt)
|
||||
fi
|
||||
|
||||
# Look for fparseln in libutil.
|
||||
AC_SEARCH_LIBS(fparseln, util, found_fparseln=yes, found_fparseln=no)
|
||||
if test "x$found_fparseln" = xyes; then
|
||||
AC_DEFINE(HAVE_FPARSELN)
|
||||
else
|
||||
AC_LIBOBJ(fparseln)
|
||||
fi
|
||||
|
||||
# Look for fdforkpty and forkpty in libutil.
|
||||
AC_SEARCH_LIBS(fdforkpty, util, found_fdforkpty=yes, found_fdforkpty=no)
|
||||
if test "x$found_fdforkpty" = xyes; then
|
||||
|
||||
@@ -28,19 +28,14 @@
|
||||
|
||||
void
|
||||
control_notify_input(struct client *c, struct window_pane *wp,
|
||||
struct evbuffer *input)
|
||||
const u_char *buf, size_t len)
|
||||
{
|
||||
u_char *buf;
|
||||
size_t len;
|
||||
struct evbuffer *message;
|
||||
u_int i;
|
||||
|
||||
if (c->session == NULL)
|
||||
return;
|
||||
|
||||
buf = EVBUFFER_DATA(input);
|
||||
len = EVBUFFER_LENGTH(input);
|
||||
|
||||
/*
|
||||
* Only write input if the window pane is linked to a window belonging
|
||||
* to the client's session.
|
||||
|
||||
25
control.c
25
control.c
@@ -68,10 +68,9 @@ control_error(struct cmdq_item *item, void *data)
|
||||
void
|
||||
control_callback(struct client *c, int closed, __unused void *data)
|
||||
{
|
||||
char *line, *cause;
|
||||
struct cmd_list *cmdlist;
|
||||
struct cmd *cmd;
|
||||
char *line;
|
||||
struct cmdq_item *item;
|
||||
struct cmd_parse_result *pr;
|
||||
|
||||
if (closed)
|
||||
c->flags |= CLIENT_EXIT;
|
||||
@@ -85,16 +84,20 @@ control_callback(struct client *c, int closed, __unused void *data)
|
||||
break;
|
||||
}
|
||||
|
||||
cmdlist = cmd_string_parse(line, NULL, 0, &cause);
|
||||
if (cmdlist == NULL) {
|
||||
item = cmdq_get_callback(control_error, cause);
|
||||
pr = cmd_parse_from_string(line, NULL);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_EMPTY:
|
||||
break;
|
||||
case CMD_PARSE_ERROR:
|
||||
item = cmdq_get_callback(control_error, pr->error);
|
||||
cmdq_append(c, item);
|
||||
} else {
|
||||
TAILQ_FOREACH(cmd, &cmdlist->list, qentry)
|
||||
cmd->flags |= CMD_CONTROL;
|
||||
item = cmdq_get_command(cmdlist, NULL, NULL, 0);
|
||||
break;
|
||||
case CMD_PARSE_SUCCESS:
|
||||
item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
|
||||
item->shared->flags |= CMDQ_SHARED_CONTROL;
|
||||
cmdq_append(c, item);
|
||||
cmd_list_free(cmdlist);
|
||||
cmd_list_free(pr->cmdlist);
|
||||
break;
|
||||
}
|
||||
|
||||
free(line);
|
||||
|
||||
12
environ.c
12
environ.c
@@ -177,20 +177,16 @@ environ_update(struct options *oo, struct environ *src, struct environ *dst)
|
||||
struct environ_entry *envent;
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
const char *value;
|
||||
union options_value *ov;
|
||||
|
||||
o = options_get(oo, "update-environment");
|
||||
if (o == NULL)
|
||||
return;
|
||||
a = options_array_first(o);
|
||||
while (a != NULL) {
|
||||
value = options_array_item_value(a);
|
||||
if (value == NULL) {
|
||||
a = options_array_next(a);
|
||||
continue;
|
||||
}
|
||||
if ((envent = environ_find(src, value)) == NULL)
|
||||
environ_clear(dst, value);
|
||||
ov = options_array_item_value(a);
|
||||
if ((envent = environ_find(src, ov->string)) == NULL)
|
||||
environ_clear(dst, ov->string);
|
||||
else
|
||||
environ_set(dst, envent->name, "%s", envent->value);
|
||||
a = options_array_next(a);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
# Some tweaks to the status line
|
||||
set -g status-right "%H:%M"
|
||||
set -g window-status-current-attr "underscore"
|
||||
set -g window-status-current-style "underscore"
|
||||
|
||||
# If running inside tmux ($TMUX is set), then change the status line to red
|
||||
%if #{TMUX}
|
||||
|
||||
@@ -345,12 +345,6 @@ format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx,
|
||||
/* Write left at 0. */
|
||||
format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
|
||||
|
||||
/* Write after at available - width_after. */
|
||||
format_draw_put(octx, ocx, ocy, after, frs,
|
||||
available - width_after,
|
||||
after->cx - width_after,
|
||||
width_after);
|
||||
|
||||
/* Write right at available - width_right. */
|
||||
format_draw_put(octx, ocx, ocy, right, frs,
|
||||
available - width_right,
|
||||
@@ -374,10 +368,10 @@ format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx,
|
||||
|
||||
/*
|
||||
* Write after at
|
||||
* middle + width_list / 2 - width_centre.
|
||||
* middle - width_list / 2 + width_list
|
||||
*/
|
||||
format_draw_put(octx, ocx, ocy, after, frs,
|
||||
middle + width_list / 2,
|
||||
middle - width_list / 2 + width_list,
|
||||
0,
|
||||
width_after);
|
||||
|
||||
|
||||
278
format.c
278
format.c
@@ -127,6 +127,8 @@ struct format_tree {
|
||||
time_t time;
|
||||
u_int loop;
|
||||
|
||||
struct mouse_event m;
|
||||
|
||||
RB_HEAD(format_entry_tree, format_entry) tree;
|
||||
};
|
||||
static int format_entry_cmp(struct format_entry *, struct format_entry *);
|
||||
@@ -715,6 +717,121 @@ format_cb_cursor_character(struct format_tree *ft, struct format_entry *fe)
|
||||
xasprintf(&fe->value, "%.*s", (int)gc.data.size, gc.data.data);
|
||||
}
|
||||
|
||||
/* Callback for mouse_word. */
|
||||
static void
|
||||
format_cb_mouse_word(struct format_tree *ft, struct format_entry *fe)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
u_int x, y, end;
|
||||
struct grid *gd;
|
||||
struct grid_line *gl;
|
||||
struct grid_cell gc;
|
||||
const char *ws;
|
||||
struct utf8_data *ud = NULL;
|
||||
size_t size = 0;
|
||||
int found = 0;
|
||||
|
||||
if (!ft->m.valid)
|
||||
return;
|
||||
wp = cmd_mouse_pane(&ft->m, NULL, NULL);
|
||||
if (wp == NULL)
|
||||
return;
|
||||
if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
|
||||
return;
|
||||
gd = wp->base.grid;
|
||||
ws = options_get_string(global_s_options, "word-separators");
|
||||
|
||||
y = gd->hsize + y;
|
||||
for (;;) {
|
||||
grid_get_cell(gd, x, y, &gc);
|
||||
if (gc.flags & GRID_FLAG_PADDING)
|
||||
break;
|
||||
if (utf8_cstrhas(ws, &gc.data)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (x == 0) {
|
||||
if (y == 0)
|
||||
break;
|
||||
gl = &gd->linedata[y - 1];
|
||||
if (~gl->flags & GRID_LINE_WRAPPED)
|
||||
break;
|
||||
y--;
|
||||
x = grid_line_length(gd, y);
|
||||
if (x == 0)
|
||||
break;
|
||||
}
|
||||
x--;
|
||||
}
|
||||
for (;;) {
|
||||
if (found) {
|
||||
end = grid_line_length(gd, y);
|
||||
if (end == 0 || x == end - 1) {
|
||||
if (y == gd->hsize + gd->sy - 1)
|
||||
break;
|
||||
gl = &gd->linedata[y];
|
||||
if (~gl->flags & GRID_LINE_WRAPPED)
|
||||
break;
|
||||
y++;
|
||||
x = 0;
|
||||
} else
|
||||
x++;
|
||||
}
|
||||
found = 1;
|
||||
|
||||
grid_get_cell(gd, x, y, &gc);
|
||||
if (gc.flags & GRID_FLAG_PADDING)
|
||||
break;
|
||||
if (utf8_cstrhas(ws, &gc.data))
|
||||
break;
|
||||
|
||||
ud = xreallocarray(ud, size + 2, sizeof *ud);
|
||||
memcpy(&ud[size++], &gc.data, sizeof *ud);
|
||||
}
|
||||
if (size != 0) {
|
||||
ud[size].size = 0;
|
||||
fe->value = utf8_tocstr(ud);
|
||||
free(ud);
|
||||
}
|
||||
}
|
||||
|
||||
/* Callback for mouse_line. */
|
||||
static void
|
||||
format_cb_mouse_line(struct format_tree *ft, struct format_entry *fe)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
u_int x, y;
|
||||
struct grid *gd;
|
||||
struct grid_cell gc;
|
||||
struct utf8_data *ud = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
if (!ft->m.valid)
|
||||
return;
|
||||
wp = cmd_mouse_pane(&ft->m, NULL, NULL);
|
||||
if (wp == NULL)
|
||||
return;
|
||||
if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
|
||||
return;
|
||||
gd = wp->base.grid;
|
||||
|
||||
y = gd->hsize + y;
|
||||
for (x = 0; x < grid_line_length(gd, y); x++) {
|
||||
grid_get_cell(gd, x, y, &gc);
|
||||
if (gc.flags & GRID_FLAG_PADDING)
|
||||
break;
|
||||
|
||||
ud = xreallocarray(ud, size + 2, sizeof *ud);
|
||||
memcpy(&ud[size++], &gc.data, sizeof *ud);
|
||||
}
|
||||
if (size != 0) {
|
||||
ud[size].size = 0;
|
||||
fe->value = utf8_tocstr(ud);
|
||||
free(ud);
|
||||
}
|
||||
}
|
||||
|
||||
/* Merge a format tree. */
|
||||
static void
|
||||
format_merge(struct format_tree *ft, struct format_tree *from)
|
||||
@@ -727,6 +844,35 @@ format_merge(struct format_tree *ft, struct format_tree *from)
|
||||
}
|
||||
}
|
||||
|
||||
/* Add item bits to tree. */
|
||||
static void
|
||||
format_create_add_item(struct format_tree *ft, struct cmdq_item *item)
|
||||
{
|
||||
struct mouse_event *m;
|
||||
struct window_pane *wp;
|
||||
u_int x, y;
|
||||
|
||||
if (item->cmd != NULL)
|
||||
format_add(ft, "command", "%s", item->cmd->entry->name);
|
||||
|
||||
if (item->shared == NULL)
|
||||
return;
|
||||
if (item->shared->formats != NULL)
|
||||
format_merge(ft, item->shared->formats);
|
||||
|
||||
m = &item->shared->mouse;
|
||||
if (m->valid && ((wp = cmd_mouse_pane(m, NULL, NULL)) != NULL)) {
|
||||
format_add(ft, "mouse_pane", "%%%u", wp->id);
|
||||
if (cmd_mouse_at(wp, m, &x, &y, 0) == 0) {
|
||||
format_add(ft, "mouse_x", "%u", x);
|
||||
format_add(ft, "mouse_y", "%u", y);
|
||||
format_add_cb(ft, "mouse_word", format_cb_mouse_word);
|
||||
format_add_cb(ft, "mouse_line", format_cb_mouse_line);
|
||||
}
|
||||
}
|
||||
memcpy(&ft->m, m, sizeof ft->m);
|
||||
}
|
||||
|
||||
/* Create a new tree. */
|
||||
struct format_tree *
|
||||
format_create(struct client *c, struct cmdq_item *item, int tag, int flags)
|
||||
@@ -768,12 +914,8 @@ format_create(struct client *c, struct cmdq_item *item, int tag, int flags)
|
||||
}
|
||||
}
|
||||
|
||||
if (item != NULL) {
|
||||
if (item->cmd != NULL)
|
||||
format_add(ft, "command", "%s", item->cmd->entry->name);
|
||||
if (item->shared != NULL && item->shared->formats != NULL)
|
||||
format_merge(ft, item->shared->formats);
|
||||
}
|
||||
if (item != NULL)
|
||||
format_create_add_item(ft, item);
|
||||
|
||||
return (ft);
|
||||
}
|
||||
@@ -920,9 +1062,8 @@ format_find(struct format_tree *ft, const char *key, int modifiers)
|
||||
struct environ_entry *envent;
|
||||
static char s[64];
|
||||
struct options_entry *o;
|
||||
const char *found;
|
||||
int idx;
|
||||
char *copy, *saved;
|
||||
char *found, *saved;
|
||||
|
||||
if (~modifiers & FORMAT_TIMESTRING) {
|
||||
o = options_parse_get(global_options, key, &idx, 0);
|
||||
@@ -949,12 +1090,11 @@ format_find(struct format_tree *ft, const char *key, int modifiers)
|
||||
return (NULL);
|
||||
ctime_r(&fe->t, s);
|
||||
s[strcspn(s, "\n")] = '\0';
|
||||
found = s;
|
||||
found = xstrdup(s);
|
||||
goto found;
|
||||
}
|
||||
if (fe->t != 0) {
|
||||
xsnprintf(s, sizeof s, "%lld", (long long)fe->t);
|
||||
found = s;
|
||||
xasprintf(&found, "%lld", (long long)fe->t);
|
||||
goto found;
|
||||
}
|
||||
if (fe->value == NULL && fe->cb != NULL) {
|
||||
@@ -962,7 +1102,7 @@ format_find(struct format_tree *ft, const char *key, int modifiers)
|
||||
if (fe->value == NULL)
|
||||
fe->value = xstrdup("");
|
||||
}
|
||||
found = fe->value;
|
||||
found = xstrdup(fe->value);
|
||||
goto found;
|
||||
}
|
||||
|
||||
@@ -972,8 +1112,8 @@ format_find(struct format_tree *ft, const char *key, int modifiers)
|
||||
envent = environ_find(ft->s->environ, key);
|
||||
if (envent == NULL)
|
||||
envent = environ_find(global_environ, key);
|
||||
if (envent != NULL) {
|
||||
found = envent->value;
|
||||
if (envent != NULL && envent->value != NULL) {
|
||||
found = xstrdup(envent->value);
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
@@ -983,23 +1123,22 @@ format_find(struct format_tree *ft, const char *key, int modifiers)
|
||||
found:
|
||||
if (found == NULL)
|
||||
return (NULL);
|
||||
copy = xstrdup(found);
|
||||
if (modifiers & FORMAT_BASENAME) {
|
||||
saved = copy;
|
||||
copy = xstrdup(basename(saved));
|
||||
saved = found;
|
||||
found = xstrdup(basename(saved));
|
||||
free(saved);
|
||||
}
|
||||
if (modifiers & FORMAT_DIRNAME) {
|
||||
saved = copy;
|
||||
copy = xstrdup(dirname(saved));
|
||||
saved = found;
|
||||
found = xstrdup(dirname(saved));
|
||||
free(saved);
|
||||
}
|
||||
if (modifiers & FORMAT_QUOTE) {
|
||||
saved = copy;
|
||||
copy = xstrdup(format_quote(saved));
|
||||
saved = found;
|
||||
found = xstrdup(format_quote(saved));
|
||||
free(saved);
|
||||
}
|
||||
return (copy);
|
||||
return (found);
|
||||
}
|
||||
|
||||
/* Skip until end. */
|
||||
@@ -1107,13 +1246,13 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
|
||||
|
||||
/*
|
||||
* Modifiers are a ; separated list of the forms:
|
||||
* l,m,C,b,d,t,q,E,T,S,W,P
|
||||
* l,m,C,b,d,t,q,E,T,S,W,P,<,>
|
||||
* =a
|
||||
* =/a
|
||||
* =/a/
|
||||
* s/a/b/
|
||||
* s/a/b
|
||||
* ||,&&,!=,==
|
||||
* ||,&&,!=,==,<=,>=
|
||||
*/
|
||||
|
||||
*count = 0;
|
||||
@@ -1124,7 +1263,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
|
||||
cp++;
|
||||
|
||||
/* Check single character modifiers with no arguments. */
|
||||
if (strchr("lmCbdtqETSWP", cp[0]) != NULL &&
|
||||
if (strchr("lmCbdtqETSWP<>", cp[0]) != NULL &&
|
||||
format_is_end(cp[1])) {
|
||||
format_add_modifier(&list, count, cp, 1, NULL, 0);
|
||||
cp++;
|
||||
@@ -1135,7 +1274,9 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
|
||||
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) &&
|
||||
format_is_end(cp[2])) {
|
||||
format_add_modifier(&list, count, cp, 2, NULL, 0);
|
||||
cp += 2;
|
||||
@@ -1377,7 +1518,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
||||
char **buf, size_t *len, size_t *off)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
const char *errptr, *copy, *cp;
|
||||
const char *errptr, *copy, *cp, *marker = NULL;
|
||||
char *copy0, *condition, *found, *new;
|
||||
char *value, *left, *right;
|
||||
size_t valuelen;
|
||||
@@ -1404,6 +1545,8 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
||||
if (fm->size == 1) {
|
||||
switch (fm->modifier[0]) {
|
||||
case 'm':
|
||||
case '<':
|
||||
case '>':
|
||||
cmp = fm;
|
||||
break;
|
||||
case 'C':
|
||||
@@ -1415,12 +1558,14 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
||||
sub = fm;
|
||||
break;
|
||||
case '=':
|
||||
if (fm->argc != 1)
|
||||
if (fm->argc != 1 && fm->argc != 2)
|
||||
break;
|
||||
limit = strtonum(fm->argv[0], INT_MIN, INT_MAX,
|
||||
&errptr);
|
||||
if (errptr != NULL)
|
||||
limit = 0;
|
||||
if (fm->argc == 2 && fm->argv[1] != NULL)
|
||||
marker = fm->argv[1];
|
||||
break;
|
||||
case 'l':
|
||||
modifiers |= FORMAT_LITERAL;
|
||||
@@ -1457,7 +1602,9 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
||||
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)
|
||||
cmp = fm;
|
||||
}
|
||||
}
|
||||
@@ -1520,8 +1667,27 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
||||
value = xstrdup("1");
|
||||
else
|
||||
value = xstrdup("0");
|
||||
}
|
||||
else if (strcmp(cmp->modifier, "m") == 0) {
|
||||
} else if (strcmp(cmp->modifier, "<") == 0) {
|
||||
if (strcmp(left, right) < 0)
|
||||
value = xstrdup("1");
|
||||
else
|
||||
value = xstrdup("0");
|
||||
} else if (strcmp(cmp->modifier, ">") == 0) {
|
||||
if (strcmp(left, right) > 0)
|
||||
value = xstrdup("1");
|
||||
else
|
||||
value = xstrdup("0");
|
||||
} else if (strcmp(cmp->modifier, "<=") == 0) {
|
||||
if (strcmp(left, right) <= 0)
|
||||
value = xstrdup("1");
|
||||
else
|
||||
value = xstrdup("0");
|
||||
} else if (strcmp(cmp->modifier, ">=") == 0) {
|
||||
if (strcmp(left, right) >= 0)
|
||||
value = xstrdup("1");
|
||||
else
|
||||
value = xstrdup("0");
|
||||
} else if (strcmp(cmp->modifier, "m") == 0) {
|
||||
if (fnmatch(left, right, 0) == 0)
|
||||
value = xstrdup("1");
|
||||
else
|
||||
@@ -1614,14 +1780,24 @@ done:
|
||||
/* Truncate the value if needed. */
|
||||
if (limit > 0) {
|
||||
new = format_trim_left(value, limit);
|
||||
format_log(ft, "applied length limit %d: %s", limit, new);
|
||||
free(value);
|
||||
value = new;
|
||||
if (marker != NULL && strcmp(new, value) != 0) {
|
||||
free(value);
|
||||
xasprintf(&value, "%s%s", new, marker);
|
||||
} else {
|
||||
free(value);
|
||||
value = new;
|
||||
}
|
||||
format_log(ft, "applied length limit %d: %s", limit, value);
|
||||
} else if (limit < 0) {
|
||||
new = format_trim_right(value, -limit);
|
||||
format_log(ft, "applied length limit %d: %s", limit, new);
|
||||
free(value);
|
||||
value = new;
|
||||
if (marker != NULL && strcmp(new, value) != 0) {
|
||||
free(value);
|
||||
xasprintf(&value, "%s%s", marker, new);
|
||||
} else {
|
||||
free(value);
|
||||
value = new;
|
||||
}
|
||||
format_log(ft, "applied length limit %d: %s", limit, value);
|
||||
}
|
||||
|
||||
/* Expand the buffer and copy in the value. */
|
||||
@@ -1822,6 +1998,23 @@ void
|
||||
format_defaults(struct format_tree *ft, struct client *c, struct session *s,
|
||||
struct winlink *wl, struct window_pane *wp)
|
||||
{
|
||||
if (c != NULL)
|
||||
log_debug("%s: c=%s", __func__, c->name);
|
||||
else
|
||||
log_debug("%s: s=none", __func__);
|
||||
if (s != NULL)
|
||||
log_debug("%s: s=$%u", __func__, s->id);
|
||||
else
|
||||
log_debug("%s: s=none", __func__);
|
||||
if (wl != NULL)
|
||||
log_debug("%s: wl=%u w=@%u", __func__, wl->idx, wl->window->id);
|
||||
else
|
||||
log_debug("%s: wl=none", __func__);
|
||||
if (wp != NULL)
|
||||
log_debug("%s: wp=%%%u", __func__, wp->id);
|
||||
else
|
||||
log_debug("%s: wp=none", __func__);
|
||||
|
||||
if (c != NULL && s != NULL && c->session != s)
|
||||
log_debug("%s: session does not match", __func__);
|
||||
|
||||
@@ -2033,7 +2226,16 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
|
||||
|
||||
if ((wp->flags & PANE_STATUSREADY) && WIFEXITED(status))
|
||||
format_add(ft, "pane_dead_status", "%d", WEXITSTATUS(status));
|
||||
format_add(ft, "pane_dead", "%d", wp->fd == -1);
|
||||
if (~wp->flags & PANE_EMPTY)
|
||||
format_add(ft, "pane_dead", "%d", wp->fd == -1);
|
||||
else
|
||||
format_add(ft, "pane_dead", "0");
|
||||
|
||||
if (server_check_marked() && marked_pane.wp == wp)
|
||||
format_add(ft, "pane_marked", "1");
|
||||
else
|
||||
format_add(ft, "pane_marked", "0");
|
||||
format_add(ft, "pane_marked_set", "%d", server_check_marked());
|
||||
|
||||
format_add(ft, "pane_left", "%u", wp->xoff);
|
||||
format_add(ft, "pane_top", "%u", wp->yoff);
|
||||
|
||||
20
grid.c
20
grid.c
@@ -790,6 +790,7 @@ grid_string_cells_code(const struct grid_cell *lastgc,
|
||||
{ GRID_ATTR_UNDERSCORE_3, 43 },
|
||||
{ GRID_ATTR_UNDERSCORE_4, 44 },
|
||||
{ GRID_ATTR_UNDERSCORE_5, 45 },
|
||||
{ GRID_ATTR_OVERLINE, 53 },
|
||||
};
|
||||
n = 0;
|
||||
|
||||
@@ -1349,3 +1350,22 @@ grid_unwrap_position(struct grid *gd, u_int *px, u_int *py, u_int wx, u_int wy)
|
||||
*px = wx;
|
||||
*py = yy;
|
||||
}
|
||||
|
||||
/* Get length of line. */
|
||||
u_int
|
||||
grid_line_length(struct grid *gd, u_int py)
|
||||
{
|
||||
struct grid_cell gc;
|
||||
u_int px;
|
||||
|
||||
px = grid_get_line(gd, py)->cellsize;
|
||||
if (px > gd->sx)
|
||||
px = gd->sx;
|
||||
while (px > 0) {
|
||||
grid_get_cell(gd, px - 1, py, &gc);
|
||||
if (gc.data.size != 1 || *gc.data.data != ' ')
|
||||
break;
|
||||
px--;
|
||||
}
|
||||
return (px);
|
||||
}
|
||||
|
||||
173
hooks.c
173
hooks.c
@@ -1,173 +0,0 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
struct hooks {
|
||||
RB_HEAD(hooks_tree, hook) tree;
|
||||
struct hooks *parent;
|
||||
};
|
||||
|
||||
static int hooks_cmp(struct hook *, struct hook *);
|
||||
RB_GENERATE_STATIC(hooks_tree, hook, entry, hooks_cmp);
|
||||
|
||||
static struct hook *hooks_find1(struct hooks *, const char *);
|
||||
static void hooks_free1(struct hooks *, struct hook *);
|
||||
|
||||
static int
|
||||
hooks_cmp(struct hook *hook1, struct hook *hook2)
|
||||
{
|
||||
return (strcmp(hook1->name, hook2->name));
|
||||
}
|
||||
|
||||
struct hooks *
|
||||
hooks_get(struct session *s)
|
||||
{
|
||||
if (s != NULL)
|
||||
return (s->hooks);
|
||||
return (global_hooks);
|
||||
}
|
||||
|
||||
struct hooks *
|
||||
hooks_create(struct hooks *parent)
|
||||
{
|
||||
struct hooks *hooks;
|
||||
|
||||
hooks = xcalloc(1, sizeof *hooks);
|
||||
RB_INIT(&hooks->tree);
|
||||
hooks->parent = parent;
|
||||
return (hooks);
|
||||
}
|
||||
|
||||
static void
|
||||
hooks_free1(struct hooks *hooks, struct hook *hook)
|
||||
{
|
||||
RB_REMOVE(hooks_tree, &hooks->tree, hook);
|
||||
cmd_list_free(hook->cmdlist);
|
||||
free((char *)hook->name);
|
||||
free(hook);
|
||||
}
|
||||
|
||||
void
|
||||
hooks_free(struct hooks *hooks)
|
||||
{
|
||||
struct hook *hook, *hook1;
|
||||
|
||||
RB_FOREACH_SAFE(hook, hooks_tree, &hooks->tree, hook1)
|
||||
hooks_free1(hooks, hook);
|
||||
free(hooks);
|
||||
}
|
||||
|
||||
struct hook *
|
||||
hooks_first(struct hooks *hooks)
|
||||
{
|
||||
return (RB_MIN(hooks_tree, &hooks->tree));
|
||||
}
|
||||
|
||||
struct hook *
|
||||
hooks_next(struct hook *hook)
|
||||
{
|
||||
return (RB_NEXT(hooks_tree, &hooks->tree, hook));
|
||||
}
|
||||
|
||||
void
|
||||
hooks_add(struct hooks *hooks, const char *name, struct cmd_list *cmdlist)
|
||||
{
|
||||
struct hook *hook;
|
||||
|
||||
if ((hook = hooks_find1(hooks, name)) != NULL)
|
||||
hooks_free1(hooks, hook);
|
||||
|
||||
hook = xcalloc(1, sizeof *hook);
|
||||
hook->name = xstrdup(name);
|
||||
hook->cmdlist = cmdlist;
|
||||
hook->cmdlist->references++;
|
||||
RB_INSERT(hooks_tree, &hooks->tree, hook);
|
||||
}
|
||||
|
||||
void
|
||||
hooks_remove(struct hooks *hooks, const char *name)
|
||||
{
|
||||
struct hook *hook;
|
||||
|
||||
if ((hook = hooks_find1(hooks, name)) != NULL)
|
||||
hooks_free1(hooks, hook);
|
||||
}
|
||||
|
||||
static struct hook *
|
||||
hooks_find1(struct hooks *hooks, const char *name)
|
||||
{
|
||||
struct hook hook;
|
||||
|
||||
hook.name = name;
|
||||
return (RB_FIND(hooks_tree, &hooks->tree, &hook));
|
||||
}
|
||||
|
||||
struct hook *
|
||||
hooks_find(struct hooks *hooks, const char *name)
|
||||
{
|
||||
struct hook hook0, *hook;
|
||||
|
||||
hook0.name = name;
|
||||
hook = RB_FIND(hooks_tree, &hooks->tree, &hook0);
|
||||
while (hook == NULL) {
|
||||
hooks = hooks->parent;
|
||||
if (hooks == NULL)
|
||||
break;
|
||||
hook = RB_FIND(hooks_tree, &hooks->tree, &hook0);
|
||||
}
|
||||
return (hook);
|
||||
}
|
||||
|
||||
void
|
||||
hooks_insert(struct hooks *hooks, struct cmdq_item *item,
|
||||
struct cmd_find_state *fs, const char *fmt, ...)
|
||||
{
|
||||
struct hook *hook;
|
||||
va_list ap;
|
||||
char *name;
|
||||
struct cmdq_item *new_item;
|
||||
|
||||
if (item->flags & CMDQ_NOHOOKS)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&name, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
hook = hooks_find(hooks, name);
|
||||
if (hook == NULL) {
|
||||
free(name);
|
||||
return;
|
||||
}
|
||||
log_debug("running hook %s (parent %p)", name, item);
|
||||
|
||||
new_item = cmdq_get_command(hook->cmdlist, fs, NULL, CMDQ_NOHOOKS);
|
||||
cmdq_format(new_item, "hook", "%s", name);
|
||||
if (item != NULL)
|
||||
cmdq_insert_after(item, new_item);
|
||||
else
|
||||
cmdq_append(NULL, new_item);
|
||||
|
||||
free(name);
|
||||
}
|
||||
59
input.c
59
input.c
@@ -873,19 +873,28 @@ input_set_state(struct window_pane *wp, const struct input_transition *itr)
|
||||
/* Parse input. */
|
||||
void
|
||||
input_parse(struct window_pane *wp)
|
||||
{
|
||||
struct evbuffer *evb = wp->event->input;
|
||||
|
||||
input_parse_buffer(wp, EVBUFFER_DATA(evb), EVBUFFER_LENGTH(evb));
|
||||
evbuffer_drain(evb, EVBUFFER_LENGTH(evb));
|
||||
}
|
||||
|
||||
/* Parse given input. */
|
||||
void
|
||||
input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
|
||||
{
|
||||
struct input_ctx *ictx = wp->ictx;
|
||||
struct screen_write_ctx *sctx = &ictx->ctx;
|
||||
const struct input_transition *itr;
|
||||
struct evbuffer *evb = wp->event->input;
|
||||
u_char *buf;
|
||||
size_t len, off;
|
||||
size_t off = 0;
|
||||
|
||||
if (EVBUFFER_LENGTH(evb) == 0)
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
window_update_activity(wp->window);
|
||||
wp->flags |= PANE_CHANGED;
|
||||
notify_input(wp, buf, len);
|
||||
|
||||
/*
|
||||
* Open the screen. Use NULL wp if there is a mode set as don't want to
|
||||
@@ -897,12 +906,6 @@ input_parse(struct window_pane *wp)
|
||||
screen_write_start(sctx, NULL, &wp->base);
|
||||
ictx->wp = wp;
|
||||
|
||||
buf = EVBUFFER_DATA(evb);
|
||||
len = EVBUFFER_LENGTH(evb);
|
||||
off = 0;
|
||||
|
||||
notify_input(wp, evb);
|
||||
|
||||
log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
|
||||
ictx->state->name, len, (int)len, buf);
|
||||
|
||||
@@ -950,8 +953,6 @@ input_parse(struct window_pane *wp)
|
||||
|
||||
/* Close the screen. */
|
||||
screen_write_stop(sctx);
|
||||
|
||||
evbuffer_drain(evb, len);
|
||||
}
|
||||
|
||||
/* Split the parameter list (if any). */
|
||||
@@ -1185,6 +1186,8 @@ input_c0_dispatch(struct input_ctx *ictx)
|
||||
case '\013': /* VT */
|
||||
case '\014': /* FF */
|
||||
screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
|
||||
if (s->mode & MODE_CRLF)
|
||||
screen_write_carriagereturn(sctx);
|
||||
break;
|
||||
case '\015': /* CR */
|
||||
screen_write_carriagereturn(sctx);
|
||||
@@ -1935,23 +1938,25 @@ input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (p[0] != 38 && p[0] != 48)
|
||||
if (n < 2 || (p[0] != 38 && p[0] != 48))
|
||||
return;
|
||||
if (p[1] == -1)
|
||||
i = 2;
|
||||
else
|
||||
i = 1;
|
||||
switch (p[i]) {
|
||||
switch (p[1]) {
|
||||
case 2:
|
||||
if (n < i + 4)
|
||||
if (n < 3)
|
||||
break;
|
||||
input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[i + 1], p[i + 2],
|
||||
p[i + 3]);
|
||||
if (n == 5)
|
||||
i = 2;
|
||||
else
|
||||
i = 3;
|
||||
if (n < i + 3)
|
||||
break;
|
||||
input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[i], p[i + 1],
|
||||
p[i + 2]);
|
||||
break;
|
||||
case 5:
|
||||
if (n < i + 2)
|
||||
if (n < 3)
|
||||
break;
|
||||
input_csi_dispatch_sgr_256_do(ictx, p[0], p[i + 1]);
|
||||
input_csi_dispatch_sgr_256_do(ictx, p[0], p[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2067,6 +2072,12 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
|
||||
case 49:
|
||||
gc->bg = 8;
|
||||
break;
|
||||
case 53:
|
||||
gc->attr |= GRID_ATTR_OVERLINE;
|
||||
break;
|
||||
case 55:
|
||||
gc->attr &= ~GRID_ATTR_OVERLINE;
|
||||
break;
|
||||
case 90:
|
||||
case 91:
|
||||
case 92:
|
||||
@@ -2432,7 +2443,7 @@ input_osc_52(struct input_ctx *ictx, const char *p)
|
||||
screen_write_stop(&ctx);
|
||||
notify_pane("pane-set-clipboard", wp);
|
||||
|
||||
paste_add(out, outlen);
|
||||
paste_add(NULL, out, outlen);
|
||||
}
|
||||
|
||||
/* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
|
||||
|
||||
@@ -24,6 +24,52 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
#define DEFAULT_CLIENT_MENU \
|
||||
" 'Detach' 'd' {detach-client}" \
|
||||
" 'Detach & Kill' 'X' {detach-client -P}" \
|
||||
" 'Detach Others' 'o' {detach-client -a}" \
|
||||
" ''" \
|
||||
" 'Lock' 'l' {lock-client}"
|
||||
#define DEFAULT_SESSION_MENU \
|
||||
" 'Next' 'n' {switch-client -n}" \
|
||||
" 'Previous' 'p' {switch-client -p}" \
|
||||
" ''" \
|
||||
" 'Renumber' 'N' {move-window -r}" \
|
||||
" 'Rename' 'n' {command-prompt -I \"#S\" \"rename-session -- '%%'\"}" \
|
||||
" ''" \
|
||||
" 'New Session' 's' {new-session}" \
|
||||
" 'New Window' 'w' {new-window}"
|
||||
#define DEFAULT_WINDOW_MENU \
|
||||
" 'Swap Left' 'l' {swap-window -t:-1}" \
|
||||
" 'Swap Right' 'r' {swap-window -t:+1}" \
|
||||
" '#{?pane_marked_set,,-}Swap Marked' 's' {swap-window}" \
|
||||
" ''" \
|
||||
" 'Kill' 'X' {kill-window}" \
|
||||
" 'Respawn' 'R' {respawn-window -k}" \
|
||||
" '#{?pane_marked,Unmark,Mark}' 'm' {select-pane -m}" \
|
||||
" 'Rename' 'n' {command-prompt -I \"#W\" \"rename-window -- '%%'\"}" \
|
||||
" ''" \
|
||||
" 'New After' 'w' {new-window -a}" \
|
||||
" 'New At End' 'W' {new-window}"
|
||||
#define DEFAULT_PANE_MENU \
|
||||
" '#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}' 'C-r' {copy-mode -t=; send -Xt= search-backward \"#{q:mouse_word}\"}" \
|
||||
" '#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}' 'C-y' {send-keys -l -- \"#{q:mouse_word}\"}" \
|
||||
" '#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}' 'c' {set-buffer -- \"#{q:mouse_word}\"}" \
|
||||
" '#{?mouse_line,Copy Line,}' 'l' {set-buffer -- \"#{q:mouse_line}\"}" \
|
||||
" ''" \
|
||||
" 'Horizontal Split' 'h' {split-window -h}" \
|
||||
" 'Vertical Split' 'v' {split-window -v}" \
|
||||
" ''" \
|
||||
" 'Swap Up' 'u' {swap-pane -U}" \
|
||||
" 'Swap Down' 'd' {swap-pane -D}" \
|
||||
" '#{?pane_marked_set,,-}Swap Marked' 's' {swap-pane}" \
|
||||
" ''" \
|
||||
" 'Kill' 'X' {kill-pane}" \
|
||||
" 'Respawn' 'R' {respawn-pane -k}" \
|
||||
" '#{?pane_marked,Unmark,Mark}' 'm' {select-pane -m}" \
|
||||
" '#{?window_zoomed_flag,Unzoom,Zoom}' 'z' {resize-pane -Z}"
|
||||
|
||||
|
||||
static int key_bindings_cmp(struct key_binding *, struct key_binding *);
|
||||
RB_GENERATE_STATIC(key_bindings, key_binding, entry, key_bindings_cmp);
|
||||
static int key_table_cmp(struct key_table *, struct key_table *);
|
||||
@@ -242,8 +288,8 @@ key_bindings_init(void)
|
||||
"bind w choose-tree -Zw",
|
||||
"bind x confirm-before -p\"kill-pane #P? (y/n)\" kill-pane",
|
||||
"bind z resize-pane -Z",
|
||||
"bind { swap-pane -U",
|
||||
"bind } swap-pane -D",
|
||||
"bind '{' swap-pane -U",
|
||||
"bind '}' swap-pane -D",
|
||||
"bind '~' show-messages",
|
||||
"bind PPage copy-mode -u",
|
||||
"bind -r Up select-pane -U",
|
||||
@@ -271,14 +317,22 @@ key_bindings_init(void)
|
||||
"bind -r C-Down resize-pane -D",
|
||||
"bind -r C-Left resize-pane -L",
|
||||
"bind -r C-Right resize-pane -R",
|
||||
|
||||
"bind -n MouseDown1Pane select-pane -t=\\; send-keys -M",
|
||||
"bind -n MouseDrag1Border resize-pane -M",
|
||||
"bind -n MouseDown1Status select-window -t=",
|
||||
"bind -n WheelDownStatus next-window",
|
||||
"bind -n WheelUpStatus previous-window",
|
||||
"bind -n MouseDrag1Pane if -Ft= '#{mouse_any_flag}' 'if -Ft= \"#{pane_in_mode}\" \"copy-mode -M\" \"send-keys -M\"' 'copy-mode -M'",
|
||||
"bind -n MouseDown3Pane if-shell -Ft= '#{mouse_any_flag}' 'select-pane -t=; send-keys -M' 'select-pane -mt='",
|
||||
"bind -n WheelUpPane if-shell -Ft= '#{mouse_any_flag}' 'send-keys -M' 'if -Ft= \"#{pane_in_mode}\" \"send-keys -M\" \"copy-mode -et=\"'",
|
||||
"bind -n WheelUpPane if -Ft= '#{mouse_any_flag}' 'send-keys -M' 'if -Ft= \"#{pane_in_mode}\" \"send-keys -M\" \"copy-mode -et=\"'",
|
||||
|
||||
"bind -n MouseDown3StatusRight display-menu -t= -xM -yS -T \"#[align=centre]#{client_name}\" " DEFAULT_CLIENT_MENU,
|
||||
"bind -n MouseDown3StatusLeft display-menu -t= -xM -yS -T \"#[align=centre]#{session_name}\" " DEFAULT_SESSION_MENU,
|
||||
"bind -n MouseDown3Status display-menu -t= -xW -yS -T \"#[align=centre]#{window_index}:#{window_name}\" " DEFAULT_WINDOW_MENU,
|
||||
"bind C-m display-menu -xW -yS -T \"#[align=centre]#{window_index}:#{window_name}\" " DEFAULT_WINDOW_MENU,
|
||||
"bind -n MouseDown3Pane if -Ft= '#{||:#{mouse_any_flag},#{pane_in_mode}}' 'select-pane -t=; send-keys -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 M-m display-menu -xP -yP -T \"#[align=centre]#{pane_index} (#{pane_id})\" " DEFAULT_PANE_MENU,
|
||||
|
||||
"bind -Tcopy-mode C-Space send -X begin-selection",
|
||||
"bind -Tcopy-mode C-a send -X start-of-line",
|
||||
@@ -335,13 +389,15 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode M-> send -X history-bottom",
|
||||
"bind -Tcopy-mode M-R send -X top-line",
|
||||
"bind -Tcopy-mode M-b send -X previous-word",
|
||||
"bind -Tcopy-mode C-M-b send -X previous-matching-bracket",
|
||||
"bind -Tcopy-mode M-f send -X next-word-end",
|
||||
"bind -Tcopy-mode C-M-f send -X next-matching-bracket",
|
||||
"bind -Tcopy-mode M-m send -X back-to-indentation",
|
||||
"bind -Tcopy-mode M-r send -X middle-line",
|
||||
"bind -Tcopy-mode M-v send -X page-up",
|
||||
"bind -Tcopy-mode M-w send -X copy-selection-and-cancel",
|
||||
"bind -Tcopy-mode M-{ send -X previous-paragraph",
|
||||
"bind -Tcopy-mode M-} send -X next-paragraph",
|
||||
"bind -Tcopy-mode 'M-{' send -X previous-paragraph",
|
||||
"bind -Tcopy-mode 'M-}' send -X next-paragraph",
|
||||
"bind -Tcopy-mode M-Up send -X halfpage-up",
|
||||
"bind -Tcopy-mode M-Down send -X halfpage-down",
|
||||
"bind -Tcopy-mode C-Up send -X scroll-up",
|
||||
@@ -406,8 +462,9 @@ key_bindings_init(void)
|
||||
"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 w send -X next-word",
|
||||
"bind -Tcopy-mode-vi { send -X previous-paragraph",
|
||||
"bind -Tcopy-mode-vi } send -X next-paragraph",
|
||||
"bind -Tcopy-mode-vi '{' send -X previous-paragraph",
|
||||
"bind -Tcopy-mode-vi '}' send -X next-paragraph",
|
||||
"bind -Tcopy-mode-vi % send -X next-matching-bracket",
|
||||
"bind -Tcopy-mode-vi MouseDown1Pane select-pane",
|
||||
"bind -Tcopy-mode-vi MouseDrag1Pane select-pane\\; send -X begin-selection",
|
||||
"bind -Tcopy-mode-vi MouseDragEnd1Pane send -X copy-selection-and-cancel",
|
||||
@@ -425,16 +482,15 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode-vi C-Up send -X scroll-up",
|
||||
"bind -Tcopy-mode-vi C-Down send -X scroll-down",
|
||||
};
|
||||
u_int i;
|
||||
struct cmd_list *cmdlist;
|
||||
char *cause;
|
||||
u_int i;
|
||||
struct cmd_parse_result *pr;
|
||||
|
||||
for (i = 0; i < nitems(defaults); i++) {
|
||||
cmdlist = cmd_string_parse(defaults[i], "<default>", i, &cause);
|
||||
if (cmdlist == NULL)
|
||||
pr = cmd_parse_from_string(defaults[i], NULL);
|
||||
if (pr->status != CMD_PARSE_SUCCESS)
|
||||
fatalx("bad default key: %s", defaults[i]);
|
||||
cmdq_append(NULL, cmdq_get_command(cmdlist, NULL, NULL, 0));
|
||||
cmd_list_free(cmdlist);
|
||||
cmdq_append(NULL, cmdq_get_command(pr->cmdlist, NULL, NULL, 0));
|
||||
cmd_list_free(pr->cmdlist);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,7 +501,7 @@ key_bindings_read_only(struct cmdq_item *item, __unused void *data)
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
void
|
||||
struct cmdq_item *
|
||||
key_bindings_dispatch(struct key_binding *bd, struct cmdq_item *item,
|
||||
struct client *c, struct mouse_event *m, struct cmd_find_state *fs)
|
||||
{
|
||||
@@ -469,4 +525,5 @@ key_bindings_dispatch(struct key_binding *bd, struct cmdq_item *item,
|
||||
cmdq_insert_after(item, new_item);
|
||||
else
|
||||
cmdq_append(c, new_item);
|
||||
return (new_item);
|
||||
}
|
||||
|
||||
42
layout-set.c
42
layout-set.c
@@ -185,7 +185,7 @@ layout_set_main_h(struct window *w)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
struct layout_cell *lc, *lcmain, *lcother, *lcchild;
|
||||
u_int n, mainh, otherh, sx;
|
||||
u_int n, mainh, otherh, sx, sy;
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
@@ -195,22 +195,25 @@ layout_set_main_h(struct window *w)
|
||||
return;
|
||||
n--; /* take off main pane */
|
||||
|
||||
/* Find available height - take off one line for the border. */
|
||||
sy = w->sy - 1;
|
||||
|
||||
/* Get the main pane height and work out the other pane height. */
|
||||
mainh = options_get_number(w->options, "main-pane-height");
|
||||
if (mainh + PANE_MINIMUM + 1 >= w->sy) {
|
||||
if (w->sy <= PANE_MINIMUM + 1 + PANE_MINIMUM)
|
||||
if (mainh + PANE_MINIMUM >= sy) {
|
||||
if (sy <= PANE_MINIMUM + PANE_MINIMUM)
|
||||
mainh = PANE_MINIMUM;
|
||||
else
|
||||
mainh = w->sy - (PANE_MINIMUM + 1);
|
||||
mainh = sy - PANE_MINIMUM;
|
||||
otherh = PANE_MINIMUM;
|
||||
} else {
|
||||
otherh = options_get_number(w->options, "other-pane-height");
|
||||
if (otherh == 0)
|
||||
otherh = w->sy - mainh;
|
||||
else if (otherh > w->sy || w->sy - otherh < mainh)
|
||||
otherh = w->sy - mainh;
|
||||
otherh = sy - mainh;
|
||||
else if (otherh > sy || sy - otherh < mainh)
|
||||
otherh = sy - mainh;
|
||||
else
|
||||
mainh = w->sy - otherh;
|
||||
mainh = sy - otherh;
|
||||
}
|
||||
|
||||
/* Work out what width is needed. */
|
||||
@@ -221,7 +224,7 @@ layout_set_main_h(struct window *w)
|
||||
/* Free old tree and create a new root. */
|
||||
layout_free(w);
|
||||
lc = w->layout_root = layout_create_cell(NULL);
|
||||
layout_set_size(lc, sx, mainh + otherh, 0, 0);
|
||||
layout_set_size(lc, sx, mainh + otherh + 1, 0, 0);
|
||||
layout_make_node(lc, LAYOUT_TOPBOTTOM);
|
||||
|
||||
/* Create the main pane. */
|
||||
@@ -269,7 +272,7 @@ layout_set_main_v(struct window *w)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
struct layout_cell *lc, *lcmain, *lcother, *lcchild;
|
||||
u_int n, mainw, otherw, sy;
|
||||
u_int n, mainw, otherw, sx, sy;
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
@@ -279,22 +282,25 @@ layout_set_main_v(struct window *w)
|
||||
return;
|
||||
n--; /* take off main pane */
|
||||
|
||||
/* Find available width - take off one line for the border. */
|
||||
sx = w->sx - 1;
|
||||
|
||||
/* Get the main pane width and work out the other pane width. */
|
||||
mainw = options_get_number(w->options, "main-pane-width");
|
||||
if (mainw + PANE_MINIMUM + 1 >= w->sx) {
|
||||
if (w->sx <= PANE_MINIMUM + 1 + PANE_MINIMUM)
|
||||
if (mainw + PANE_MINIMUM >= sx) {
|
||||
if (sx <= PANE_MINIMUM + PANE_MINIMUM)
|
||||
mainw = PANE_MINIMUM;
|
||||
else
|
||||
mainw = w->sx - (PANE_MINIMUM + 1);
|
||||
mainw = sx - PANE_MINIMUM;
|
||||
otherw = PANE_MINIMUM;
|
||||
} else {
|
||||
otherw = options_get_number(w->options, "other-pane-width");
|
||||
if (otherw == 0)
|
||||
otherw = w->sx - mainw;
|
||||
else if (otherw > w->sx || w->sx - otherw < mainw)
|
||||
otherw = w->sx - mainw;
|
||||
otherw = sx - mainw;
|
||||
else if (otherw > sx || sx - otherw < mainw)
|
||||
otherw = sx - mainw;
|
||||
else
|
||||
mainw = w->sx - otherw;
|
||||
mainw = sx - otherw;
|
||||
}
|
||||
|
||||
/* Work out what height is needed. */
|
||||
@@ -305,7 +311,7 @@ layout_set_main_v(struct window *w)
|
||||
/* Free old tree and create a new root. */
|
||||
layout_free(w);
|
||||
lc = w->layout_root = layout_create_cell(NULL);
|
||||
layout_set_size(lc, mainw + otherw, sy, 0, 0);
|
||||
layout_set_size(lc, mainw + otherw + 1, sy, 0, 0);
|
||||
layout_make_node(lc, LAYOUT_LEFTRIGHT);
|
||||
|
||||
/* Create the main pane. */
|
||||
|
||||
20
layout.c
20
layout.c
@@ -414,9 +414,9 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc,
|
||||
lcother = TAILQ_NEXT(lc, entry);
|
||||
else
|
||||
lcother = TAILQ_PREV(lc, layout_cells, entry);
|
||||
if (lcparent->type == LAYOUT_LEFTRIGHT)
|
||||
if (lcother != NULL && lcparent->type == LAYOUT_LEFTRIGHT)
|
||||
layout_resize_adjust(w, lcother, lcparent->type, lc->sx + 1);
|
||||
else
|
||||
else if (lcother != NULL)
|
||||
layout_resize_adjust(w, lcother, lcparent->type, lc->sy + 1);
|
||||
|
||||
/* Remove this from the parent's list. */
|
||||
@@ -831,12 +831,12 @@ layout_resize_child_cells(struct window *w, struct layout_cell *lc)
|
||||
*/
|
||||
struct layout_cell *
|
||||
layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
int insert_before, int full_size)
|
||||
int flags)
|
||||
{
|
||||
struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
|
||||
u_int sx, sy, xoff, yoff, size1, size2, minimum;
|
||||
u_int new_size, saved_size, resize_first = 0;
|
||||
int status;
|
||||
int full_size = (flags & SPAWN_FULLSIZE), status;
|
||||
|
||||
/*
|
||||
* If full_size is specified, add a new cell at the top of the window
|
||||
@@ -881,7 +881,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
saved_size = sy;
|
||||
if (size < 0)
|
||||
size2 = ((saved_size + 1) / 2) - 1;
|
||||
else if (insert_before)
|
||||
else if (flags & SPAWN_BEFORE)
|
||||
size2 = saved_size - size - 1;
|
||||
else
|
||||
size2 = size;
|
||||
@@ -892,7 +892,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
size1 = saved_size - 1 - size2;
|
||||
|
||||
/* Which size are we using? */
|
||||
if (insert_before)
|
||||
if (flags & SPAWN_BEFORE)
|
||||
new_size = size2;
|
||||
else
|
||||
new_size = size1;
|
||||
@@ -908,7 +908,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
*/
|
||||
lcparent = lc->parent;
|
||||
lcnew = layout_create_cell(lcparent);
|
||||
if (insert_before)
|
||||
if (flags & SPAWN_BEFORE)
|
||||
TAILQ_INSERT_BEFORE(lc, lcnew, entry);
|
||||
else
|
||||
TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry);
|
||||
@@ -937,7 +937,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
layout_set_size(lcnew, size, sy, 0, 0);
|
||||
else if (lc->type == LAYOUT_TOPBOTTOM)
|
||||
layout_set_size(lcnew, sx, size, 0, 0);
|
||||
if (insert_before)
|
||||
if (flags & SPAWN_BEFORE)
|
||||
TAILQ_INSERT_HEAD(&lc->cells, lcnew, entry);
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
|
||||
@@ -961,12 +961,12 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
|
||||
/* Create the new child cell. */
|
||||
lcnew = layout_create_cell(lcparent);
|
||||
if (insert_before)
|
||||
if (flags & SPAWN_BEFORE)
|
||||
TAILQ_INSERT_HEAD(&lcparent->cells, lcnew, entry);
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry);
|
||||
}
|
||||
if (insert_before) {
|
||||
if (flags & SPAWN_BEFORE) {
|
||||
lc1 = lcnew;
|
||||
lc2 = lc;
|
||||
} else {
|
||||
|
||||
318
menu.c
Normal file
318
menu.c
Normal file
@@ -0,0 +1,318 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
struct menu_data {
|
||||
struct cmdq_item *item;
|
||||
int flags;
|
||||
|
||||
struct cmd_find_state fs;
|
||||
struct screen s;
|
||||
|
||||
u_int px;
|
||||
u_int py;
|
||||
|
||||
struct menu *menu;
|
||||
int choice;
|
||||
|
||||
menu_choice_cb cb;
|
||||
void *data;
|
||||
};
|
||||
|
||||
void
|
||||
menu_add_items(struct menu *menu, const struct menu_item *items,
|
||||
struct cmdq_item *qitem, struct client *c, struct cmd_find_state *fs)
|
||||
{
|
||||
const struct menu_item *loop;
|
||||
|
||||
for (loop = items; loop->name != NULL; loop++)
|
||||
menu_add_item(menu, loop, qitem, c, fs);
|
||||
}
|
||||
|
||||
void
|
||||
menu_add_item(struct menu *menu, const struct menu_item *item,
|
||||
struct cmdq_item *qitem, struct client *c, struct cmd_find_state *fs)
|
||||
{
|
||||
struct menu_item *new_item;
|
||||
const char *key, *cmd;
|
||||
char *s, *name;
|
||||
u_int width;
|
||||
int line;
|
||||
|
||||
line = (item == NULL || item->name == NULL || *item->name == '\0');
|
||||
if (line && menu->count == 0)
|
||||
return;
|
||||
|
||||
menu->items = xreallocarray(menu->items, menu->count + 1,
|
||||
sizeof *menu->items);
|
||||
new_item = &menu->items[menu->count++];
|
||||
memset(new_item, 0, sizeof *new_item);
|
||||
|
||||
if (line)
|
||||
return;
|
||||
|
||||
if (fs != NULL)
|
||||
s = format_single(qitem, item->name, c, fs->s, fs->wl, fs->wp);
|
||||
else
|
||||
s = format_single(qitem, item->name, c, NULL, NULL, NULL);
|
||||
if (*s == '\0') { /* no item if empty after format expanded */
|
||||
menu->count--;
|
||||
return;
|
||||
}
|
||||
if (*s != '-' && item->key != KEYC_UNKNOWN && item->key != KEYC_NONE) {
|
||||
key = key_string_lookup_key(item->key);
|
||||
xasprintf(&name, "%s#[default] #[align=right](%s)", s, key);
|
||||
} else
|
||||
xasprintf(&name, "%s", s);
|
||||
new_item->name = name;
|
||||
free(s);
|
||||
|
||||
cmd = item->command;
|
||||
if (cmd != NULL) {
|
||||
if (fs != NULL)
|
||||
s = format_single(qitem, cmd, c, fs->s, fs->wl, fs->wp);
|
||||
else
|
||||
s = format_single(qitem, cmd, c, NULL, NULL, NULL);
|
||||
} else
|
||||
s = NULL;
|
||||
new_item->command = s;
|
||||
new_item->key = item->key;
|
||||
|
||||
width = format_width(new_item->name);
|
||||
if (width > menu->width)
|
||||
menu->width = width;
|
||||
}
|
||||
|
||||
struct menu *
|
||||
menu_create(const char *title)
|
||||
{
|
||||
struct menu *menu;
|
||||
|
||||
menu = xcalloc(1, sizeof *menu);
|
||||
menu->title = xstrdup(title);
|
||||
|
||||
return (menu);
|
||||
}
|
||||
|
||||
void
|
||||
menu_free(struct menu *menu)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < menu->count; i++) {
|
||||
free((void *)menu->items[i].name);
|
||||
free((void *)menu->items[i].command);
|
||||
}
|
||||
free(menu->items);
|
||||
|
||||
free((void *)menu->title);
|
||||
free(menu);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
|
||||
{
|
||||
struct menu_data *md = c->overlay_data;
|
||||
struct tty *tty = &c->tty;
|
||||
struct screen *s = &md->s;
|
||||
struct menu *menu = md->menu;
|
||||
struct screen_write_ctx ctx;
|
||||
u_int i, px, py;
|
||||
|
||||
screen_write_start(&ctx, NULL, s);
|
||||
screen_write_clearscreen(&ctx, 8);
|
||||
screen_write_menu(&ctx, menu, md->choice);
|
||||
screen_write_stop(&ctx);
|
||||
|
||||
px = md->px;
|
||||
py = md->py;
|
||||
|
||||
for (i = 0; i < screen_size_y(&md->s); i++)
|
||||
tty_draw_line(tty, NULL, s, 0, i, menu->width + 4, px, py + i);
|
||||
|
||||
if (~md->flags & MENU_NOMOUSE)
|
||||
tty_update_mode(tty, MODE_MOUSE_ALL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_free_cb(struct client *c)
|
||||
{
|
||||
struct menu_data *md = c->overlay_data;
|
||||
|
||||
if (md->item != NULL)
|
||||
md->item->flags &= ~CMDQ_WAITING;
|
||||
|
||||
if (md->cb != NULL)
|
||||
md->cb(md->menu, UINT_MAX, KEYC_NONE, md->data);
|
||||
|
||||
screen_free(&md->s);
|
||||
menu_free(md->menu);
|
||||
free(md);
|
||||
}
|
||||
|
||||
static int
|
||||
menu_key_cb(struct client *c, struct key_event *event)
|
||||
{
|
||||
struct menu_data *md = c->overlay_data;
|
||||
struct menu *menu = md->menu;
|
||||
struct mouse_event *m = &event->m;
|
||||
u_int i;
|
||||
int count = menu->count, old = md->choice;
|
||||
const struct menu_item *item;
|
||||
struct cmdq_item *new_item;
|
||||
struct cmd_parse_result *pr;
|
||||
const char *name;
|
||||
|
||||
if (KEYC_IS_MOUSE(event->key)) {
|
||||
if (md->flags & MENU_NOMOUSE)
|
||||
return (0);
|
||||
if (m->x < md->px ||
|
||||
m->x > md->px + 4 + menu->width ||
|
||||
m->y < md->py + 1 ||
|
||||
m->y > md->py + 1 + count - 1) {
|
||||
if (MOUSE_RELEASE(m->b))
|
||||
return (1);
|
||||
if (md->choice != -1) {
|
||||
md->choice = -1;
|
||||
c->flags |= CLIENT_REDRAWOVERLAY;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
if (MOUSE_RELEASE(m->b))
|
||||
goto chosen;
|
||||
md->choice = m->y - (md->py + 1);
|
||||
if (md->choice != old)
|
||||
c->flags |= CLIENT_REDRAWOVERLAY;
|
||||
return (0);
|
||||
}
|
||||
switch (event->key) {
|
||||
case KEYC_UP:
|
||||
if (old == -1)
|
||||
old = 0;
|
||||
do {
|
||||
if (md->choice == -1 || md->choice == 0)
|
||||
md->choice = count - 1;
|
||||
else
|
||||
md->choice--;
|
||||
name = menu->items[md->choice].name;
|
||||
} while ((name == NULL || *name == '-') && md->choice != old);
|
||||
c->flags |= CLIENT_REDRAWOVERLAY;
|
||||
return (0);
|
||||
case KEYC_DOWN:
|
||||
if (old == -1)
|
||||
old = 0;
|
||||
do {
|
||||
if (md->choice == -1 || md->choice == count - 1)
|
||||
md->choice = 0;
|
||||
else
|
||||
md->choice++;
|
||||
name = menu->items[md->choice].name;
|
||||
} while ((name == NULL || *name == '-') && md->choice != old);
|
||||
c->flags |= CLIENT_REDRAWOVERLAY;
|
||||
return (0);
|
||||
case '\r':
|
||||
goto chosen;
|
||||
case '\033': /* Escape */
|
||||
case '\003': /* C-c */
|
||||
case '\007': /* C-g */
|
||||
case 'q':
|
||||
return (1);
|
||||
}
|
||||
for (i = 0; i < (u_int)count; i++) {
|
||||
name = menu->items[i].name;
|
||||
if (name == NULL || *name == '-')
|
||||
continue;
|
||||
if (event->key == menu->items[i].key) {
|
||||
md->choice = i;
|
||||
goto chosen;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
|
||||
chosen:
|
||||
if (md->choice == -1)
|
||||
return (1);
|
||||
item = &menu->items[md->choice];
|
||||
if (item->name == NULL || *item->name == '-')
|
||||
return (1);
|
||||
if (md->cb != NULL) {
|
||||
md->cb(md->menu, md->choice, item->key, md->data);
|
||||
md->cb = NULL;
|
||||
return (1);
|
||||
}
|
||||
|
||||
pr = cmd_parse_from_string(item->command, NULL);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_EMPTY:
|
||||
new_item = NULL;
|
||||
break;
|
||||
case CMD_PARSE_ERROR:
|
||||
new_item = cmdq_get_error(pr->error);
|
||||
free(pr->error);
|
||||
cmdq_append(c, new_item);
|
||||
break;
|
||||
case CMD_PARSE_SUCCESS:
|
||||
if (md->item != NULL)
|
||||
m = &md->item->shared->mouse;
|
||||
else
|
||||
m = NULL;
|
||||
new_item = cmdq_get_command(pr->cmdlist, &md->fs, m, 0);
|
||||
cmd_list_free(pr->cmdlist);
|
||||
cmdq_append(c, new_item);
|
||||
break;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
int
|
||||
menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
|
||||
u_int py, struct client *c, struct cmd_find_state *fs, menu_choice_cb cb,
|
||||
void *data)
|
||||
{
|
||||
struct menu_data *md;
|
||||
|
||||
if (c->tty.sx < menu->width + 4 || c->tty.sy < menu->count + 2)
|
||||
return (-1);
|
||||
|
||||
md = xcalloc(1, sizeof *md);
|
||||
md->item = item;
|
||||
md->flags = flags;
|
||||
|
||||
if (fs != NULL)
|
||||
cmd_find_copy_state(&md->fs, fs);
|
||||
screen_init(&md->s, menu->width + 4, menu->count + 2, 0);
|
||||
|
||||
md->px = px;
|
||||
md->py = py;
|
||||
|
||||
md->menu = menu;
|
||||
md->choice = -1;
|
||||
|
||||
md->cb = cb;
|
||||
md->data = data;
|
||||
|
||||
server_client_set_overlay(c, 0, menu_draw_cb, menu_key_cb, menu_free_cb,
|
||||
md);
|
||||
return (0);
|
||||
}
|
||||
138
mode-tree.c
138
mode-tree.c
@@ -35,6 +35,7 @@ struct mode_tree_data {
|
||||
|
||||
struct window_pane *wp;
|
||||
void *modedata;
|
||||
const struct menu_item *menu;
|
||||
|
||||
const char **sort_list;
|
||||
u_int sort_size;
|
||||
@@ -43,6 +44,7 @@ struct mode_tree_data {
|
||||
mode_tree_build_cb buildcb;
|
||||
mode_tree_draw_cb drawcb;
|
||||
mode_tree_search_cb searchcb;
|
||||
mode_tree_menu_cb menucb;
|
||||
|
||||
struct mode_tree_list children;
|
||||
struct mode_tree_list saved;
|
||||
@@ -89,8 +91,24 @@ struct mode_tree_line {
|
||||
int flat;
|
||||
};
|
||||
|
||||
struct mode_tree_menu {
|
||||
struct mode_tree_data *data;
|
||||
struct client *c;
|
||||
u_int line;
|
||||
void *itemdata;
|
||||
};
|
||||
|
||||
static void mode_tree_free_items(struct mode_tree_list *);
|
||||
|
||||
static const struct menu_item mode_tree_menu_items[] = {
|
||||
{ "Scroll Left", '<', NULL },
|
||||
{ "Scroll Right", '>', NULL },
|
||||
{ "", KEYC_NONE, NULL },
|
||||
{ "Cancel", 'q', NULL },
|
||||
|
||||
{ NULL, KEYC_NONE, NULL }
|
||||
};
|
||||
|
||||
static struct mode_tree_item *
|
||||
mode_tree_find_item(struct mode_tree_list *mtl, uint64_t tag)
|
||||
{
|
||||
@@ -299,8 +317,9 @@ mode_tree_each_tagged(struct mode_tree_data *mtd, mode_tree_each_cb cb,
|
||||
struct mode_tree_data *
|
||||
mode_tree_start(struct window_pane *wp, struct args *args,
|
||||
mode_tree_build_cb buildcb, mode_tree_draw_cb drawcb,
|
||||
mode_tree_search_cb searchcb, void *modedata, const char **sort_list,
|
||||
u_int sort_size, struct screen **s)
|
||||
mode_tree_search_cb searchcb, mode_tree_menu_cb menucb, void *modedata,
|
||||
const struct menu_item *menu, const char **sort_list, u_int sort_size,
|
||||
struct screen **s)
|
||||
{
|
||||
struct mode_tree_data *mtd;
|
||||
const char *sort;
|
||||
@@ -311,6 +330,7 @@ mode_tree_start(struct window_pane *wp, struct args *args,
|
||||
|
||||
mtd->wp = wp;
|
||||
mtd->modedata = modedata;
|
||||
mtd->menu = menu;
|
||||
|
||||
mtd->sort_list = sort_list;
|
||||
mtd->sort_size = sort_size;
|
||||
@@ -334,6 +354,7 @@ mode_tree_start(struct window_pane *wp, struct args *args,
|
||||
mtd->buildcb = buildcb;
|
||||
mtd->drawcb = drawcb;
|
||||
mtd->searchcb = searchcb;
|
||||
mtd->menucb = menucb;
|
||||
|
||||
TAILQ_INIT(&mtd->children);
|
||||
|
||||
@@ -366,7 +387,7 @@ mode_tree_build(struct mode_tree_data *mtd)
|
||||
if (mtd->line_list != NULL)
|
||||
tag = mtd->line_list[mtd->current].item->tag;
|
||||
else
|
||||
tag = 0;
|
||||
tag = UINT64_MAX;
|
||||
|
||||
TAILQ_CONCAT(&mtd->saved, &mtd->children, entry);
|
||||
TAILQ_INIT(&mtd->children);
|
||||
@@ -382,6 +403,8 @@ mode_tree_build(struct mode_tree_data *mtd)
|
||||
mode_tree_clear_lines(mtd);
|
||||
mode_tree_build_lines(mtd, &mtd->children, 0);
|
||||
|
||||
if (tag == UINT64_MAX)
|
||||
tag = mtd->line_list[mtd->current].item->tag;
|
||||
mode_tree_set_current(mtd, tag);
|
||||
|
||||
mtd->width = screen_size_x(s);
|
||||
@@ -762,6 +785,70 @@ mode_tree_filter_free(void *data)
|
||||
mode_tree_remove_ref(data);
|
||||
}
|
||||
|
||||
static void
|
||||
mode_tree_menu_callback(__unused struct menu *menu, __unused u_int idx,
|
||||
key_code key, void *data)
|
||||
{
|
||||
struct mode_tree_menu *mtm = data;
|
||||
struct mode_tree_data *mtd = mtm->data;
|
||||
struct mode_tree_item *mti;
|
||||
|
||||
if (mtd->dead || key == KEYC_NONE)
|
||||
goto out;
|
||||
|
||||
if (mtm->line >= mtd->line_size)
|
||||
goto out;
|
||||
mti = mtd->line_list[mtm->line].item;
|
||||
if (mti->itemdata != mtm->itemdata)
|
||||
goto out;
|
||||
mtd->current = mtm->line;
|
||||
mtd->menucb (mtd->modedata, mtm->c, key);
|
||||
|
||||
out:
|
||||
mode_tree_remove_ref(mtd);
|
||||
free(mtm);
|
||||
}
|
||||
|
||||
static void
|
||||
mode_tree_display_menu(struct mode_tree_data *mtd, struct client *c, u_int x,
|
||||
u_int y, int outside)
|
||||
{
|
||||
struct mode_tree_item *mti;
|
||||
struct menu *menu;
|
||||
const struct menu_item *items;
|
||||
struct mode_tree_menu *mtm;
|
||||
char *title;
|
||||
u_int line;
|
||||
|
||||
if (mtd->offset + y > mtd->line_size - 1)
|
||||
line = mtd->current;
|
||||
else
|
||||
line = mtd->offset + y;
|
||||
mti = mtd->line_list[line].item;
|
||||
|
||||
if (!outside) {
|
||||
items = mtd->menu;
|
||||
xasprintf(&title, "#[align=centre]%s", mti->name);
|
||||
} else {
|
||||
items = mode_tree_menu_items;
|
||||
title = xstrdup("");
|
||||
}
|
||||
menu = menu_create(title);
|
||||
menu_add_items(menu, items, NULL, NULL, NULL);
|
||||
free(title);
|
||||
|
||||
mtm = xmalloc(sizeof *mtm);
|
||||
mtm->data = mtd;
|
||||
mtm->c = c;
|
||||
mtm->line = line;
|
||||
mtm->itemdata = mti->itemdata;
|
||||
mtd->references++;
|
||||
|
||||
if (menu_display(menu, 0, NULL, x, y, c, NULL, mode_tree_menu_callback,
|
||||
mtm) != 0)
|
||||
menu_free(menu);
|
||||
}
|
||||
|
||||
int
|
||||
mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
||||
struct mouse_event *m, u_int *xp, u_int *yp)
|
||||
@@ -772,7 +859,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
||||
int choice;
|
||||
key_code tmp;
|
||||
|
||||
if (KEYC_IS_MOUSE(*key)) {
|
||||
if (KEYC_IS_MOUSE(*key) && m != NULL) {
|
||||
if (cmd_mouse_at(mtd->wp, m, &x, &y, 0) != 0) {
|
||||
*key = KEYC_NONE;
|
||||
return (0);
|
||||
@@ -782,20 +869,29 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
||||
if (yp != NULL)
|
||||
*yp = y;
|
||||
if (x > mtd->width || y > mtd->height) {
|
||||
if (*key == KEYC_MOUSEDOWN3_PANE)
|
||||
mode_tree_display_menu(mtd, c, x, y, 1);
|
||||
if (!mtd->preview)
|
||||
*key = KEYC_NONE;
|
||||
return (0);
|
||||
}
|
||||
if (mtd->offset + y < mtd->line_size) {
|
||||
if (*key == KEYC_MOUSEDOWN1_PANE ||
|
||||
*key == KEYC_MOUSEDOWN3_PANE ||
|
||||
*key == KEYC_DOUBLECLICK1_PANE)
|
||||
mtd->current = mtd->offset + y;
|
||||
if (*key == KEYC_DOUBLECLICK1_PANE)
|
||||
*key = '\r';
|
||||
else
|
||||
else {
|
||||
if (*key == KEYC_MOUSEDOWN3_PANE)
|
||||
mode_tree_display_menu(mtd, c, x, y, 0);
|
||||
*key = KEYC_NONE;
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
if (*key == KEYC_MOUSEDOWN3_PANE)
|
||||
mode_tree_display_menu(mtd, c, x, y, 0);
|
||||
*key = KEYC_NONE;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -879,7 +975,8 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
||||
current->tagged = 1;
|
||||
} else
|
||||
current->tagged = 0;
|
||||
mode_tree_down(mtd, 0);
|
||||
if (m != NULL)
|
||||
mode_tree_down(mtd, 0);
|
||||
break;
|
||||
case 'T':
|
||||
for (i = 0; i < mtd->line_size; i++)
|
||||
@@ -952,8 +1049,8 @@ mode_tree_run_command(struct client *c, struct cmd_find_state *fs,
|
||||
const char *template, const char *name)
|
||||
{
|
||||
struct cmdq_item *new_item;
|
||||
struct cmd_list *cmdlist;
|
||||
char *command, *cause;
|
||||
char *command;
|
||||
struct cmd_parse_result *pr;
|
||||
|
||||
command = cmd_template_replace(template, name, 1);
|
||||
if (command == NULL || *command == '\0') {
|
||||
@@ -961,17 +1058,22 @@ mode_tree_run_command(struct client *c, struct cmd_find_state *fs,
|
||||
return;
|
||||
}
|
||||
|
||||
cmdlist = cmd_string_parse(command, NULL, 0, &cause);
|
||||
if (cmdlist == NULL) {
|
||||
if (cause != NULL && c != NULL) {
|
||||
*cause = toupper((u_char)*cause);
|
||||
status_message_set(c, "%s", cause);
|
||||
pr = cmd_parse_from_string(command, NULL);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_EMPTY:
|
||||
break;
|
||||
case CMD_PARSE_ERROR:
|
||||
if (c != NULL) {
|
||||
*pr->error = toupper((u_char)*pr->error);
|
||||
status_message_set(c, "%s", pr->error);
|
||||
}
|
||||
free(cause);
|
||||
} else {
|
||||
new_item = cmdq_get_command(cmdlist, fs, NULL, 0);
|
||||
free(pr->error);
|
||||
break;
|
||||
case CMD_PARSE_SUCCESS:
|
||||
new_item = cmdq_get_command(pr->cmdlist, fs, NULL, 0);
|
||||
cmdq_append(c, new_item);
|
||||
cmd_list_free(cmdlist);
|
||||
cmd_list_free(pr->cmdlist);
|
||||
break;
|
||||
}
|
||||
|
||||
free(command);
|
||||
|
||||
78
notify.c
78
notify.c
@@ -35,13 +35,34 @@ struct notify_entry {
|
||||
};
|
||||
|
||||
static void
|
||||
notify_hook1(struct cmdq_item *item, struct notify_entry *ne)
|
||||
notify_hook_formats(struct cmdq_item *item, struct session *s, struct window *w,
|
||||
int pane)
|
||||
{
|
||||
struct cmd_find_state fs;
|
||||
struct hook *hook;
|
||||
struct cmdq_item *new_item;
|
||||
struct session *s = ne->session;
|
||||
struct window *w = ne->window;
|
||||
if (s != NULL) {
|
||||
cmdq_format(item, "hook_session", "$%u", s->id);
|
||||
cmdq_format(item, "hook_session_name", "%s", s->name);
|
||||
}
|
||||
if (w != NULL) {
|
||||
cmdq_format(item, "hook_window", "@%u", w->id);
|
||||
cmdq_format(item, "hook_window_name", "%s", w->name);
|
||||
}
|
||||
if (pane != -1)
|
||||
cmdq_format(item, "hook_pane", "%%%d", pane);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne)
|
||||
{
|
||||
struct cmd_find_state fs;
|
||||
struct options *oo;
|
||||
struct cmdq_item *new_item;
|
||||
struct session *s = ne->session;
|
||||
struct window *w = ne->window;
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
struct cmd_list *cmdlist;
|
||||
|
||||
log_debug("%s: %s", __func__, ne->name);
|
||||
|
||||
cmd_find_clear_state(&fs, 0);
|
||||
if (cmd_find_empty_state(&ne->fs) || !cmd_find_valid_state(&ne->fs))
|
||||
@@ -49,26 +70,31 @@ notify_hook1(struct cmdq_item *item, struct notify_entry *ne)
|
||||
else
|
||||
cmd_find_copy_state(&fs, &ne->fs);
|
||||
|
||||
hook = hooks_find(hooks_get(fs.s), ne->name);
|
||||
if (hook == NULL)
|
||||
if (fs.s == NULL)
|
||||
oo = global_s_options;
|
||||
else
|
||||
oo = fs.s->options;
|
||||
o = options_get(oo, ne->name);
|
||||
if (o == NULL)
|
||||
return;
|
||||
log_debug("notify hook %s", ne->name);
|
||||
|
||||
new_item = cmdq_get_command(hook->cmdlist, &fs, NULL, CMDQ_NOHOOKS);
|
||||
cmdq_format(new_item, "hook", "%s", ne->name);
|
||||
a = options_array_first(o);
|
||||
while (a != NULL) {
|
||||
cmdlist = options_array_item_value(a)->cmdlist;
|
||||
if (cmdlist == NULL) {
|
||||
a = options_array_next(a);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s != NULL) {
|
||||
cmdq_format(new_item, "hook_session", "$%u", s->id);
|
||||
cmdq_format(new_item, "hook_session_name", "%s", s->name);
|
||||
new_item = cmdq_get_command(cmdlist, &fs, NULL, CMDQ_NOHOOKS);
|
||||
cmdq_format(new_item, "hook", "%s", ne->name);
|
||||
notify_hook_formats(new_item, s, w, ne->pane);
|
||||
|
||||
cmdq_insert_after(item, new_item);
|
||||
item = new_item;
|
||||
|
||||
a = options_array_next(a);
|
||||
}
|
||||
if (w != NULL) {
|
||||
cmdq_format(new_item, "hook_window", "@%u", w->id);
|
||||
cmdq_format(new_item, "hook_window_name", "%s", w->name);
|
||||
}
|
||||
if (ne->pane != -1)
|
||||
cmdq_format(new_item, "hook_pane", "%%%d", ne->pane);
|
||||
|
||||
cmdq_insert_after(item, new_item);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
@@ -101,7 +127,7 @@ notify_callback(struct cmdq_item *item, void *data)
|
||||
if (strcmp(ne->name, "session-window-changed") == 0)
|
||||
control_notify_session_window_changed(ne->session);
|
||||
|
||||
notify_hook1(item, ne);
|
||||
notify_insert_hook(item, ne);
|
||||
|
||||
if (ne->client != NULL)
|
||||
server_client_unref(ne->client);
|
||||
@@ -168,17 +194,17 @@ notify_hook(struct cmdq_item *item, const char *name)
|
||||
ne.window = item->target.w;
|
||||
ne.pane = item->target.wp->id;
|
||||
|
||||
notify_hook1(item, &ne);
|
||||
notify_insert_hook(item, &ne);
|
||||
}
|
||||
|
||||
void
|
||||
notify_input(struct window_pane *wp, struct evbuffer *input)
|
||||
notify_input(struct window_pane *wp, const u_char *buf, size_t len)
|
||||
{
|
||||
struct client *c;
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (c->flags & CLIENT_CONTROL)
|
||||
control_notify_input(c, wp, input);
|
||||
control_notify_input(c, wp, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,8 +129,19 @@ static const char *options_table_status_format_default[] = {
|
||||
OPTIONS_TABLE_STATUS_FORMAT1, OPTIONS_TABLE_STATUS_FORMAT2, NULL
|
||||
};
|
||||
|
||||
/* Helper for hook options. */
|
||||
#define OPTIONS_TABLE_HOOK(hook_name, default_value) \
|
||||
{ .name = hook_name, \
|
||||
.type = OPTIONS_TABLE_COMMAND, \
|
||||
.scope = OPTIONS_TABLE_SESSION, \
|
||||
.flags = OPTIONS_TABLE_IS_ARRAY|OPTIONS_TABLE_IS_HOOK, \
|
||||
.default_str = default_value, \
|
||||
.separator = "" \
|
||||
}
|
||||
|
||||
/* Top-level options. */
|
||||
const struct options_table_entry options_table[] = {
|
||||
/* Server options. */
|
||||
{ .name = "buffer-limit",
|
||||
.type = OPTIONS_TABLE_NUMBER,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
@@ -140,8 +151,9 @@ const struct options_table_entry options_table[] = {
|
||||
},
|
||||
|
||||
{ .name = "command-alias",
|
||||
.type = OPTIONS_TABLE_ARRAY,
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_ARRAY,
|
||||
.default_str = "split-pane=split-window,"
|
||||
"splitp=split-window,"
|
||||
"server-info=show-messages -JT,"
|
||||
@@ -205,8 +217,9 @@ const struct options_table_entry options_table[] = {
|
||||
},
|
||||
|
||||
{ .name = "terminal-overrides",
|
||||
.type = OPTIONS_TABLE_ARRAY,
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_ARRAY,
|
||||
.default_str = "xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007"
|
||||
":Cs=\\E]12;%p1%s\\007:Cr=\\E]112\\007"
|
||||
":Ss=\\E[%p1%d q:Se=\\E[2 q,screen*:XT",
|
||||
@@ -214,12 +227,14 @@ const struct options_table_entry options_table[] = {
|
||||
},
|
||||
|
||||
{ .name = "user-keys",
|
||||
.type = OPTIONS_TABLE_ARRAY,
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_ARRAY,
|
||||
.default_str = "",
|
||||
.separator = ","
|
||||
},
|
||||
|
||||
/* Session options. */
|
||||
{ .name = "activity-action",
|
||||
.type = OPTIONS_TABLE_CHOICE,
|
||||
.scope = OPTIONS_TABLE_SESSION,
|
||||
@@ -420,8 +435,9 @@ const struct options_table_entry options_table[] = {
|
||||
},
|
||||
|
||||
{ .name = "status-format",
|
||||
.type = OPTIONS_TABLE_ARRAY,
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SESSION,
|
||||
.flags = OPTIONS_TABLE_IS_ARRAY,
|
||||
.default_arr = options_table_status_format_default,
|
||||
},
|
||||
|
||||
@@ -503,8 +519,9 @@ const struct options_table_entry options_table[] = {
|
||||
},
|
||||
|
||||
{ .name = "update-environment",
|
||||
.type = OPTIONS_TABLE_ARRAY,
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SESSION,
|
||||
.flags = OPTIONS_TABLE_IS_ARRAY,
|
||||
.default_str = "DISPLAY KRB5CCNAME SSH_ASKPASS SSH_AUTH_SOCK "
|
||||
"SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY"
|
||||
},
|
||||
@@ -533,9 +550,10 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "word-separators",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SESSION,
|
||||
.default_str = " -_@"
|
||||
.default_str = " "
|
||||
},
|
||||
|
||||
/* Window options. */
|
||||
{ .name = "aggressive-resize",
|
||||
.type = OPTIONS_TABLE_FLAG,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
@@ -770,5 +788,66 @@ const struct options_table_entry options_table[] = {
|
||||
.default_num = 1
|
||||
},
|
||||
|
||||
/* Hook options. */
|
||||
OPTIONS_TABLE_HOOK("after-bind-key", ""),
|
||||
OPTIONS_TABLE_HOOK("after-capture-pane", ""),
|
||||
OPTIONS_TABLE_HOOK("after-copy-mode", ""),
|
||||
OPTIONS_TABLE_HOOK("after-display-message", ""),
|
||||
OPTIONS_TABLE_HOOK("after-display-panes", ""),
|
||||
OPTIONS_TABLE_HOOK("after-list-buffers", ""),
|
||||
OPTIONS_TABLE_HOOK("after-list-clients", ""),
|
||||
OPTIONS_TABLE_HOOK("after-list-keys", ""),
|
||||
OPTIONS_TABLE_HOOK("after-list-panes", ""),
|
||||
OPTIONS_TABLE_HOOK("after-list-sessions", ""),
|
||||
OPTIONS_TABLE_HOOK("after-list-windows", ""),
|
||||
OPTIONS_TABLE_HOOK("after-load-buffer", ""),
|
||||
OPTIONS_TABLE_HOOK("after-lock-server", ""),
|
||||
OPTIONS_TABLE_HOOK("after-new-session", ""),
|
||||
OPTIONS_TABLE_HOOK("after-new-window", ""),
|
||||
OPTIONS_TABLE_HOOK("after-paste-buffer", ""),
|
||||
OPTIONS_TABLE_HOOK("after-pipe-pane", ""),
|
||||
OPTIONS_TABLE_HOOK("after-queue", ""),
|
||||
OPTIONS_TABLE_HOOK("after-refresh-client", ""),
|
||||
OPTIONS_TABLE_HOOK("after-rename-session", ""),
|
||||
OPTIONS_TABLE_HOOK("after-rename-window", ""),
|
||||
OPTIONS_TABLE_HOOK("after-resize-pane", ""),
|
||||
OPTIONS_TABLE_HOOK("after-resize-window", ""),
|
||||
OPTIONS_TABLE_HOOK("after-save-buffer", ""),
|
||||
OPTIONS_TABLE_HOOK("after-select-layout", ""),
|
||||
OPTIONS_TABLE_HOOK("after-select-pane", ""),
|
||||
OPTIONS_TABLE_HOOK("after-select-window", ""),
|
||||
OPTIONS_TABLE_HOOK("after-send-keys", ""),
|
||||
OPTIONS_TABLE_HOOK("after-set-buffer", ""),
|
||||
OPTIONS_TABLE_HOOK("after-set-environment", ""),
|
||||
OPTIONS_TABLE_HOOK("after-set-hook", ""),
|
||||
OPTIONS_TABLE_HOOK("after-set-option", ""),
|
||||
OPTIONS_TABLE_HOOK("after-show-environment", ""),
|
||||
OPTIONS_TABLE_HOOK("after-show-messages", ""),
|
||||
OPTIONS_TABLE_HOOK("after-show-options", ""),
|
||||
OPTIONS_TABLE_HOOK("after-split-window", ""),
|
||||
OPTIONS_TABLE_HOOK("after-unbind-key", ""),
|
||||
OPTIONS_TABLE_HOOK("alert-activity", ""),
|
||||
OPTIONS_TABLE_HOOK("alert-bell", ""),
|
||||
OPTIONS_TABLE_HOOK("alert-silence", ""),
|
||||
OPTIONS_TABLE_HOOK("client-attached", ""),
|
||||
OPTIONS_TABLE_HOOK("client-detached", ""),
|
||||
OPTIONS_TABLE_HOOK("client-resized", ""),
|
||||
OPTIONS_TABLE_HOOK("client-session-changed", ""),
|
||||
OPTIONS_TABLE_HOOK("pane-died", ""),
|
||||
OPTIONS_TABLE_HOOK("pane-exited", ""),
|
||||
OPTIONS_TABLE_HOOK("pane-focus-in", ""),
|
||||
OPTIONS_TABLE_HOOK("pane-focus-out", ""),
|
||||
OPTIONS_TABLE_HOOK("pane-mode-changed", ""),
|
||||
OPTIONS_TABLE_HOOK("pane-set-clipboard", ""),
|
||||
OPTIONS_TABLE_HOOK("session-closed", ""),
|
||||
OPTIONS_TABLE_HOOK("session-created", ""),
|
||||
OPTIONS_TABLE_HOOK("session-renamed", ""),
|
||||
OPTIONS_TABLE_HOOK("session-window-changed", ""),
|
||||
OPTIONS_TABLE_HOOK("window-layout-changed", ""),
|
||||
OPTIONS_TABLE_HOOK("window-linked", ""),
|
||||
OPTIONS_TABLE_HOOK("window-pane-changed", ""),
|
||||
OPTIONS_TABLE_HOOK("window-renamed", ""),
|
||||
OPTIONS_TABLE_HOOK("window-unlinked", ""),
|
||||
|
||||
{ .name = NULL }
|
||||
};
|
||||
|
||||
287
options.c
287
options.c
@@ -32,10 +32,9 @@
|
||||
|
||||
struct options_array_item {
|
||||
u_int index;
|
||||
char *value;
|
||||
union options_value value;
|
||||
RB_ENTRY(options_array_item) entry;
|
||||
};
|
||||
RB_HEAD(options_array, options_array_item);
|
||||
static int
|
||||
options_array_cmp(struct options_array_item *a1, struct options_array_item *a2)
|
||||
{
|
||||
@@ -48,19 +47,13 @@ options_array_cmp(struct options_array_item *a1, struct options_array_item *a2)
|
||||
RB_GENERATE_STATIC(options_array, options_array_item, entry, options_array_cmp);
|
||||
|
||||
struct options_entry {
|
||||
struct options *owner;
|
||||
struct options *owner;
|
||||
|
||||
const char *name;
|
||||
const struct options_table_entry *tableentry;
|
||||
const char *name;
|
||||
const struct options_table_entry *tableentry;
|
||||
union options_value value;
|
||||
|
||||
union {
|
||||
char *string;
|
||||
long long number;
|
||||
struct style style;
|
||||
struct options_array array;
|
||||
};
|
||||
|
||||
RB_ENTRY(options_entry) entry;
|
||||
RB_ENTRY(options_entry) entry;
|
||||
};
|
||||
|
||||
struct options {
|
||||
@@ -83,9 +76,13 @@ static struct options_entry *options_add(struct options *, const char *);
|
||||
#define OPTIONS_IS_STYLE(o) \
|
||||
((o)->tableentry != NULL && \
|
||||
(o)->tableentry->type == OPTIONS_TABLE_STYLE)
|
||||
#define OPTIONS_IS_ARRAY(o) \
|
||||
#define OPTIONS_IS_COMMAND(o) \
|
||||
((o)->tableentry != NULL && \
|
||||
(o)->tableentry->type == OPTIONS_TABLE_ARRAY)
|
||||
(o)->tableentry->type == OPTIONS_TABLE_COMMAND)
|
||||
|
||||
#define OPTIONS_IS_ARRAY(o) \
|
||||
((o)->tableentry != NULL && \
|
||||
((o)->tableentry->flags & OPTIONS_TABLE_IS_ARRAY))
|
||||
|
||||
static int options_cmp(struct options_entry *, struct options_entry *);
|
||||
RB_GENERATE_STATIC(options_tree, options_entry, entry, options_cmp);
|
||||
@@ -109,6 +106,57 @@ options_parent_table_entry(struct options *oo, const char *s)
|
||||
return (o->tableentry);
|
||||
}
|
||||
|
||||
static void
|
||||
options_value_free(struct options_entry *o, union options_value *ov)
|
||||
{
|
||||
if (OPTIONS_IS_STRING(o))
|
||||
free(ov->string);
|
||||
if (OPTIONS_IS_COMMAND(o) && ov->cmdlist != NULL)
|
||||
cmd_list_free(ov->cmdlist);
|
||||
}
|
||||
|
||||
static char *
|
||||
options_value_tostring(struct options_entry *o, union options_value *ov,
|
||||
int numeric)
|
||||
{
|
||||
char *s;
|
||||
|
||||
if (OPTIONS_IS_COMMAND(o))
|
||||
return (cmd_list_print(ov->cmdlist, 0));
|
||||
if (OPTIONS_IS_STYLE(o))
|
||||
return (xstrdup(style_tostring(&ov->style)));
|
||||
if (OPTIONS_IS_NUMBER(o)) {
|
||||
switch (o->tableentry->type) {
|
||||
case OPTIONS_TABLE_NUMBER:
|
||||
xasprintf(&s, "%lld", ov->number);
|
||||
break;
|
||||
case OPTIONS_TABLE_KEY:
|
||||
s = xstrdup(key_string_lookup_key(ov->number));
|
||||
break;
|
||||
case OPTIONS_TABLE_COLOUR:
|
||||
s = xstrdup(colour_tostring(ov->number));
|
||||
break;
|
||||
case OPTIONS_TABLE_FLAG:
|
||||
if (numeric)
|
||||
xasprintf(&s, "%lld", ov->number);
|
||||
else
|
||||
s = xstrdup(ov->number ? "on" : "off");
|
||||
break;
|
||||
case OPTIONS_TABLE_CHOICE:
|
||||
s = xstrdup(o->tableentry->choices[ov->number]);
|
||||
break;
|
||||
case OPTIONS_TABLE_STRING:
|
||||
case OPTIONS_TABLE_STYLE:
|
||||
case OPTIONS_TABLE_COMMAND:
|
||||
fatalx("not a number option type");
|
||||
}
|
||||
return (s);
|
||||
}
|
||||
if (OPTIONS_IS_STRING(o))
|
||||
return (xstrdup(ov->string));
|
||||
return (xstrdup(""));
|
||||
}
|
||||
|
||||
struct options *
|
||||
options_create(struct options *parent)
|
||||
{
|
||||
@@ -174,8 +222,8 @@ options_empty(struct options *oo, const struct options_table_entry *oe)
|
||||
o = options_add(oo, oe->name);
|
||||
o->tableentry = oe;
|
||||
|
||||
if (oe->type == OPTIONS_TABLE_ARRAY)
|
||||
RB_INIT(&o->array);
|
||||
if (oe->flags & OPTIONS_TABLE_IS_ARRAY)
|
||||
RB_INIT(&o->value.array);
|
||||
|
||||
return (o);
|
||||
}
|
||||
@@ -183,23 +231,35 @@ options_empty(struct options *oo, const struct options_table_entry *oe)
|
||||
struct options_entry *
|
||||
options_default(struct options *oo, const struct options_table_entry *oe)
|
||||
{
|
||||
struct options_entry *o;
|
||||
u_int i;
|
||||
struct options_entry *o;
|
||||
union options_value *ov;
|
||||
u_int i;
|
||||
|
||||
o = options_empty(oo, oe);
|
||||
if (oe->type == OPTIONS_TABLE_ARRAY) {
|
||||
if (oe->default_arr != NULL) {
|
||||
for (i = 0; oe->default_arr[i] != NULL; i++)
|
||||
options_array_set(o, i, oe->default_arr[i], 0);
|
||||
} else
|
||||
options_array_assign(o, oe->default_str);
|
||||
} else if (oe->type == OPTIONS_TABLE_STRING)
|
||||
o->string = xstrdup(oe->default_str);
|
||||
else if (oe->type == OPTIONS_TABLE_STYLE) {
|
||||
style_set(&o->style, &grid_default_cell);
|
||||
style_parse(&o->style, &grid_default_cell, oe->default_str);
|
||||
} else
|
||||
o->number = oe->default_num;
|
||||
ov = &o->value;
|
||||
|
||||
if (oe->flags & OPTIONS_TABLE_IS_ARRAY) {
|
||||
if (oe->default_arr == NULL) {
|
||||
options_array_assign(o, oe->default_str, NULL);
|
||||
return (o);
|
||||
}
|
||||
for (i = 0; oe->default_arr[i] != NULL; i++)
|
||||
options_array_set(o, i, oe->default_arr[i], 0, NULL);
|
||||
return (o);
|
||||
}
|
||||
|
||||
switch (oe->type) {
|
||||
case OPTIONS_TABLE_STRING:
|
||||
ov->string = xstrdup(oe->default_str);
|
||||
break;
|
||||
case OPTIONS_TABLE_STYLE:
|
||||
style_set(&ov->style, &grid_default_cell);
|
||||
style_parse(&ov->style, &grid_default_cell, oe->default_str);
|
||||
break;
|
||||
default:
|
||||
ov->number = oe->default_num;
|
||||
break;
|
||||
}
|
||||
return (o);
|
||||
}
|
||||
|
||||
@@ -225,11 +285,10 @@ options_remove(struct options_entry *o)
|
||||
{
|
||||
struct options *oo = o->owner;
|
||||
|
||||
if (OPTIONS_IS_STRING(o))
|
||||
free(o->string);
|
||||
else if (OPTIONS_IS_ARRAY(o))
|
||||
if (OPTIONS_IS_ARRAY(o))
|
||||
options_array_clear(o);
|
||||
|
||||
else
|
||||
options_value_free(o, &o->value);
|
||||
RB_REMOVE(options_tree, &oo->tree, o);
|
||||
free(o);
|
||||
}
|
||||
@@ -252,14 +311,14 @@ options_array_item(struct options_entry *o, u_int idx)
|
||||
struct options_array_item a;
|
||||
|
||||
a.index = idx;
|
||||
return (RB_FIND(options_array, &o->array, &a));
|
||||
return (RB_FIND(options_array, &o->value.array, &a));
|
||||
}
|
||||
|
||||
static void
|
||||
options_array_free(struct options_entry *o, struct options_array_item *a)
|
||||
{
|
||||
free(a->value);
|
||||
RB_REMOVE(options_array, &o->array, a);
|
||||
options_value_free(o, &a->value);
|
||||
RB_REMOVE(options_array, &o->value.array, a);
|
||||
free(a);
|
||||
}
|
||||
|
||||
@@ -271,11 +330,11 @@ options_array_clear(struct options_entry *o)
|
||||
if (!OPTIONS_IS_ARRAY(o))
|
||||
return;
|
||||
|
||||
RB_FOREACH_SAFE(a, options_array, &o->array, a1)
|
||||
RB_FOREACH_SAFE(a, options_array, &o->value.array, a1)
|
||||
options_array_free(o, a);
|
||||
}
|
||||
|
||||
const char *
|
||||
union options_value *
|
||||
options_array_get(struct options_entry *o, u_int idx)
|
||||
{
|
||||
struct options_array_item *a;
|
||||
@@ -285,18 +344,39 @@ options_array_get(struct options_entry *o, u_int idx)
|
||||
a = options_array_item(o, idx);
|
||||
if (a == NULL)
|
||||
return (NULL);
|
||||
return (a->value);
|
||||
return (&a->value);
|
||||
}
|
||||
|
||||
int
|
||||
options_array_set(struct options_entry *o, u_int idx, const char *value,
|
||||
int append)
|
||||
int append, char **cause)
|
||||
{
|
||||
struct options_array_item *a;
|
||||
char *new;
|
||||
struct cmd_parse_result *pr;
|
||||
|
||||
if (!OPTIONS_IS_ARRAY(o))
|
||||
if (!OPTIONS_IS_ARRAY(o)) {
|
||||
if (cause != NULL)
|
||||
*cause = xstrdup("not an array");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (OPTIONS_IS_COMMAND(o) && value != NULL) {
|
||||
pr = cmd_parse_from_string(value, NULL);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_EMPTY:
|
||||
*cause = xstrdup("empty command");
|
||||
return (-1);
|
||||
case CMD_PARSE_ERROR:
|
||||
if (cause != NULL)
|
||||
*cause = pr->error;
|
||||
else
|
||||
free(pr->error);
|
||||
return (-1);
|
||||
case CMD_PARSE_SUCCESS:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
a = options_array_item(o, idx);
|
||||
if (value == NULL) {
|
||||
@@ -305,25 +385,29 @@ options_array_set(struct options_entry *o, u_int idx, const char *value,
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (OPTIONS_IS_STRING(o)) {
|
||||
if (a != NULL && append)
|
||||
xasprintf(&new, "%s%s", a->value.string, value);
|
||||
else
|
||||
new = xstrdup(value);
|
||||
}
|
||||
|
||||
if (a == NULL) {
|
||||
a = xcalloc(1, sizeof *a);
|
||||
a->index = idx;
|
||||
a->value = xstrdup(value);
|
||||
RB_INSERT(options_array, &o->array, a);
|
||||
} else {
|
||||
free(a->value);
|
||||
if (a != NULL && append)
|
||||
xasprintf(&new, "%s%s", a->value, value);
|
||||
else
|
||||
new = xstrdup(value);
|
||||
a->value = new;
|
||||
}
|
||||
RB_INSERT(options_array, &o->value.array, a);
|
||||
} else
|
||||
options_value_free(o, &a->value);
|
||||
|
||||
if (OPTIONS_IS_STRING(o))
|
||||
a->value.string = new;
|
||||
else if (OPTIONS_IS_COMMAND(o))
|
||||
a->value.cmdlist = pr->cmdlist;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
options_array_assign(struct options_entry *o, const char *s)
|
||||
int
|
||||
options_array_assign(struct options_entry *o, const char *s, char **cause)
|
||||
{
|
||||
const char *separator;
|
||||
char *copy, *next, *string;
|
||||
@@ -332,7 +416,18 @@ options_array_assign(struct options_entry *o, const char *s)
|
||||
separator = o->tableentry->separator;
|
||||
if (separator == NULL)
|
||||
separator = " ,";
|
||||
if (*separator == '\0') {
|
||||
if (*s == '\0')
|
||||
return (0);
|
||||
for (i = 0; i < UINT_MAX; i++) {
|
||||
if (options_array_item(o, i) == NULL)
|
||||
break;
|
||||
}
|
||||
return (options_array_set(o, i, s, 0, cause));
|
||||
}
|
||||
|
||||
if (*s == '\0')
|
||||
return (0);
|
||||
copy = string = xstrdup(s);
|
||||
while ((next = strsep(&string, separator)) != NULL) {
|
||||
if (*next == '\0')
|
||||
@@ -343,9 +438,13 @@ options_array_assign(struct options_entry *o, const char *s)
|
||||
}
|
||||
if (i == UINT_MAX)
|
||||
break;
|
||||
options_array_set(o, i, next, 0);
|
||||
if (options_array_set(o, i, next, 0, cause) != 0) {
|
||||
free(copy);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
free(copy);
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct options_array_item *
|
||||
@@ -353,13 +452,13 @@ options_array_first(struct options_entry *o)
|
||||
{
|
||||
if (!OPTIONS_IS_ARRAY(o))
|
||||
return (NULL);
|
||||
return (RB_MIN(options_array, &o->array));
|
||||
return (RB_MIN(options_array, &o->value.array));
|
||||
}
|
||||
|
||||
struct options_array_item *
|
||||
options_array_next(struct options_array_item *a)
|
||||
{
|
||||
return (RB_NEXT(options_array, &o->array, a));
|
||||
return (RB_NEXT(options_array, &o->value.array, a));
|
||||
}
|
||||
|
||||
u_int
|
||||
@@ -368,10 +467,10 @@ options_array_item_index(struct options_array_item *a)
|
||||
return (a->index);
|
||||
}
|
||||
|
||||
const char *
|
||||
union options_value *
|
||||
options_array_item_value(struct options_array_item *a)
|
||||
{
|
||||
return (a->value);
|
||||
return (&a->value);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -383,59 +482,23 @@ options_isarray(struct options_entry *o)
|
||||
int
|
||||
options_isstring(struct options_entry *o)
|
||||
{
|
||||
return (OPTIONS_IS_STRING(o) || OPTIONS_IS_ARRAY(o));
|
||||
return (OPTIONS_IS_STRING(o));
|
||||
}
|
||||
|
||||
const char *
|
||||
char *
|
||||
options_tostring(struct options_entry *o, int idx, int numeric)
|
||||
{
|
||||
static char s[1024];
|
||||
const char *tmp;
|
||||
struct options_array_item *a;
|
||||
|
||||
if (OPTIONS_IS_ARRAY(o)) {
|
||||
if (idx == -1)
|
||||
return (NULL);
|
||||
return (xstrdup(""));
|
||||
a = options_array_item(o, idx);
|
||||
if (a == NULL)
|
||||
return ("");
|
||||
return (a->value);
|
||||
return (xstrdup(""));
|
||||
return (options_value_tostring(o, &a->value, numeric));
|
||||
}
|
||||
if (OPTIONS_IS_STYLE(o))
|
||||
return (style_tostring(&o->style));
|
||||
if (OPTIONS_IS_NUMBER(o)) {
|
||||
tmp = NULL;
|
||||
switch (o->tableentry->type) {
|
||||
case OPTIONS_TABLE_NUMBER:
|
||||
xsnprintf(s, sizeof s, "%lld", o->number);
|
||||
break;
|
||||
case OPTIONS_TABLE_KEY:
|
||||
tmp = key_string_lookup_key(o->number);
|
||||
break;
|
||||
case OPTIONS_TABLE_COLOUR:
|
||||
tmp = colour_tostring(o->number);
|
||||
break;
|
||||
case OPTIONS_TABLE_FLAG:
|
||||
if (numeric)
|
||||
xsnprintf(s, sizeof s, "%lld", o->number);
|
||||
else
|
||||
tmp = (o->number ? "on" : "off");
|
||||
break;
|
||||
case OPTIONS_TABLE_CHOICE:
|
||||
tmp = o->tableentry->choices[o->number];
|
||||
break;
|
||||
case OPTIONS_TABLE_STRING:
|
||||
case OPTIONS_TABLE_STYLE:
|
||||
case OPTIONS_TABLE_ARRAY:
|
||||
break;
|
||||
}
|
||||
if (tmp != NULL)
|
||||
xsnprintf(s, sizeof s, "%s", tmp);
|
||||
return (s);
|
||||
}
|
||||
if (OPTIONS_IS_STRING(o))
|
||||
return (o->string);
|
||||
return (NULL);
|
||||
return (options_value_tostring(o, &o->value, numeric));
|
||||
}
|
||||
|
||||
char *
|
||||
@@ -549,7 +612,7 @@ options_get_string(struct options *oo, const char *name)
|
||||
fatalx("missing option %s", name);
|
||||
if (!OPTIONS_IS_STRING(o))
|
||||
fatalx("option %s is not a string", name);
|
||||
return (o->string);
|
||||
return (o->value.string);
|
||||
}
|
||||
|
||||
long long
|
||||
@@ -562,7 +625,7 @@ options_get_number(struct options *oo, const char *name)
|
||||
fatalx("missing option %s", name);
|
||||
if (!OPTIONS_IS_NUMBER(o))
|
||||
fatalx("option %s is not a number", name);
|
||||
return (o->number);
|
||||
return (o->value.number);
|
||||
}
|
||||
|
||||
struct style *
|
||||
@@ -575,7 +638,7 @@ options_get_style(struct options *oo, const char *name)
|
||||
fatalx("missing option %s", name);
|
||||
if (!OPTIONS_IS_STYLE(o))
|
||||
fatalx("option %s is not a style", name);
|
||||
return (&o->style);
|
||||
return (&o->value.style);
|
||||
}
|
||||
|
||||
struct options_entry *
|
||||
@@ -592,7 +655,7 @@ options_set_string(struct options *oo, const char *name, int append,
|
||||
|
||||
o = options_get_only(oo, name);
|
||||
if (o != NULL && append && OPTIONS_IS_STRING(o)) {
|
||||
xasprintf(&value, "%s%s", o->string, s);
|
||||
xasprintf(&value, "%s%s", o->value.string, s);
|
||||
free(s);
|
||||
} else
|
||||
value = s;
|
||||
@@ -606,8 +669,8 @@ options_set_string(struct options *oo, const char *name, int append,
|
||||
|
||||
if (!OPTIONS_IS_STRING(o))
|
||||
fatalx("option %s is not a string", name);
|
||||
free(o->string);
|
||||
o->string = value;
|
||||
free(o->value.string);
|
||||
o->value.string = value;
|
||||
return (o);
|
||||
}
|
||||
|
||||
@@ -628,7 +691,7 @@ options_set_number(struct options *oo, const char *name, long long value)
|
||||
|
||||
if (!OPTIONS_IS_NUMBER(o))
|
||||
fatalx("option %s is not a number", name);
|
||||
o->number = value;
|
||||
o->value.number = value;
|
||||
return (o);
|
||||
}
|
||||
|
||||
@@ -644,7 +707,7 @@ options_set_style(struct options *oo, const char *name, int append,
|
||||
|
||||
o = options_get_only(oo, name);
|
||||
if (o != NULL && append && OPTIONS_IS_STYLE(o))
|
||||
style_copy(&sy, &o->style);
|
||||
style_copy(&sy, &o->value.style);
|
||||
else
|
||||
style_set(&sy, &grid_default_cell);
|
||||
if (style_parse(&sy, &grid_default_cell, value) == -1)
|
||||
@@ -657,7 +720,7 @@ options_set_style(struct options *oo, const char *name, int append,
|
||||
|
||||
if (!OPTIONS_IS_STYLE(o))
|
||||
fatalx("option %s is not a style", name);
|
||||
style_copy(&o->style, &sy);
|
||||
style_copy(&o->value.style, &sy);
|
||||
return (o);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,9 @@ char *osdep_get_name(int, char *);
|
||||
char *osdep_get_cwd(int);
|
||||
struct event_base *osdep_event_init(void);
|
||||
|
||||
#ifndef __unused
|
||||
#define __unused __attribute__ ((__unused__))
|
||||
#endif
|
||||
|
||||
char *
|
||||
osdep_get_name(int fd, __unused char *tty)
|
||||
@@ -47,6 +49,7 @@ osdep_get_name(int fd, __unused char *tty)
|
||||
&bsdinfo, sizeof bsdinfo);
|
||||
if (ret == sizeof bsdinfo && *bsdinfo.pbsi_comm != '\0')
|
||||
return (strdup(bsdinfo.pbsi_comm));
|
||||
return (NULL);
|
||||
#else
|
||||
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 };
|
||||
size_t size;
|
||||
|
||||
9
paste.c
9
paste.c
@@ -157,11 +157,14 @@ paste_free(struct paste_buffer *pb)
|
||||
* that the caller is responsible for allocating data.
|
||||
*/
|
||||
void
|
||||
paste_add(char *data, size_t size)
|
||||
paste_add(const char *prefix, char *data, size_t size)
|
||||
{
|
||||
struct paste_buffer *pb, *pb1;
|
||||
u_int limit;
|
||||
|
||||
if (prefix == NULL)
|
||||
prefix = "buffer";
|
||||
|
||||
if (size == 0) {
|
||||
free(data);
|
||||
return;
|
||||
@@ -180,7 +183,7 @@ paste_add(char *data, size_t size)
|
||||
pb->name = NULL;
|
||||
do {
|
||||
free(pb->name);
|
||||
xasprintf(&pb->name, "buffer%04u", paste_next_index);
|
||||
xasprintf(&pb->name, "%s%u", prefix, paste_next_index);
|
||||
paste_next_index++;
|
||||
} while (paste_get_name(pb->name) != NULL);
|
||||
|
||||
@@ -262,7 +265,7 @@ paste_set(char *data, size_t size, const char *name, char **cause)
|
||||
return (0);
|
||||
}
|
||||
if (name == NULL) {
|
||||
paste_add(data, size);
|
||||
paste_add(NULL, data, size);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
53
regress/command-order.sh
Normal file
53
regress/command-order.sh
Normal file
@@ -0,0 +1,53 @@
|
||||
#!/bin/sh
|
||||
|
||||
# new-session without clients should be the right size
|
||||
|
||||
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
|
||||
|
||||
cat <<EOF >$TMP
|
||||
new -sfoo -nfoo0; neww -nfoo1; neww -nfoo2
|
||||
new -sbar -nbar0; neww -nbar1; neww -nbar2
|
||||
EOF
|
||||
$TMUX -f$TMP start </dev/null || exit 1
|
||||
sleep 1
|
||||
$TMUX lsw -aF '#{session_name},#{window_name}'|sort >$TMP || exit 1
|
||||
cat <<EOF|cmp -s $TMP - || exit 1
|
||||
bar,bar0
|
||||
bar,bar1
|
||||
bar,bar2
|
||||
foo,foo0
|
||||
foo,foo1
|
||||
foo,foo2
|
||||
EOF
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
cat <<EOF >$TMP
|
||||
new -sfoo -nfoo0
|
||||
neww -nfoo1
|
||||
neww -nfoo2
|
||||
new -sbar -nbar0
|
||||
neww -nbar1
|
||||
neww -nbar2
|
||||
EOF
|
||||
$TMUX -f$TMP start </dev/null || exit 1
|
||||
sleep 1
|
||||
$TMUX lsw -aF '#{session_name},#{window_name}'|sort >$TMP || exit 1
|
||||
cat <<EOF|cmp -s $TMP - || exit 1
|
||||
bar,bar0
|
||||
bar,bar1
|
||||
bar,bar2
|
||||
foo,foo0
|
||||
foo,foo1
|
||||
foo,foo2
|
||||
EOF
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
exit 0
|
||||
14
regress/conf-syntax.sh
Normal file
14
regress/conf-syntax.sh
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
for i in conf/*.conf; do
|
||||
$TMUX -f/dev/null start \; source -n $i || exit 1
|
||||
done
|
||||
|
||||
exit 0
|
||||
58
regress/conf/29813ff35544434e2e64dc879a8dd274.conf
Normal file
58
regress/conf/29813ff35544434e2e64dc879a8dd274.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
set -g prefix C-g
|
||||
# needed for e.g. mutt
|
||||
bind C-g send-prefix
|
||||
|
||||
set -g set-titles on
|
||||
set -g status-position top
|
||||
set -g status-keys vi
|
||||
set -g mode-keys vi
|
||||
set -g base-index 1
|
||||
set -g pane-base-index 1
|
||||
set -g focus-events on
|
||||
|
||||
set history-file ~/.tmux_SSH_history
|
||||
set focus-events on
|
||||
set -g history-limit 100000
|
||||
set -s set-clipboard on
|
||||
set -g display-time 3000
|
||||
set -g display-panes-time 3000
|
||||
|
||||
set -g pane-border-status top
|
||||
|
||||
setw -g window-status-current-style bg=colour240,fg=colour250
|
||||
setw -g window-status-separator "|"
|
||||
set -g status-bg colour235
|
||||
set -g status-fg colour245
|
||||
|
||||
set -g window-status-format " #I #{=+15:pane_title} #{=-2:?window_flags, #{window_flags}, }"
|
||||
set -g window-status-current-format " #I #{=+15:pane_title} #{=-2:?window_flags, #{window_flags}, }"
|
||||
set -g pane-border-format " #P: #{s/ //:pane_title} "
|
||||
|
||||
set -g renumber-windows on
|
||||
set -g status-right-length 0
|
||||
##############################################################
|
||||
|
||||
# I prefer not to have a status for my tabbed term
|
||||
set -g status-right ""
|
||||
set -g status-right-length 0
|
||||
set -g status-left-length 0
|
||||
set -g status-left ""
|
||||
|
||||
# some settings for "navigation"
|
||||
bind -n C-PageUp copy-mode -u
|
||||
unbind -n C-Left
|
||||
unbind -n C-Right
|
||||
bind -n C-Left select-window -t :-
|
||||
bind -n C-Right select-window -t :+
|
||||
|
||||
# I prefer a tiled layout and easy joining of current active pane via windows'
|
||||
# index
|
||||
bind F1 join-pane -s 1.\; select-layout tiled
|
||||
bind F2 join-pane -s 2.\; select-layout tiled
|
||||
bind F3 join-pane -s 3.\; select-layout tiled
|
||||
bind F4 join-pane -s 4.\; select-layout tiled
|
||||
bind F5 join-pane -s 5.\; select-layout tiled
|
||||
bind F6 join-pane -s 6.\; select-layout tiled
|
||||
bind F7 join-pane -s 7.\; select-layout tiled
|
||||
bind F8 join-pane -s 8.\; select-layout tiled
|
||||
bind F9 join-pane -s 9.\; select-layout tiled
|
||||
56
regress/conf/2eae5d47049c1f6d0bef3db4e171aed7.conf
Normal file
56
regress/conf/2eae5d47049c1f6d0bef3db4e171aed7.conf
Normal file
@@ -0,0 +1,56 @@
|
||||
# 256 colors for vim
|
||||
set -g default-terminal "screen-256color"
|
||||
|
||||
# Set default shell to zsh
|
||||
set-option -g default-shell /bin/zsh
|
||||
|
||||
# Start window numbering at 1
|
||||
set-option -g base-index 1
|
||||
set-window-option -g pane-base-index 1
|
||||
|
||||
# Cycle panes with C-b C-b
|
||||
unbind ^B
|
||||
bind ^B select-pane -t :.+
|
||||
|
||||
# Reload config wtih a key
|
||||
bind-key r source-file ~/.tmux.conf \; display "Config reloaded!"
|
||||
|
||||
# Mouse works as expected
|
||||
# set -g mode-mouse on
|
||||
# set -g mouse-select-pane on
|
||||
# set -g mouse-resize-pane on
|
||||
# set -g mouse-select-window on
|
||||
|
||||
# Scrolling works as expected
|
||||
set -g terminal-overrides 'xterm*:smcup@:rmcup@'
|
||||
|
||||
# Use the system clipboard
|
||||
# set-option -g default-command "reattach-to-user-namespace -l zsh"
|
||||
|
||||
# Clear the pane and its history
|
||||
bind -n C-k send-keys C-l \; clear-history
|
||||
|
||||
# smart pane switching with awareness of vim splits
|
||||
bind -n C-h run "(tmux display-message -p '#{pane_current_command}' | grep -iq vim && tmux send-keys C-h) || tmux select-pane -L"
|
||||
bind -n C-j run "(tmux display-message -p '#{pane_current_command}' | grep -iq vim && tmux send-keys C-j) || tmux select-pane -D"
|
||||
bind -n C-k run "(tmux display-message -p '#{pane_current_command}' | grep -iq vim && tmux send-keys C-k) || tmux select-pane -U"
|
||||
bind -n C-l run "(tmux display-message -p '#{pane_current_command}' | grep -iq vim && tmux send-keys C-l) || tmux select-pane -R"
|
||||
bind -n C-\ run "(tmux display-message -p '#{pane_current_command}' | grep -iq vim && tmux send-keys 'C-\\') || tmux select-pane -l"
|
||||
|
||||
# C-l is taken oer by vim style pane navigation
|
||||
bind C-l send-keys 'C-l'
|
||||
|
||||
# Use vim keybindings in copy mode
|
||||
setw -g mode-keys vi
|
||||
|
||||
# Setup 'v' to begin selection as in Vim
|
||||
# bind-key -t vi-copy v begin-selection
|
||||
# bind-key -t vi-copy y copy-pipe "reattach-to-user-namespace pbcopy"
|
||||
|
||||
# Update default binding of `Enter` to also use copy-pipe
|
||||
# unbind -t vi-copy Enter
|
||||
# bind-key -t vi-copy Enter copy-pipe "reattach-to-user-namespace pbcopy"
|
||||
|
||||
# Powerline
|
||||
run-shell "powerline-daemon -q"
|
||||
source "/Users/adamcooper/Library/Python/3.7/lib/python/site-packages/powerline/bindings/tmux/powerline.conf"
|
||||
30
regress/conf/327af72ad372255817b585a74da06eda.conf
Normal file
30
regress/conf/327af72ad372255817b585a74da06eda.conf
Normal file
@@ -0,0 +1,30 @@
|
||||
set -sg escape-time 10
|
||||
|
||||
set -g default-terminal tmux-256color
|
||||
set -g prefix ^X
|
||||
set -g history-limit 10000
|
||||
setw -g mode-keys vi
|
||||
setw -g xterm-keys off
|
||||
|
||||
# black, red, green, yellow, blue, magenta, cyan, white, default.
|
||||
setw -g message-command-style fg=yellow,bg=black
|
||||
setw -g message-style fg=black,bg=yellow
|
||||
|
||||
%if #{m:*mydomain*,#{host}}
|
||||
set -g status-style fg=cyan,bg='#001040'
|
||||
setw -g window-status-current-style fg='#f0f0f0',bg='#001040'
|
||||
%elif #{||:#{m:*somedomain*,#{host}},#{m:*otherdomain*,#{host}}}
|
||||
set -g status-style fg=white,bg='#400040'
|
||||
setw -g window-status-current-style fg=yellow,bg='#400040',bright
|
||||
%else
|
||||
set -g status-style fg=white,bg='#800000'
|
||||
setw -g window-status-current-style fg=brightwhite,bg='#800000'
|
||||
%endif
|
||||
|
||||
unbind ^B
|
||||
bind ^X last-window
|
||||
bind x send-prefix
|
||||
bind ^C new-window
|
||||
bind ^D detach-client
|
||||
bind ^N next-window
|
||||
bind ^P previous-window
|
||||
118
regress/conf/58304907c117cab9898ea0b070bccde3.conf
Normal file
118
regress/conf/58304907c117cab9898ea0b070bccde3.conf
Normal file
@@ -0,0 +1,118 @@
|
||||
#
|
||||
# Tureba's tmux.conf
|
||||
#
|
||||
# To use it, either:
|
||||
# a) link ~/.tmux.conf to it; or
|
||||
# b) create a ~/.tmux.conf that sources it.
|
||||
#
|
||||
# who: Arthur Nascimento <tureba@gmail.com>
|
||||
# where: github.com/tureba/myconfigfiles
|
||||
#
|
||||
|
||||
# defaults
|
||||
set -g default-shell /bin/zsh
|
||||
set -g default-command zsh
|
||||
# tmux sets screen/screen-256, but has no codes for italics
|
||||
set -g default-terminal tmux-256color
|
||||
# linux terminal doesn't need this, but xterm does
|
||||
set -g terminal-overrides 'xterm*:smcup@:rmcup@,*256col*:colors=256,xterm*:XT'
|
||||
# xterm-style function key sequences
|
||||
setw -g xterm-keys on
|
||||
|
||||
# 1, 2 and 3 are closer together than 0, 1 and 2
|
||||
set -g base-index 1
|
||||
set -g pane-base-index 1
|
||||
|
||||
# easier to type than C-b
|
||||
set -g prefix C-a
|
||||
set -g prefix2 C-b
|
||||
unbind C-b
|
||||
bind C-a send-prefix
|
||||
|
||||
# for repeatable keys
|
||||
set -g repeat-time 170
|
||||
|
||||
# status bar
|
||||
set -g status-style fg=green,bg=colour234
|
||||
set -g status-right-style bg=colour236
|
||||
set -g status-right "#[bold,fg=blue][#[fg=default]#T#[fg=blue]]#[nobold,fg=default] | #[fg=yellow]%F %R"
|
||||
set -g status-right-length 120
|
||||
set -g status-left-style bg=colour236,bright
|
||||
set -g status-left "#[fg=blue][#[fg=default]#h#[fg=cyan]:#[fg=default]#S#[fg=blue]]"
|
||||
set -g status-left-length 30
|
||||
setw -g window-status-style fg=green
|
||||
setw -g window-status-format " #I#[nobold]:#W "
|
||||
setw -g window-status-current-style fg=green,bright
|
||||
setw -g window-status-current-format "#[fg=red][#[fg=default]#I:#W#[fg=red]]"
|
||||
setw -g window-status-separator "|"
|
||||
setw -g window-status-activity-style blink
|
||||
setw -g window-status-bell-style blink
|
||||
setw -g window-status-last-style bright
|
||||
|
||||
# enable wm window titles
|
||||
set -g set-titles on
|
||||
|
||||
# auto window rename
|
||||
setw -g automatic-rename on
|
||||
# auto window resize
|
||||
setw -g aggressive-resize on
|
||||
|
||||
# mouse settings
|
||||
set -g mouse on
|
||||
|
||||
# var|bind \ cmd | vim | less | copy | zsh
|
||||
# pane_in_mode | 0 | 0 | 1 | 0
|
||||
# mouse_any_flag | 1 | 0 | 0 | 0
|
||||
# alternate_on | 1 | 1 | 0 | 0
|
||||
# WheelUpPane | send -M | send Up | * | send Up (** or copy-mode -e)
|
||||
# WheelDownPane | send -M | send Down | * | send Down
|
||||
# * panes in copy mode have scroll handled by different bindings
|
||||
|
||||
# ** cycle over shell history
|
||||
#bind -T root WheelUpPane if -Ft= '#{mouse_any_flag}' 'send -Mt=' 'send -t= Up'
|
||||
|
||||
# ** enter copy mode
|
||||
bind -T root WheelUpPane if -Ft= '#{mouse_any_flag}' 'send -Mt=' 'if -Ft= "#{alternate_on}" "send -t= Up" "copy-mode -et="'
|
||||
|
||||
bind -T root WheelDownPane if -Ft= '#{mouse_any_flag}' 'send -Mt=' 'send -t= Down'
|
||||
|
||||
# sensible v/h splits
|
||||
unbind %
|
||||
unbind '"'
|
||||
bind | split-window -h
|
||||
bind - split-window -v
|
||||
|
||||
# hjkl pane traversal
|
||||
bind -r h select-pane -L
|
||||
bind -r j select-pane -D
|
||||
bind -r k select-pane -U
|
||||
bind -r l select-pane -R
|
||||
|
||||
# window navigation
|
||||
unbind p
|
||||
bind -r [ previous-window
|
||||
unbind n
|
||||
bind -r ] next-window
|
||||
|
||||
# Vi copypaste mode
|
||||
setw -g mode-keys vi
|
||||
bind C-c copy-mode
|
||||
bind p paste-buffer
|
||||
bind -T copy-mode-vi v send-keys -X begin-selection
|
||||
bind -T copy-mode-vi y send-keys -X copy-selection
|
||||
bind -T copy-mode-vi V send-keys -X rectangle-toggle
|
||||
|
||||
# toggle window activity monitoring
|
||||
bind m setw monitor-activity
|
||||
|
||||
# reload the configuration
|
||||
bind r source-file ~/.tmux.conf
|
||||
|
||||
# toggle synchronize-panes
|
||||
bind S setw synchronize-panes
|
||||
|
||||
# create a new window with exactly this command
|
||||
bind C command-prompt "new-window 'exec %%'"
|
||||
|
||||
# (toggle) mark this pane for easier joins and swaps
|
||||
bind . select-pane -m
|
||||
30
regress/conf/91378fd400b0444eb8cac471e30642b3.conf
Normal file
30
regress/conf/91378fd400b0444eb8cac471e30642b3.conf
Normal file
@@ -0,0 +1,30 @@
|
||||
###
|
||||
|
||||
if-shell " \
|
||||
tmux -V \
|
||||
| awk '{print $2}' \
|
||||
| awk -F - '{print $1}' \
|
||||
| awk '{ \
|
||||
if ($1 ~ /^[[:digit:].]+$/) { \
|
||||
exit !($1 >= 2.6) \
|
||||
} else { \
|
||||
exit !($1 == \"master\" || $1 == \"next\") \
|
||||
} \
|
||||
}'" \
|
||||
"source-file ~/.tmux/v2rc" \
|
||||
"source-file ~/.tmux/v1rc" \
|
||||
;
|
||||
|
||||
###
|
||||
|
||||
set-option -qg status-left \
|
||||
"[#[fg=yellow]#{session_name}#[default]] #[fg=colour060]#{host_short}#[default]:#[fg=colour151]#{b:pane_current_path} #[fg=colour099]#(git -C #{pane_current_path} symbolic-ref --short HEAD) #[fg=green]#(git -C #{pane_current_path} status --porcelain --untracked-files=no | cut -b 1-1 | sort | uniq | awk '/^[^[:space:]]/ {printf\(\"%%s\", $0\)}')#[fg=red]#(git -C #{pane_current_path} status --porcelain --untracked-files=no | cut -b 2-2 | sort | uniq | awk '/^[^[:space:]]/ {printf\(\"%%s\", $0\)}')#[fg=colour113]#(git -C #{pane_current_path} stash list 2>/dev/null | wc -l | tr -d '\n' | sed s,^0\$,,) #[default]"
|
||||
|
||||
set-option -qg status-right \
|
||||
"#[default] ┊ #[fg=colour065]#(grep ^MemFree /proc/meminfo | awk '{print rshift\($2, 10\)}')#[fg=colour071]m #[default]┊ #[fg=colour101]#(echo \"\(`awk '{print \$1}' /proc/loadavg` / `grep ^processor /proc/cpuinfo | wc -l`\) \* 100\" | bc -ql | sed 's,\\..*,,' | awk '{printf\(\"%%2u\", $0\)}')#[fg=colour102]%% "
|
||||
|
||||
set-option -qwg window-status-current-format \
|
||||
"#[fg=colour208]»#[fg=colour190]#{window_name}#[fg=colour037]·#{?window_flags,#[fg=colour058]#{window_flags}#[default], #[default]}"
|
||||
|
||||
set-option -qwg window-status-format \
|
||||
"#[default]»#[fg=colour066]#{window_name}#[fg=colour037]·#{?window_flags,#[fg=colour058]#{window_flags}#[default], #[default]}"
|
||||
432
regress/conf/a46e6e84cd1071105aa807256dbc158d.conf
Normal file
432
regress/conf/a46e6e84cd1071105aa807256dbc158d.conf
Normal file
@@ -0,0 +1,432 @@
|
||||
# Dynamic configuration file generated by ~/Makefile from /home/sunny/.tmux.conf.erb
|
||||
#
|
||||
# DO NOT EDIT THIS FILE BY HAND --
|
||||
# YOUR CHANGES WILL BE OVERWRITTEN
|
||||
#
|
||||
|
||||
|
||||
|
||||
bind-key R source ~/.tmux.conf \; display-message 'config reloaded!'
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# terminal
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# enable mouse support for general selection and control
|
||||
set-option -g mouse on
|
||||
|
||||
# auto-set terminal title to current window pane's title
|
||||
set-option -g set-titles on
|
||||
|
||||
# enable 256-color support for pretty colorschemes in Vim
|
||||
set-option -g default-terminal 'screen-256color'
|
||||
|
||||
# allow Vim to receive focus events from terminal window
|
||||
set-option -g focus-events on
|
||||
|
||||
# allow Vim to recieve modifier keys: Shift, Control, Alt
|
||||
set-window-option -g xterm-keys on
|
||||
|
||||
# prevent tmux from catching modifier keys meant for Vim
|
||||
set-option -s escape-time 0
|
||||
|
||||
# enable 24-bit true color RGB escape sequences under st
|
||||
# https://sunaku.github.io/tmux-24bit-color.html
|
||||
set-option -ga terminal-overrides ',st-256color:Tc'
|
||||
set-option -ga terminal-overrides ',xterm-256color:Tc' # hterm (ChromeOS)
|
||||
|
||||
# allow set-titles to change the window title under XTerm
|
||||
# http://opennomad.com/content/goodbye-screen-hello-tmux
|
||||
set-option -ga terminal-overrides ',xterm*:XT'
|
||||
|
||||
# allow set-titles to change the window title under XTerm
|
||||
# http://opennomad.com/content/goodbye-screen-hello-tmux
|
||||
# http://stackoverflow.com/questions/15195624
|
||||
set-option -ga terminal-overrides ',st-256color:smkx=\E='
|
||||
|
||||
# yank to system clipboard rather than primary selection
|
||||
# http://invisible-island.net/xterm/terminfo-contents.html#tic-xterm_tmux
|
||||
set-option -ga terminal-overrides ',xterm*:Ms=\E]52;c;%p2%s\007'
|
||||
|
||||
# KiTTY always appends to clipboard; must clear it first
|
||||
# https://sw.kovidgoyal.net/kitty/protocol-extensions.html#pasting-to-clipboard
|
||||
set-option -ga terminal-overrides ',xterm-kitty:Ms=\E]52;c;!\007\E]52;c;%p2%s\007'
|
||||
|
||||
# prevent standout from appearing as italics under URxvt
|
||||
# http://comments.gmane.org/gmane.comp.terminal-emulators.tmux.user/1927
|
||||
set-option -ga terminal-overrides ',rxvt-unicode*:sitm@'
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# appearance
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Colors from the "lucius" and "gruvbox" themes in the vim-airline plugin:
|
||||
# https://github.com/bling/vim-airline/blob/master/autoload/airline/themes/lucius.vim
|
||||
# https://github.com/morhetz/gruvbox/blob/master/autoload/airline/themes/gruvbox.vim
|
||||
|
||||
set-option -g status-style fg=colour246,bg=colour237
|
||||
set-window-option -g window-status-current-style fg=colour214,bg=colour239
|
||||
set-option -g pane-border-style fg=colour239
|
||||
set-option -g pane-active-border-style fg=colour208
|
||||
set-option -g message-style fg=colour214,bg=colour239
|
||||
set-window-option -g mode-style fg=colour214,bg=colour239,bold,reverse
|
||||
|
||||
# Common UI interaction cues from Blueprint CSS:
|
||||
# http://blueprintcss.org/tests/parts/forms.html
|
||||
set-window-option -g window-status-bell-style 'bg=#205791,fg=#d5edf8' # info (blue)
|
||||
set-window-option -g window-status-activity-style 'bg=#8a1f11,fg=#fbe3e4' # error (red)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# status bar
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# toggle status bar visibility
|
||||
bind-key -n M-` set-option -g status
|
||||
|
||||
# toggle status bar position
|
||||
bind-key -n M-~ \
|
||||
if-shell 'tmux show-option -g status-position | grep -q top$' \
|
||||
'set-option -g status-position bottom' \
|
||||
'set-option -g status-position top'
|
||||
|
||||
# put status bar at the top of the screen
|
||||
set-option -g status-position top
|
||||
|
||||
# list windows on left side of status bar
|
||||
set-option -g status-left-length 0
|
||||
|
||||
# make window list easier to scan
|
||||
set-window-option -g window-status-format ' #[bold]#I#F#[nobold]#W '
|
||||
set-window-option -g window-status-current-format ' #[bold]#I#F#[nobold]#W '
|
||||
set-window-option -g window-status-separator ''
|
||||
|
||||
# show pane title, pane identifier, and hostname on right side of status bar
|
||||
set-option -g status-right-length 64
|
||||
set-option -g status-right '#{=32:pane_title} \
|
||||
#[fg=colour214,bg=colour239] #S:#I.#P \
|
||||
#(test -n "$SSH_TTY" && echo "#[fg=colour214,bg=colour239,bold,reverse] #H ")'
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# windows
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# create window
|
||||
bind-key -n M-e new-window
|
||||
|
||||
# rename window
|
||||
bind-key -n M-E command-prompt -I '#W' 'rename-window "%%%"'
|
||||
|
||||
set-window-option -g automatic-rename off
|
||||
|
||||
|
||||
# break off pane to a new window
|
||||
bind-key -n M-x \
|
||||
command-prompt -p 'break-pane:' -I '#W' \
|
||||
'break-pane ; rename-window "%%%"'
|
||||
bind-key -n M-X break-pane
|
||||
|
||||
# focus window
|
||||
bind-key -n M-, previous-window
|
||||
bind-key -n M-. next-window
|
||||
bind-key -n M-o last-window
|
||||
|
||||
# focus by number
|
||||
set-option -g base-index 1
|
||||
set-window-option -g pane-base-index 1
|
||||
set-option -g renumber-windows on
|
||||
bind-key -n M-0 choose-window
|
||||
bind-key -n M-1 select-window -t :1
|
||||
bind-key -n M-2 select-window -t :2
|
||||
bind-key -n M-3 select-window -t :3
|
||||
bind-key -n M-4 select-window -t :4
|
||||
bind-key -n M-5 select-window -t :5
|
||||
bind-key -n M-6 select-window -t :6
|
||||
bind-key -n M-7 select-window -t :7
|
||||
bind-key -n M-8 select-window -t :8
|
||||
bind-key -n M-9 select-window -t :1 \; select-window -t :-1
|
||||
|
||||
# swap window
|
||||
bind-key -n M-< swap-window -t :-1
|
||||
bind-key -n M-> swap-window -t :+1
|
||||
|
||||
# monitor window
|
||||
set-option -g visual-activity on
|
||||
set-option -g visual-silence on
|
||||
|
||||
|
||||
bind-key -n M-k \
|
||||
set-window-option monitor-activity \;\
|
||||
display-message 'monitor-activity #{?monitor-activity,on,off}'
|
||||
|
||||
bind-key -n M-K \
|
||||
if-shell 'tmux show-window-option -g monitor-activity | grep -q off$' \
|
||||
'set-window-option -g monitor-activity on' \
|
||||
'set-window-option -g monitor-activity off' \;\
|
||||
display-message 'monitor-activity #{?monitor-activity,on,off} (global)'
|
||||
|
||||
bind-key -n M-j \
|
||||
command-prompt -p 'monitor-silence (seconds):' -I '#{monitor-silence}' \
|
||||
'set-window-option monitor-silence %% ;\
|
||||
display-message "monitor-silence #{?monitor-silence,on,off}"'
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# panes
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# send input to all panes in window (toggle)
|
||||
bind-key C-a \
|
||||
set-option synchronize-panes \;\
|
||||
display-message 'synchronize-panes #{?synchronize-panes,on,off}'
|
||||
|
||||
# clear the screen in all panes in window
|
||||
bind-key C-l \
|
||||
set-option synchronize-panes on \;\
|
||||
send-keys C-l \;\
|
||||
set-option synchronize-panes off
|
||||
|
||||
# create pane (below, above, left, right)
|
||||
bind-key -n M-c split-window -c '#{pane_current_path}'
|
||||
bind-key -n M-C split-window -c '#{pane_current_path}' -b
|
||||
bind-key -n M-R split-window -c '#{pane_current_path}' -b -h
|
||||
bind-key -n M-r split-window -c '#{pane_current_path}' -h
|
||||
|
||||
# join pane (above, left, below, right)
|
||||
bind-key -n M-g move-pane -t .-1 -s . # join pane at bottom of prev pane
|
||||
bind-key -n M-l move-pane -t .-1 -s . -h # join pane at right of prev pane
|
||||
bind-key -n M-G move-pane -d -s .+1 -t . # join next pane at bottom
|
||||
bind-key -n M-L move-pane -d -s .+1 -t . -h # join next pane at right
|
||||
|
||||
# Intelligently navigate tmux panes and Vim splits using the same keys.
|
||||
# See https://sunaku.github.io/tmux-select-pane.html for documentation.
|
||||
#
|
||||
# +-------------+------------+-----------------------------+
|
||||
# | inside Vim? | is Zoomed? | Action taken by key binding |
|
||||
# +-------------+------------+-----------------------------+
|
||||
# | No | No | Focus directional tmux pane |
|
||||
# | No | Yes | Nothing: ignore key binding |
|
||||
# | Yes | No | Seamlessly focus Vim / tmux |
|
||||
# | Yes | Yes | Focus directional Vim split |
|
||||
# +-------------+------------+-----------------------------+
|
||||
#
|
||||
vim_navigation_timeout=0.05 # number of seconds we give Vim to navigate
|
||||
navigate=' \
|
||||
pane_is_zoomed() { \
|
||||
test #{window_zoomed_flag} -eq 1; \
|
||||
}; \
|
||||
pane_title_changed() { \
|
||||
test "#{pane_title}" != "$(tmux display -p "##{pane_title}")"; \
|
||||
}; \
|
||||
command_is_vim() { \
|
||||
case "${1%% *}" in \
|
||||
(vi|?vi|vim*|?vim*|view|?view|vi??*) true ;; \
|
||||
(*) false ;; \
|
||||
esac; \
|
||||
}; \
|
||||
pane_contains_vim() { \
|
||||
case "#{=3:pane_current_command}" in \
|
||||
(git|ssh|sh) command_is_vim "#{=5:pane_title}" ;; \
|
||||
(*) command_is_vim "#{=5:pane_current_command}" ;; \
|
||||
esac; \
|
||||
}; \
|
||||
pane_contains_neovim_terminal() { \
|
||||
test "#{=12:pane_title}" = "nvim term://"; \
|
||||
}; \
|
||||
navigate() { \
|
||||
tmux_navigation_command=$1; \
|
||||
vim_navigation_command=$2; \
|
||||
vim_navigation_only_if=${3:-true}; \
|
||||
if pane_contains_vim && eval "$vim_navigation_only_if"; then \
|
||||
if pane_contains_neovim_terminal; then \
|
||||
tmux send-keys C-\\ C-n; \
|
||||
fi; \
|
||||
eval "$vim_navigation_command"; \
|
||||
if ! pane_is_zoomed; then \
|
||||
sleep $vim_navigation_timeout; : wait for Vim to change title; \
|
||||
if ! pane_title_changed; then \
|
||||
eval "$tmux_navigation_command"; \
|
||||
fi; \
|
||||
fi; \
|
||||
elif ! pane_is_zoomed; then \
|
||||
eval "$tmux_navigation_command"; \
|
||||
fi; \
|
||||
}; \
|
||||
navigate '
|
||||
navigate_left=" $navigate 'tmux select-pane -L' 'tmux send-keys C-w h'"
|
||||
navigate_down=" $navigate 'tmux select-pane -D' 'tmux send-keys C-w j'"
|
||||
navigate_up=" $navigate 'tmux select-pane -U' 'tmux send-keys C-w k'"
|
||||
navigate_right="$navigate 'tmux select-pane -R' 'tmux send-keys C-w l'"
|
||||
navigate_back=" $navigate 'tmux select-pane -l || tmux select-pane -t1'\
|
||||
'tmux send-keys C-w p' \
|
||||
'pane_is_zoomed' "
|
||||
|
||||
## QWERTY keys - comment these out if you don't use QWERTY layout!
|
||||
#bind-key -n M-h run-shell -b "$navigate_left"
|
||||
#bind-key -n M-j run-shell -b "$navigate_down"
|
||||
#bind-key -n M-k run-shell -b "$navigate_up"
|
||||
#bind-key -n M-l run-shell -b "$navigate_right"
|
||||
#bind-key -n M-\ run-shell -b "$navigate_back"
|
||||
|
||||
# Dvorak keys - comment these out if you don't use Dvorak layout!
|
||||
bind-key -n M-d run-shell -b "$navigate_back"
|
||||
bind-key -n M-h run-shell -b "$navigate_left"
|
||||
bind-key -n M-t run-shell -b "$navigate_up"
|
||||
bind-key -n M-n run-shell -b "$navigate_down"
|
||||
bind-key -n M-s run-shell -b "$navigate_right"
|
||||
|
||||
# resize pane
|
||||
bind-key -r H resize-pane -L 5
|
||||
bind-key -r T resize-pane -U 5
|
||||
bind-key -r N resize-pane -D 5
|
||||
bind-key -r S resize-pane -R 5
|
||||
|
||||
# zoom pane
|
||||
bind-key -n M-m resize-pane -Z
|
||||
|
||||
# swap pane
|
||||
bind-key -n M-- swap-pane -D
|
||||
bind-key -n M-_ swap-pane -U
|
||||
bind-key -n M-D run-shell 'tmux select-pane -l \; swap-pane -d -s #D'
|
||||
bind-key -n M-H run-shell 'tmux select-pane -L \; swap-pane -d -s #D'
|
||||
bind-key -n M-T run-shell 'tmux select-pane -U \; swap-pane -d -s #D'
|
||||
bind-key -n M-N run-shell 'tmux select-pane -D \; swap-pane -d -s #D'
|
||||
bind-key -n M-S run-shell 'tmux select-pane -R \; swap-pane -d -s #D'
|
||||
|
||||
# attach by number
|
||||
bind-key -n 'M-!' join-pane -t :1
|
||||
bind-key -n 'M-@' join-pane -t :2
|
||||
bind-key -n 'M-#' join-pane -t :3
|
||||
bind-key -n 'M-$' join-pane -t :4
|
||||
bind-key -n 'M-%' join-pane -t :5
|
||||
bind-key -n 'M-^' join-pane -t :6
|
||||
bind-key -n 'M-&' join-pane -t :7
|
||||
bind-key -n 'M-*' join-pane -t :8
|
||||
bind-key -n 'M-(' run-shell 'tmux select-window -t :1 \;\
|
||||
select-window -t :-1 \;\
|
||||
join-pane -s "#{pane_id}"'
|
||||
bind-key -n 'M-)' choose-window 'join-pane -t "%%%"'
|
||||
|
||||
# promote pane (toggle)
|
||||
bind-key -n M-Enter \
|
||||
if-shell 'test #P -ne 1' \
|
||||
'select-pane -t 1' \
|
||||
'last-pane; swap-pane -s 1'
|
||||
|
||||
# rotate panes
|
||||
bind-key -n M-a rotate-window -D
|
||||
bind-key -n M-A rotate-window -U
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# layouts
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
bind-key M-w select-layout main-horizontal
|
||||
bind-key M-W select-layout even-vertical
|
||||
bind-key M-v select-layout main-vertical
|
||||
bind-key M-V select-layout even-horizontal
|
||||
bind-key M-z select-layout tiled
|
||||
|
||||
# half-screen tiling layouts (horizontal, vertical)
|
||||
# https://sunaku.github.io/tmux-half-screen-tiling-layouts.html
|
||||
bind-key -n M-w select-layout main-horizontal \;\
|
||||
run-shell 'tmux resize-pane -t 1 -y $(( #{window_height} / 2 ))'
|
||||
bind-key -n M-v select-layout main-vertical \;\
|
||||
run-shell 'tmux resize-pane -t 1 -x $(( #{window_width} / 2 ))'
|
||||
|
||||
# binary space partitioned layouts (dwindle, spiral)
|
||||
# https://sunaku.github.io/tmux-layout-dwindle.html
|
||||
bind-key -n M-w run-shell 'tmux-layout-dwindle brhc && tmux-redraw-vim'
|
||||
bind-key -n M-W run-shell 'tmux-layout-dwindle trhc && tmux-redraw-vim'
|
||||
bind-key -n M-v run-shell 'tmux-layout-dwindle brvc && tmux-redraw-vim'
|
||||
bind-key -n M-V run-shell 'tmux-layout-dwindle blvc && tmux-redraw-vim'
|
||||
bind-key -n M-z select-layout tiled
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# scrollback buffer
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# buffer length
|
||||
set-option -g history-limit 32767
|
||||
|
||||
# search buffer using copy mode
|
||||
bind-key -n M-/ copy-mode \;\
|
||||
command-prompt -p 'search-backward (press up):' \
|
||||
-i 'send-keys -X search-backward-incremental "%%%"'
|
||||
|
||||
# search buffer using Vim or less
|
||||
bind-key -n M-| \
|
||||
capture-pane -J -S - \; \
|
||||
new-window -n '#S:#I.#P' -a ' \
|
||||
tmux save-buffer - \; delete-buffer | { \
|
||||
if command -v vim; \
|
||||
then vim -R -c "set nofen is hls ic" -; \
|
||||
else less; \
|
||||
fi; \
|
||||
}; \
|
||||
' \; \
|
||||
run-shell 'tmux send-keys G \?'
|
||||
|
||||
# search colored buffer using less
|
||||
bind-key -n M-? \
|
||||
capture-pane -e -J -S - \; \
|
||||
new-window -n '#S:#I.#P' -a ' \
|
||||
tmux save-buffer - \; delete-buffer | \
|
||||
less -R \
|
||||
' \; \
|
||||
run-shell 'tmux send-keys G \?'
|
||||
|
||||
# scroll buffer
|
||||
# NOTE: set "URxvt.saveLines: 0" in ~/.Xdefaults to make Shift+PageUp bindable
|
||||
# NOTE: see http://aperiodic.net/screen/interface for doing the same in XTerm
|
||||
bind-key -n S-PPage copy-mode -u
|
||||
|
||||
# copy text from buffer
|
||||
bind-key -n M-u copy-mode
|
||||
set-window-option -g mode-keys vi
|
||||
bind-key -T copy-mode-vi v send-keys -X begin-selection
|
||||
bind-key -T copy-mode-vi y send-keys -X copy-selection
|
||||
bind-key -T copy-mode-vi - send-keys -X jump-again
|
||||
bind-key -T copy-mode-vi _ send-keys -X jump-reverse
|
||||
bind-key -T copy-mode-vi ? command-prompt -p 'search-backward:' -I '#{pane_search_string}' -i 'send-keys -X search-backward-incremental "%%%"'
|
||||
bind-key -T copy-mode-vi / command-prompt -p 'search-forward:' -I '#{pane_search_string}' -i 'send-keys -X search-forward-incremental "%%%"'
|
||||
|
||||
# transfer copied text to attached terminal with yank:
|
||||
# https://github.com/sunaku/home/blob/master/bin/yank
|
||||
bind-key -T copy-mode-vi Y send-keys -X copy-pipe 'yank > #{pane_tty}'
|
||||
# open the visual selection with xdg-open(1)
|
||||
bind-key -T copy-mode-vi O send-keys -X copy-pipe 'xargs -r xdg-open'
|
||||
|
||||
# paste most-recently copied text
|
||||
bind-key -n M-i paste-buffer
|
||||
|
||||
# paste previously copied text (chosen from a menu)
|
||||
bind-key -n M-I choose-buffer
|
||||
|
||||
# transfer most-recently copied text to attached terminal with yank:
|
||||
# https://github.com/sunaku/home/blob/master/bin/yank
|
||||
bind-key -n M-y run-shell 'tmux save-buffer - | yank > #{pane_tty}'
|
||||
|
||||
# transfer previously copied text (chosen from a menu) to attached terminal:
|
||||
# https://github.com/sunaku/home/blob/master/bin/yank
|
||||
bind-key -n M-Y choose-buffer 'run-shell "tmux save-buffer -b \"%%%\" - | yank > #{pane_tty}"'
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# TMUX plugin manager https://github.com/tmux-plugins/tpm
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
set -g @plugin 'tmux-plugins/tmux-resurrect'
|
||||
set -g @resurrect-capture-pane-contents on
|
||||
|
||||
set -g @plugin 'Morantron/tmux-fingers'
|
||||
set -g @fingers-key '-n M-U'
|
||||
set -g @fingers-compact-hints 1
|
||||
set -g @fingers-hint-format '#[fg=yellow,bold,reverse]%s'
|
||||
set -g @fingers-hint-labels ' \
|
||||
a o e u i d h t n s \
|
||||
p y f g c r l \
|
||||
q j k x b m w v z \
|
||||
A O E U I D H T N S \
|
||||
P Y F G C R L \
|
||||
Q J K X B M W V Z \
|
||||
'
|
||||
|
||||
run-shell ~/.tmux/plugins/tpm/tpm
|
||||
80
regress/conf/a4789a6782859c66aa8c9614ee6fabfa.conf
Normal file
80
regress/conf/a4789a6782859c66aa8c9614ee6fabfa.conf
Normal file
@@ -0,0 +1,80 @@
|
||||
set -g default-command "if [ \"$(uname)\" = 'Darwin' ]; then exec reattach-to-user-namespace $SHELL; else exec $SHELL; fi"
|
||||
set -g history-limit 32000
|
||||
set -g update-environment "DISPLAY WINDOWID SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION SSH_CLIENT SSH_TTY KRB5CCNAME Apple_PubSub_Socket_Render Apple_Ubiquity_Message"
|
||||
|
||||
# Reset SHLVL (otherwise it is 2 inside tmux)
|
||||
setenv -g SHLVL 0
|
||||
|
||||
# Send esc faster so that neovim won't get so laggy
|
||||
# https://github.com/neovim/neovim/issues/2093
|
||||
set -g escape-time 100
|
||||
|
||||
# Disable paste detection
|
||||
set -g assume-paste-time 0
|
||||
|
||||
# Titles and window names
|
||||
set -g set-titles on
|
||||
set -g set-titles-string "#T"
|
||||
|
||||
# Make it not so annoying/sticky to switch windows
|
||||
set -g repeat-time 170
|
||||
|
||||
# Don't deattach me when a session ends
|
||||
set -g detach-on-destroy off
|
||||
|
||||
# Make shift+keys work
|
||||
setw -g xterm-keys on
|
||||
|
||||
# Prefix
|
||||
set -g prefix ^A
|
||||
unbind ^B
|
||||
bind ^A send-prefix
|
||||
bind a send-prefix
|
||||
|
||||
# Last window
|
||||
bind ^a last
|
||||
|
||||
# Next & prev
|
||||
bind ' ' next
|
||||
bind '^ ' next
|
||||
bind ^p prev
|
||||
|
||||
# Status
|
||||
set -g status off
|
||||
# Need more (cow)bells!
|
||||
set -g bell-action any
|
||||
set -g bell-on-alert on
|
||||
|
||||
# Detach
|
||||
bind ^d detach
|
||||
|
||||
# Control the a tmux in a tmux
|
||||
bind A send-prefix \; send-prefix
|
||||
bind C send-prefix \; send-keys c
|
||||
bind n send-prefix \; send-keys ' '
|
||||
bind bspace send-prefix \; send-keys p
|
||||
bind '#' send-prefix \; send-keys '"'
|
||||
|
||||
# Other key bindings.
|
||||
bind ^r command-prompt "find-window '%%'"
|
||||
bind '"' choose-tree -w
|
||||
bind w split-window
|
||||
bind W split-window -c "#{pane_current_path}"
|
||||
bind ^w split-window
|
||||
bind I list-windows
|
||||
bind i list-windows
|
||||
bind D neww 'if who | grep -q "$USER.* via mosh"; then tmux lsc -F "#{client_activity} #{client_tty}" | sort | head -n -1 | awk "{print \$2}" | xargs -n1 tmux detach -t; else for i in $(tmux lsc | cut -d: -f1 | grep -v "^$SSH_TTY$"); do tmux detach -t $i; done; fi'
|
||||
bind S neww -t 999 'window=`tmux display -p "#{pane_title}"`; i=0; tmux list-windows | cut -d: -f1 | while read j; do if [ $j != $i ]; then tmux move-window -s $j -t $i; fi; i=$(($i+1)); done' # ; tmux find-window -T "$window"
|
||||
bind ^s command-prompt "rename-session '%%'"
|
||||
# Make the default HOME always ~
|
||||
bind c neww -c ~
|
||||
bind ^c new -c ~
|
||||
bind escape copy-mode
|
||||
# Copy to the OS clipboard
|
||||
bind -T copy-mode-vi y send -X copy-pipe-and-cancel "if [ \"$(uname)\" = 'Darwin' ]; then reattach-to-user-namespace pbcopy; else xclip; fi"
|
||||
bind j command-prompt "join-pane -s '%%'"
|
||||
bind ! break-pane -d
|
||||
bind - command-prompt "move-pane -t '%%'"
|
||||
|
||||
# Makes `tmux a` work even when there isn't a session going on
|
||||
new-session -A -c ~
|
||||
65
regress/conf/ad0537c4e83d7a25d5dc4f3a3c571349.conf
Normal file
65
regress/conf/ad0537c4e83d7a25d5dc4f3a3c571349.conf
Normal file
@@ -0,0 +1,65 @@
|
||||
set-option -g allow-rename on
|
||||
set-option -g automatic-rename off
|
||||
set-option -g base-index 1
|
||||
set-option -g default-command "$SHELL"
|
||||
set-option -g default-terminal "tmux-256color"
|
||||
set-option -g history-limit 25000
|
||||
set-option -g mode-keys vi
|
||||
set-option -g prefix C-f
|
||||
set-option -g renumber-windows yes
|
||||
set-option -g set-titles on
|
||||
set-option -g set-titles-string "#T"
|
||||
set-option -g xterm-keys on
|
||||
|
||||
set-option -g status-interval 1
|
||||
set-option -g status-left "#(tmux-status-left)"
|
||||
set-option -g status-left-length 40
|
||||
set-option -g status-right ""
|
||||
|
||||
set-option -g window-status-current-attr bold
|
||||
set-option -g window-status-current-format "[#I#F#{?window_zoomed_flag, ,}#{=40:pane_title}]"
|
||||
set-option -g window-status-format "#I#{?window_zoomed_flag, ,}#F#{?window_flags,, }#{?window_zoomed_flag, ,}#{=20:pane_title}"
|
||||
|
||||
set-option -g pane-active-border-fg colour247
|
||||
set-option -g pane-border-fg colour235
|
||||
set-option -g status-bg colour7
|
||||
set-option -g status-fg colour16
|
||||
set-option -g status-left-bg colour4
|
||||
set-option -g status-left-fg colour15
|
||||
set-option -g window-status-current-bg colour15
|
||||
set-option -g window-status-current-fg colour16
|
||||
|
||||
set-option -g update-environment "DBUS_SESSION_BUS_ADDRESS DISPLAY KRB5CCNAME \
|
||||
SESSION_MANAGER SSH_AGENT_PID SSH_ASKPASS SSH_AUTH_SOCK SSH_CONNECTION \
|
||||
WINDOWID XAUTHORITY SSH_TTY"
|
||||
|
||||
bind-key w break-pane -d
|
||||
bind-key l clear-history \; display "Pane history cleared."
|
||||
bind-key C-f if-shell "test #{window_panes} -eq 1" last-window last-pane
|
||||
bind-key N new-session
|
||||
bind-key t new-window
|
||||
bind-key z resize-pane -Z
|
||||
bind-key C-r rotate-window -D
|
||||
bind-key -n C-t run-shell "metamux new-shell-in-pane #{window_panes}"
|
||||
bind-key n run-shell "metamux rotate-pane next"
|
||||
bind-key p run-shell "metamux rotate-pane prev"
|
||||
bind-key q run-shell "metamux pane-buster"
|
||||
bind-key S run-shell "metamux join-hidden-pane -v"
|
||||
bind-key u run-shell "metamux open-last-url-printed"
|
||||
bind-key | run-shell "metamux join-hidden-pane -h"
|
||||
bind-key f send-prefix
|
||||
bind-key r source "$HOME/.tmux.conf" \; display "Configuration reloaded."
|
||||
|
||||
# When the current window is split, Ctrl+Tab and Ctrl+Shift+Tab should rotate
|
||||
# between the split windows. If there is only one pane in the current window,
|
||||
# Ctrl+Tab and Ctrl+Shift+Tab will cycle between windows as though they were
|
||||
# tabs in modern desktop UIs.
|
||||
bind-key -n C-Tab if-shell "test #{window_panes} -eq 1" next-window "select-pane -t :.+"
|
||||
bind-key -n C-S-Tab if-shell "test #{window_panes} -eq 1" previous-window "select-pane -t :.-"
|
||||
|
||||
# Binding to mark and swap panes; if no pane is marked, the shortcut will mark
|
||||
# the active pane, but if a pane is already marked, active pane will be swapped
|
||||
# with the marked pane.
|
||||
bind-key m if-shell 'test -z "$PANE_IS_MARKED"' \
|
||||
"select-pane -m; set-env PANE_IS_MARKED 1" \
|
||||
"swap-pane; select-pane -M; set-env -u PANE_IS_MARKED"
|
||||
580
regress/conf/ad21dbb0893240563ddfdd954b9903a1.conf
Normal file
580
regress/conf/ad21dbb0893240563ddfdd954b9903a1.conf
Normal file
@@ -0,0 +1,580 @@
|
||||
# Time-stamp: <2018-05-31 17:10:05 kmodi>
|
||||
# https://github.com/tmux/tmux
|
||||
# Hi-lock: (("\\(^\\s< \\**\\)\\(\\* *.*\\)" (1 'org-hide prepend) (2 '(:inherit org-level-1 :height 1.3 :weight bold :overline t :underline t) prepend)))
|
||||
# Hi-Lock: end
|
||||
|
||||
# Running tmux built from master branch on tcsh in uxterm
|
||||
# tmux version 2.5-RC+ dev
|
||||
|
||||
# Contents:
|
||||
#
|
||||
# PREFIX
|
||||
# Source config
|
||||
# Pane Management
|
||||
# Window <-join/split-> Pane
|
||||
# Select Panes
|
||||
# Resize Panes
|
||||
# Dynamic Split
|
||||
# Window Management
|
||||
# Window Navigation
|
||||
# Swap Windows
|
||||
# Split Window
|
||||
# Layout
|
||||
# Session Management
|
||||
# Mouse
|
||||
# Drag pane border to resize
|
||||
# Left click on pane
|
||||
# Middle click on pane
|
||||
# Right click on pane
|
||||
# Wheel scroll in pane
|
||||
# Wheel scroll in pane WHILE in copy-mode
|
||||
# Left click on status
|
||||
# Middle click on status
|
||||
# Other mouse settings
|
||||
# Window Title
|
||||
# Status Bar
|
||||
# Left Status
|
||||
# Right Status
|
||||
# Pane Status
|
||||
# Colors
|
||||
# Status Bar Colors
|
||||
# Message Colors
|
||||
# Window Status Colors
|
||||
# Pane Colors
|
||||
# Mode Info Colors
|
||||
# Activity
|
||||
# Command Prompt
|
||||
# Audible and Visual Bells
|
||||
# Copy & Paste
|
||||
# Synchronize commands to panes/windows/sessions
|
||||
# Terminal Setting
|
||||
# Other Options
|
||||
# Server Options
|
||||
# Session Options
|
||||
# Window Options
|
||||
# Notes
|
||||
|
||||
# * PREFIX
|
||||
set -g prefix C-z
|
||||
unbind C-b # unbind the default binding to send prefix key to the application
|
||||
# Often you'll run a tmux inside another tmux and need a command sequence to
|
||||
# send things to the inner session. With below binding that can be accomplished
|
||||
# using "PREFIX Z <command>"
|
||||
bind Z send-prefix
|
||||
|
||||
# * Source config
|
||||
unbind r # unbind default binding to force redraw of attached client
|
||||
bind r source-file ~/.tmux.conf \; display "Finished sourcing ~/.tmux.conf ."
|
||||
|
||||
# * Pane Management
|
||||
|
||||
set -g pane-base-index 1 # start pane indices at 1
|
||||
set -g main-pane-width 100 # used by selectl main-vertical
|
||||
bind z resize-pane -Z # zoom/unzoom the current pane
|
||||
# If the window has >1 panes kill them without confirming. But confirm before kill
|
||||
# the last pane (along with its window) in a window
|
||||
bind x if "tmux display -p \"#{window_panes}\" | grep ^1\$" \
|
||||
"confirm-before -p \"Kill the only pane in window? It will kill this window too! (y/n)\" kill-pane" \
|
||||
"kill-pane"
|
||||
bind C clear-history \; display "Cleared history of the current pane."
|
||||
unbind C-p
|
||||
bind C-p run -b "tmux display -p -F '#{pane_current_path}' | xclip -i -sel pri" \; display "Copied current path '#{pane_current_path}' to the primary selection."
|
||||
|
||||
# Hooks need tmux 2.3+
|
||||
# set-hook -g -u after-kill-pane # Remove after hook for kill-pane
|
||||
set-hook -g after-kill-pane "selectl main-vertical"
|
||||
# If -g options is used when setting the hook, it has to be used when
|
||||
# removing (-u option) the hook too.
|
||||
|
||||
# ** Window <-join/split-> Pane
|
||||
# Join a pane *from* a different window (of same or different session) into the CURRENT window
|
||||
# Binding mnemonic: F for (F)etch/pull (as in git) from a different window
|
||||
bind F command-prompt -p "Join pane from [sess:]win#[.pane#] (ex: kmodi:3.1) into current window:" "join-pane -s '%%'"
|
||||
# Join CURRENT pane *to* a different window
|
||||
# Binding mnemonic: P for (P)ush (as in git) to a different window
|
||||
bind P command-prompt -p "Send CURRENT pane to [sess:]win# (ex: kmodi:3):" "join-pane -t '%%'"
|
||||
# PREFIX ! : break-pane, convert the current pane to a window
|
||||
|
||||
# ** Select Panes
|
||||
bind o select-pane -t :.+ # cycle to the next pane number
|
||||
bind O select-pane -t :.- # cycle to the previous pane number
|
||||
# PREFIX ; : last-pane or select-pane -l, switch to the last active pane
|
||||
# PREFIX ← : select-pane -L, switch to the pane on the left
|
||||
# PREFIX → : select-pane -R, switch to the pane on the right
|
||||
# PREFIX ↑ : select-pane -U, switch to the pane on the top
|
||||
# PREFIX ↓ : select-pane -D, switch to the pane on the bottom
|
||||
# PREFIX { : swap-pane -U, swap current pane with the pane above (not literally above)
|
||||
# PREFIX } : swap-pane -D, swap current pane with the pane below (not literally below)
|
||||
|
||||
# ** Resize Panes
|
||||
bind -r h resize-pane -L 2
|
||||
bind -r C-h resize-pane -L 2
|
||||
bind -r j resize-pane -D 2
|
||||
bind -r C-j resize-pane -D 2
|
||||
bind -r k resize-pane -U 2
|
||||
bind -r C-k resize-pane -U 2
|
||||
unbind l # unbind default binding for `last-window`
|
||||
bind -r l resize-pane -R 2
|
||||
bind -r C-l resize-pane -R 2
|
||||
|
||||
# ** Dynamic Split
|
||||
# Key-chaining example, analogous to prefix maps in emacs
|
||||
bind / switch-client -Tlauncher
|
||||
# Run below -Tlauncher commands using "PREFIX / <binding>"
|
||||
# Open calendar in a split window "PREFIX / c"
|
||||
# FIXME: Below does not work; cal pane quits as soon as it launches (before "&& sleep .."
|
||||
# was added). To make better of the situation, I now auto-close that pane after 3 seconds.
|
||||
# bind -Tlauncher c split-window -h 'cal && sleep 3'
|
||||
bind -Tlauncher c run "/home/kmodi/scripts/tcsh/tmux/dynamic_split.csh 'cal && sleep 3'"
|
||||
# Start emacsclient in terminal mode in a split window "PREFIX / e"
|
||||
# Use the emacs binding "C-x 5 0" to quit from that pane gracefully.
|
||||
bind -Tlauncher e run "/home/kmodi/scripts/tcsh/tmux/dynamic_split.csh 'emacsclient -a \"\" -t'"
|
||||
# Open man page "PREFIX / m"
|
||||
# PREFIX / m will bring up the tmux command prompt. Enter the command for which
|
||||
# you want to see the man page, example: ls. That man page will open in a split
|
||||
# pane. When you are done reviewing the man page, hit q and the split pane
|
||||
# closes by itself. Beautiful!
|
||||
bind -Tlauncher m command-prompt -p "man" "run \"/home/kmodi/scripts/tcsh/tmux/dynamic_split.csh 'man %1'\""
|
||||
# Open python interpreter in a split window for quick calculations "PREFIX / p"
|
||||
# Ctrl-D in python quits python and thus closes the split window too.
|
||||
bind -Tlauncher p run "/home/kmodi/scripts/tcsh/tmux/dynamic_split.csh 'ipython --profile=default --no-confirm-exit'"
|
||||
# PREFIX Up, Down, Right, Left : Move cursor from one pane to another
|
||||
# PREFIX Space : Cycle through different pane layouts
|
||||
# PREFIX C-o : rotate-window, rotate panes in the current window
|
||||
|
||||
# * Window Management
|
||||
set -g base-index 1 # start window indices at 1
|
||||
# automatically renumber the windows
|
||||
# http://unix.stackexchange.com/questions/21742/renumbering-windows-in-tmux
|
||||
set -g renumber-windows on
|
||||
|
||||
bind C-f command-prompt -p "New window:" "new-window -c '#{pane_current_path}' -n %1"
|
||||
bind C-r command-prompt -p "New name for this window:" "rename-window '%%'"
|
||||
unbind L # unbind default binding for `switch-client -l`
|
||||
bind L list-windows -F '#{window_index}:#{window_name}: #{?pane_dead, (dead), (not dead)}'
|
||||
unbind & # unbind default binding for `kill-window`
|
||||
bind C-c confirm-before -p "Kill this window? (y/n)" kill-window
|
||||
# Move the current window to another window index in the same or any other session
|
||||
bind m command-prompt -p "Move window to sess or sess:win# or win# (ex: kmodi or kmodi:3 or 2(of current session)):" "move-window -t '%%'"
|
||||
# Move or bring a window from a different session to the current one
|
||||
bind M command-prompt -p "Move the window from sess:win# (ex: kmodi:3):" "move-window -s '%%'"
|
||||
|
||||
# ** Window Navigation
|
||||
bind C-z last-window # switch to last active window
|
||||
# Allow repeats for next/previous-window
|
||||
bind -r p previous-window
|
||||
bind -r n next-window
|
||||
# switch to another window by name
|
||||
bind W split-window "tmux lsw | peco --initial-index `tmux lsw | awk '/active.$/ {print NR-1}'` | cut -d':' -f 1 | xargs tmux select-window -t"
|
||||
# PREFIX <N> : switches to window with index=N
|
||||
|
||||
# ** Swap Windows
|
||||
bind N move-window -r # renumber the windows
|
||||
unbind , # unbind default binding for `rename-window`
|
||||
bind -r , swap-window -t -1 # move window one position to the left
|
||||
bind -r < swap-window -t -1 # move window one position to the left
|
||||
unbind . # unbind default binding to move window to user provided index
|
||||
bind -r . swap-window -t +1 # move window one position to the right
|
||||
bind -r > swap-window -t +1 # move window one position to the right
|
||||
unbind t # unbind default binding to show time
|
||||
bind t swap-window -t 1 # swap the current window's position with window # 1, move it to the top
|
||||
|
||||
# ** Split Window
|
||||
unbind & # unbind default binding for `split-window -h`
|
||||
bind - split-window -v -c '#{pane_current_path}' # vertical split
|
||||
bind _ split-window -v -c '#{pane_current_path}' -f # full vertical split (v2.3+)
|
||||
bind \ split-window -h -c '#{pane_current_path}' # horizontal split
|
||||
bind | split-window -h -c '#{pane_current_path}' -f # full horizontal split (v2.3+)
|
||||
# https://www.reddit.com/r/tmux/comments/3paqoi/tmux_21_has_been_released/cw5wy00
|
||||
bind w switch-client -Tsplit_wind
|
||||
bind -Tsplit_wind v split-window -v -c '#{pane_current_path}'
|
||||
bind -Tsplit_wind V split-window -v -c '#{pane_current_path}'\; swap-pane -U
|
||||
bind -Tsplit_wind h split-window -h -c '#{pane_current_path}'
|
||||
bind -Tsplit_wind H split-window -h -c '#{pane_current_path}'\; swap-pane -U
|
||||
|
||||
# ** Layout
|
||||
bind Space next-layout
|
||||
bind C-Space select-layout -o # undo only the last layout change #v2.1
|
||||
|
||||
# * Session Management
|
||||
bind C-t command-prompt -p "New name for this session:" "rename-session '%%'"
|
||||
bind b switch-client -l # switch to previously selected session
|
||||
# switch to another session by name
|
||||
bind S split-window "tmux ls | peco --initial-index `tmux ls | awk '/attached.$/ {print NR-1}'` | cut -d':' -f 1 | xargs tmux switch-client -t"
|
||||
# switch to ANY window in ANY session by name
|
||||
bind s split-window "tmux ls | cut -d: -f1 | xargs -I SESSION tmux lsw -F 'SESSION:#{window_name}' -t SESSION | peco --initial-index `tmux ls | cut -d: -f1 | xargs -I SESSION tmux lsw -F '___#{session_attached}#{window_active}___' -t SESSION | awk '/___11___/ {print NR-1}'` | xargs tmux switch-client -t"
|
||||
# tmux kill-session -t NAME/SESSIONNUMBER # Kill session
|
||||
|
||||
# * Mouse
|
||||
# setw -g mode-mouse on # incompatible in tmux 2.1+
|
||||
set -g mouse on
|
||||
|
||||
# ** Drag pane border to resize
|
||||
# set -g mouse-resize-pane off # incompatible in tmux 2.1+
|
||||
bind -T root MouseDrag1Border resize-pane -M # default
|
||||
# unbind -T root MouseDrag1Border # disable drag pane border to resize
|
||||
|
||||
bind -T root MouseDrag1Pane if -Ft= '#{mouse_any_flag}' 'if -Ft= "#{pane_in_mode}" "copy-mode -M" "send-keys -M"' 'copy-mode -M' # default
|
||||
|
||||
# ** Left click on pane
|
||||
# set -g mouse-select-pane on # incompatible in tmux 2.1+
|
||||
# Left click on a pane selects it
|
||||
# bind -T root MouseDown1Pane select-pane -t=\; send-keys -M # default
|
||||
bind -T root MouseDown1Pane select-pane -t=
|
||||
|
||||
# Sun Feb 19 11:31:34 EST 2017 - kmodi
|
||||
# Below break in tmux 2.4
|
||||
# # Fri Aug 26 18:35:21 EDT 2016 - kmodi
|
||||
# # FIXME Need to remember why I unbound the below 2 bindings
|
||||
# unbind -temacs-copy MouseDown1Pane
|
||||
# unbind -temacs-copy MouseUp1Pane
|
||||
# #
|
||||
|
||||
# https://groups.google.com/forum/#!topic/tmux-users/mHhdx7Au0Ds
|
||||
# Fri Aug 26 18:30:15 EDT 2016 - kmodi
|
||||
# Do not do the below!! That will update the primary selection with the top-most
|
||||
# tmux buffer each time you left click on a pane.
|
||||
# bind -T root MouseUp1Pane run -b "tmux show-buffer | xclip -i -sel pri"
|
||||
#
|
||||
|
||||
# Left click in the pane *followed after a region selection* copies that to the
|
||||
# secondary selection
|
||||
bind -T root MouseUp1Pane run -b "tmux show-buffer | xclip -i -sel sec"
|
||||
# Fri Aug 26 19:03:57 EDT 2016 - kmodi
|
||||
# FIXME: As of today it needs to be figured out how to best paste the content
|
||||
# from secondary selection
|
||||
|
||||
# ** Middle click on pane
|
||||
# Middle click in a pane to paste from the primary selection
|
||||
bind -T root MouseDown2Pane run -b "xclip -o -sel pri | tmux load-buffer - && tmux paste-buffer -s ' '"
|
||||
|
||||
# ** Right click on pane
|
||||
# Right click on a pane selects and marks it *if not in copy-mode*; else
|
||||
# passes on the mode keys
|
||||
# bind -T root MouseDown3Pane select-pane -t= -m # default
|
||||
bind -T root MouseDown3Pane if -Ft= '#{pane_in_mode}' 'send-keys -M' 'select-pane -t= -m'
|
||||
|
||||
# Sun Feb 19 11:32:00 EST 2017 - kmodi
|
||||
# Below breaks in tmux 2.4
|
||||
# # Right click *release* on a pane *in copy-mode* quits copy-mode
|
||||
# bind -temacs-copy MouseUp3Pane cancel
|
||||
|
||||
# ** Wheel scroll in pane
|
||||
unbind -T root WheelUpPane
|
||||
unbind -T root WheelDownPane
|
||||
# Do mouse wheel-up to enter copy mode and do page-up
|
||||
# https://groups.google.com/d/msg/tmux-users/XTrSVUR15Zk/3iyJLMyQ7PwJ
|
||||
# Below binding did not work
|
||||
# bind -T root WheelUpPane if -Ft= '#{mouse_any_flag}' 'if -Ft= "#{pane_in_mode}" "copy-mode -u" "send-keys -M"' 'copy-mode -u'
|
||||
# Below works and allows the WheelUpPane binding in emacs-copy table to be effective
|
||||
bind -T root WheelUpPane if -Ft= '#{mouse_any_flag}' 'send-keys -M' 'if -Ft= "#{pane_in_mode}" "send-keys -M" "copy-mode -u"'
|
||||
# |---------------------+-----------------------------------------+--------------------------------|
|
||||
# | using mouse? AND .. | #{pane_in_mode} (already in copy-mode?) | action |
|
||||
# |---------------------+-----------------------------------------+--------------------------------|
|
||||
# | Yes | Don't care | Send the mode keys |
|
||||
# | No | Yes | Send the mode keys |
|
||||
# | No | No | Enable copy-mode and do PageUp |
|
||||
# |---------------------+-----------------------------------------+--------------------------------|
|
||||
|
||||
# *** Wheel scroll in pane WHILE in copy-mode
|
||||
# Sun Feb 19 11:32:16 EST 2017 - kmodi
|
||||
# Below breaks in tmux 2.4
|
||||
# # Once in copy-mode, mouse wheel scrolls scrolls by half pages
|
||||
# bind -temacs-copy WheelUpPane halfpage-up
|
||||
# bind -temacs-copy WheelDownPane halfpage-down
|
||||
|
||||
# ** Left click on status
|
||||
# set -g mouse-select-window on # incompatible in tmux 2.1+
|
||||
# Left click on a window name in status bar to select it
|
||||
bind -T root MouseDown1Status select-window -t= # default
|
||||
|
||||
# ** Middle click on status
|
||||
# Middle click on a window name in status bar to kill it
|
||||
bind -T root MouseDown2Status kill-window
|
||||
|
||||
# ** Other mouse settings
|
||||
# The special token ‘{mouse}’ or ‘=’ may be used as target-window or target-pane in
|
||||
# commands bound to mouse key bindings. Example: -t =
|
||||
|
||||
# * Window Title
|
||||
set -g set-titles on
|
||||
set -g set-titles-string '#h :: #S:W#I(#W).P#P'
|
||||
|
||||
# * Status Bar
|
||||
set -g status-interval 5 # default = 15 seconds
|
||||
set -g status-justify centre
|
||||
|
||||
# ** Left Status
|
||||
set -g status-left-length 20
|
||||
# Change the left status when prefix is pressed.
|
||||
# https://www.reddit.com/r/tmux/comments/5cm2ca/post_you_favourite_tmux_tricks_here/d9ziuy9/
|
||||
set -g status-left "#{?client_prefix,#[fg=yellow]prefix pressed ..,[#S]}"
|
||||
|
||||
# ** Right Status
|
||||
set -g status-right-length 20
|
||||
set -g status-right "%l:%M %b %d %a "
|
||||
|
||||
# ** Pane Status
|
||||
setw -g pane-border-status "bottom"
|
||||
setw -g pane-border-format " #P #T "
|
||||
|
||||
# # tmux-powerline
|
||||
# # https://github.com/erikw/tmux-powerline
|
||||
# set -g status-left-length 30
|
||||
# set -g status-right-length 30
|
||||
# set -g status-left "#(~/usr_local/scripts/tmux-powerline/powerline.sh left)"
|
||||
# set -g status-right "#(~/usr_local/scripts/tmux-powerline/powerline.sh right)"
|
||||
|
||||
# * Colors
|
||||
|
||||
# ** Status Bar Colors
|
||||
set -g status-style fg=colour246,bg=colour233 # default for whole status line
|
||||
set -g status-left-style fg=white,bold,bg=colour233
|
||||
set -g status-right-style fg=colour75,none,bg=colour233
|
||||
|
||||
# ** Message Colors
|
||||
set -g message-style fg=colour2,bold,bg=default
|
||||
|
||||
# ** Window Status Colors
|
||||
setw -g window-status-style default # default for all window statuses
|
||||
setw -g window-status-last-style fg=default,bg=colour235
|
||||
setw -g window-status-current-style fg=white,bold,bg=colour63
|
||||
setw -g window-status-bell-style default
|
||||
setw -g window-status-activity-style fg=white,none,bg=colour196
|
||||
# setw -g window-status-content-style fg=black,none,bg=green # incompatible with tmux 2.0+
|
||||
|
||||
# ** Pane Colors
|
||||
setw -g pane-active-border-style fg=colour63,bg=default
|
||||
setw -g pane-border-style fg=colour235,bg=default
|
||||
setw -g window-active-style 'bg=#330000' # bg color of active pane
|
||||
setw -g window-style 'bg=black' # bg color of inactive pane(s)
|
||||
|
||||
# ** Mode Info Colors
|
||||
# Color of display shown on top-right in copy-mode, highlighting
|
||||
setw -g mode-style fg=black,bg=colour244
|
||||
|
||||
# * Activity
|
||||
# Notify when a window has activity
|
||||
# This quick snippet will have tmux notify you in the status area when a
|
||||
# window has activity:
|
||||
setw -g monitor-activity on
|
||||
set -g visual-activity off # Display message telling that an activity happened (on/off)
|
||||
# It lets me know that there is activity in a non-active window
|
||||
# To try this, enter `sleep 10 && echo “Hi”` in a window and switch to
|
||||
# another window.
|
||||
|
||||
# # Notify when a window has a content alert
|
||||
# setw -g monitor-content "--[A-Za-z][A-Za-z]sim Done--" # This string appears when a sim finishes, alert then # incompatible with tmux 2.0+
|
||||
# # setw -g monitor-content "" # Disable monitor-content
|
||||
# set -g visual-content on # Display message telling that a content alert was triggered (on/off) # incompatible with tmux 2.0+
|
||||
|
||||
# * Command Prompt
|
||||
# Move focus to command prompt. tmux commands can be entered there directly
|
||||
# without using the `tmux` prefix and it also supports auto-complete.
|
||||
bind C-x command-prompt # default command-prompt binding "PREFIX :" also works
|
||||
|
||||
# * Audible and Visual Bells
|
||||
set -g bell-action any
|
||||
set -g bell-on-alert off
|
||||
set -g visual-bell on
|
||||
|
||||
# * Copy & Paste
|
||||
set -g set-clipboard off # default is on
|
||||
|
||||
# Copy tmux buffer to primary and clipboard selections
|
||||
# run -b runs a shell command in background
|
||||
# http://grota.github.io/blog/2012/05/08/tmux-clipboard-integration/
|
||||
bind C-w run -b "tmux show-buffer | xclip -i -sel pri && tmux show-buffer | xclip -i -sel cli"
|
||||
# Fri Aug 26 18:41:30 EDT 2016 - kmodi
|
||||
# Below binding was suggested by Nicholas Marriott
|
||||
# But the my older binding works fine so I am commenting out below for now.
|
||||
# bind C-w run "tmux saveb - | xclip -i -sel pri; tmux saveb - | xclip -i -sel cli"
|
||||
# Paste into tmux; also replace LF characters with
|
||||
# space as separator characters (-s) when pasting.
|
||||
# Yank from primary
|
||||
bind C-y run -b "xclip -o -sel pri | tmux load-buffer - && tmux paste-buffer -s ' '"
|
||||
# Yank from clipboard
|
||||
bind M-y run -b "xclip -o -sel cli | tmux load-buffer - && tmux paste-buffer -s ' '"
|
||||
# Open the file/dir path that was copied by selection in existing emacs client
|
||||
# Usage: Highlight a file name in ls output and press "PREFIX e"
|
||||
bind e run -b "tmux show-buffer | xclip -i -sel pri; (emacsclient -a '' `tmux display -p '#{pane_current_path}'`/`xclip -o -sel pri `&)"
|
||||
|
||||
# * Synchronize commands to panes/windows/sessions
|
||||
# Send the same command to all panes in the same window
|
||||
bind C-a command-prompt -p "Command to all panes in this window:" \
|
||||
"run \"tmux list-panes -F '##{pane_index}' | xargs -I PANE \
|
||||
tmux send-keys -t PANE '%1' Enter\""
|
||||
# Alternative to using the above "C-a" binding is to enable pane synchronization,
|
||||
# type the command you want to execute in all panes in the same window and disable
|
||||
# pane synchronization
|
||||
# Also turn the pane borders red while pane synchronization is enabled.
|
||||
# - https://www.reddit.com/r/tmux/comments/5cm2ca/post_you_favourite_tmux_tricks_here/d9y6jzu/
|
||||
bind C-s if -F '#{pane_synchronized}' \
|
||||
'setw synchronize-panes off; \
|
||||
setw pane-active-border-style fg=colour63,bg=default; \
|
||||
setw pane-border-format " #P #T "' \
|
||||
'setw synchronize-panes on; \
|
||||
setw pane-active-border-style fg=red; \
|
||||
setw pane-border-format " #P - Pane Synchronization ON "'
|
||||
# So it would be: C-s <type the command RET> C-s
|
||||
|
||||
# https://scripter.co/command-to-every-pane-window-session-in-tmux/
|
||||
# Send the same command to all panes/windows in the current session
|
||||
bind C-e command-prompt -p "Command:" \
|
||||
"run \"tmux list-panes -s -F '##{session_name}:##{window_index}.##{pane_index}' \
|
||||
| xargs -I PANE tmux send-keys -t PANE '%1' Enter\""
|
||||
|
||||
# Send the same command to all panes/windows/sessions
|
||||
bind E command-prompt -p "Command:" \
|
||||
"run \"tmux list-panes -a -F '##{session_name}:##{window_index}.##{pane_index}' \
|
||||
| xargs -I PANE tmux send-keys -t PANE '%1' Enter\""
|
||||
|
||||
# * Terminal Setting
|
||||
|
||||
# From `man tmux', about `default-terminal'
|
||||
# Set the default terminal for new windows created in this session - the default
|
||||
# value of the TERM environment variable. For tmux to work correctly, this must
|
||||
# be set to ‘screen’, ‘tmux’ or a derivative of them.
|
||||
# set -g default-terminal "screen"
|
||||
set -g default-terminal "screen-256color"
|
||||
# Mon May 22 11:43:56 EDT 2017 - kmodi
|
||||
# Blinking text (useful to show broken symlinks in ls) does not work when using tmux-24bits.
|
||||
# set -g default-terminal "tmux-24bits"
|
||||
# tmux-24bits is a custom terminfo profile created using the steps explained
|
||||
# on https://github.com/ThomasAdam/tmux/blob/master/FAQ to support italics and
|
||||
# 256 colors.
|
||||
|
||||
# Enable 24-bit color
|
||||
# https://sunaku.github.io/tmux-24bit-color.html
|
||||
set -ga terminal-overrides ",screen-256color:Tc"
|
||||
# set -ga terminal-overrides ",tmux-24bits:Tc"
|
||||
|
||||
# Thu May 31 17:10:04 EDT 2018 - kmodi
|
||||
# TODO: Try the 24-bit emacs+tmux config for ST
|
||||
# https://www.reddit.com/r/emacs/comments/8ndm2x/gnu_emacs_261_24bit_colors_suckless_st_terminal/dzwh4vv/
|
||||
# set -g default-terminal "tmux-256color"
|
||||
# set -ga terminal-overrides ",*256col*:Tc"
|
||||
#
|
||||
|
||||
setw -g xterm-keys on
|
||||
|
||||
# Uncomment below when using st (by suckless.org)
|
||||
# set -g default-terminal "st-256color"
|
||||
# # https://sunaku.github.io/tmux-24bit-color.html
|
||||
# # st supports 24-bit color, so enable support for that in tmux
|
||||
# set -ga terminal-overrides ",st-256color:Tc"
|
||||
# setw -g xterm-keys off
|
||||
|
||||
bind R refresh-client
|
||||
# bind R refresh-client \; display "Refreshed the client."
|
||||
|
||||
# * Other Options
|
||||
|
||||
# ** Server Options
|
||||
set -s escape-time 0 # Allows for faster key repetition
|
||||
|
||||
# ** Session Options
|
||||
# Set the default shell to /bin/sh. If the default is tcsh, doing a split-window takes a long
|
||||
# time as my tcsh init is loaded first (which takes really long).
|
||||
set -g default-shell /bin/sh
|
||||
# If I am doing a new-window or split-window without a specified command, start the tcsh
|
||||
# shell by default.
|
||||
set -g default-command tcsh
|
||||
set -g history-limit 100000
|
||||
set -g display-time 1000 # Duration of tmux display messages in milliseconds
|
||||
|
||||
# ** Window Options
|
||||
# When a smaller terminal connects to a tmux client, it shrinks to fit it. The
|
||||
# clients attached with bigger displays see this constrained view.
|
||||
# aggressive-resize makes it such that the window is only resized if the smaller
|
||||
# client is actively looking at it.
|
||||
setw -g aggressive-resize on
|
||||
setw -g mode-keys emacs # Use emacs keybindings in copy mode
|
||||
setw -g status-keys emacs
|
||||
|
||||
# * Notes
|
||||
|
||||
# |-------------------+------------|
|
||||
# | tmux command | short form |
|
||||
# |-------------------+------------|
|
||||
# | set-option | set |
|
||||
# | set-window-option | setw |
|
||||
# | bind-key | bind |
|
||||
# | unbind-key | unbind |
|
||||
# | display-message | display |
|
||||
# | run-shell | run |
|
||||
# | if-shell | if |
|
||||
# |-------------------+------------|
|
||||
|
||||
# Colo'u'r table
|
||||
# http://guns.github.io/xterm-color-table.vim/images/xterm-color-table.png
|
||||
|
||||
# CHARACTER PAIR REPLACED WITH
|
||||
# #(command) First line of command’s output
|
||||
# #[attributes] Colour or attribute change
|
||||
# #H Hostname of local host
|
||||
# #I Current window index
|
||||
# #P Current pane index
|
||||
# #S Session name
|
||||
# #T Current window title
|
||||
# #W Current window name
|
||||
# ## A literal ‘#’
|
||||
|
||||
# Variables used in time format
|
||||
# Source: http://docs.splunk.com/Documentation/Splunk/5.0.2/SearchReference/Commontimeformatvariables
|
||||
# %y = year in numbers (2-digit)
|
||||
# %Y = year in numbers (4-digit)
|
||||
# %m = month in number (eg: 12)
|
||||
# %B = full month name (eg: December)sho
|
||||
# %b = short month name (eg: Dec)
|
||||
# %d = day in numbers, with leading zeros (eg: 08)
|
||||
# %e = day in numbers, no leading zeros (eg: 8)
|
||||
# %A = full weekday name (eg: Sunday)
|
||||
# %a = short weekday name (eg: Sun)
|
||||
# %H = hours in 24-clock, with leading zeros
|
||||
# %k = hours in 24-clock, no leading zeros
|
||||
# %l = hours in 12-clock, with leading zeros
|
||||
# %p = am/pm
|
||||
# %T = time in 24-hour notation (%H:%M:%S)
|
||||
|
||||
# PREFIX ? : list-keys, display key bindings
|
||||
|
||||
# In command-prompt: show-options -g shows the global options
|
||||
# In command-prompt: show-window-options -g shows the global windows options
|
||||
|
||||
# How do I know which tmux version I am running?
|
||||
# tmux -V
|
||||
|
||||
# How to set bindings that don't need the prefix?
|
||||
# bind -n .. or
|
||||
# bind -T root ..
|
||||
|
||||
# Changelog: https://github.com/tmux/tmux/blob/master/CHANGES
|
||||
|
||||
# style colors: default, black, red, green, yellow, blue, magenta, cyan, white,
|
||||
# colour0-colour255, hexdecimal RGB string '#ffffff'
|
||||
# Use $SCRIPTS/bash/256-colors.sh to figure out the color number you want
|
||||
# style attributes: none, bold/bright, dim, underscore, blink, reverse, hidden,
|
||||
# or italics
|
||||
|
||||
# https://www.reddit.com/r/tmux/comments/3paqoi/tmux_21_has_been_released/cw552qd
|
||||
|
||||
# tmux buffers
|
||||
# PREFIX # : List all paste buffers
|
||||
# PREFIX - : Delete the most recently copied buffer of text
|
||||
# PREFIX = : Choose which buffer to paste interactively from a list
|
||||
# PREFIX ] : Paste the most recently copied buffer of text
|
||||
|
||||
# How to start a temporary tmux server in addition to an existing running one?
|
||||
# > tmux -L temp
|
||||
|
||||
# In a shell environment in a terminal in tmux, the env var $TMUX will be
|
||||
# defined to something like "/tmp/tmux-23273/default,31101,0". Outside tmux,
|
||||
# $TMUX will be undefined.
|
||||
|
||||
# Notation to address a specific pane
|
||||
# SESSION_NAME:WINDOW_INDEX.PANE_NUMBER (Example: foo:2.1 i.e. Pane 1 in Window 2 of Session foo)
|
||||
|
||||
# To print a message containing tmux variable values to stdout use '-p' option in display-message
|
||||
# tmux display-message -p '#{session_name}:#{window_name}.#{pane_index}', or
|
||||
# tmux display -p '#{session_name}:#{window_name}.#{pane_index}'
|
||||
84
regress/conf/b9f0ce1976ec62ec60dc5da7dd92c160.conf
Normal file
84
regress/conf/b9f0ce1976ec62ec60dc5da7dd92c160.conf
Normal file
@@ -0,0 +1,84 @@
|
||||
# none of these attempts worked, to bind keys, except sometimes during the sesssion. Oh well.
|
||||
# I thought maybe that was because F1 is handled differently in a console than in X, but
|
||||
# even just C-1 didnt work. Using just "a" or "x" as the key did, but not yet sure why not "C-".
|
||||
#bind-key -T root C-1 attach-session -t$0
|
||||
#But this one works now, only picks the wrong one? Mbe need2understand what "$1" or $0 mean, better,
|
||||
#but with the stub maybe this doesn't matter:
|
||||
bind-key "`" switch-client -t$1
|
||||
|
||||
new-session #$0, stub, for keystroke convenience
|
||||
|
||||
#$1 for root
|
||||
new-session #a stub I guess, where keyboard convenience is concerned
|
||||
new-window
|
||||
send-keys -l pgup
|
||||
send-keys Enter
|
||||
send-keys -l "less /root/.tmux.conf &"
|
||||
send-keys -l "echo; echo; echo Put something here for ssa or just run manly?"
|
||||
send-keys Enter
|
||||
new-window
|
||||
new-window
|
||||
new-window sul #for lcall, like man pages
|
||||
send-keys -l "man tmux&"
|
||||
send-keys Enter
|
||||
select-window -t :=1
|
||||
|
||||
#$2 for om, so, can do C-b C-s 2 to get to the session, then C-b <#s> to get ~"tabs"
|
||||
new-session sula ; send-keys -l q #0
|
||||
send-keys Enter Escape Escape
|
||||
new-window sula ; send-keys -l q #1
|
||||
send-keys Enter Escape Escape
|
||||
new-window sula ; send-keys -l q #2
|
||||
send-keys Enter Escape Enter Enter
|
||||
new-window sula ; send-keys q #3, to start:
|
||||
send-keys Enter Escape
|
||||
# %%need a sleep here & .. ?
|
||||
send-keys Enter Enter Enter Enter
|
||||
new-window sula ; send-keys -l q #4
|
||||
send-keys Enter Escape Escape
|
||||
new-window sula
|
||||
new-window sula
|
||||
new-window sula
|
||||
new-window sula
|
||||
new-window sula
|
||||
select-window -t :=2
|
||||
select-window -t :=3
|
||||
|
||||
#$3 for email (mutt)
|
||||
new-session sula
|
||||
new-window sula ; send-keys mutt Enter
|
||||
#nah, probly betr not?:
|
||||
#send-keys -l z
|
||||
#send-keys -l "thepassifdecide"
|
||||
#send-keys Enter
|
||||
new-window sula ; send-keys mutt Enter
|
||||
send-keys -l "c!=sent"
|
||||
send-keys Enter
|
||||
new-window sula ; send-keys -l "cd mail/config; less mailsig.txt&"
|
||||
send-keys Enter
|
||||
send-keys "less macros&"
|
||||
send-keys Enter
|
||||
select-window -t :=1
|
||||
|
||||
#$4 for lacall-net: links etc
|
||||
new-session suln
|
||||
new-window suln
|
||||
#send-keys -l "lkslfx" #; et; links ksl.com"
|
||||
#send-keys asdafdfadfadfadfadf
|
||||
#%%does opening links break subsequent cmds? With this Enter, the switch-client etc dont work:
|
||||
#send-keys Enter
|
||||
#send-keys Space Space Space
|
||||
new-window suln
|
||||
new-window suln
|
||||
select-window -t :=1
|
||||
#send-keys Space Space Space
|
||||
|
||||
#$5 for lacall-secnet, links?:
|
||||
#new-session sulsn
|
||||
|
||||
# then, where to start:
|
||||
#%%need a sleep here, or ck a debug thing?
|
||||
switch-client -t"$0"
|
||||
send-keys -l "sleep 2"
|
||||
send-keys Enter
|
||||
switch-client -t$2
|
||||
108
regress/conf/d0040b2e097f1e3d31d78eed6ce8d461.conf
Normal file
108
regress/conf/d0040b2e097f1e3d31d78eed6ce8d461.conf
Normal file
@@ -0,0 +1,108 @@
|
||||
# Put the status bar on top
|
||||
#set -g status-position "top"
|
||||
|
||||
# Basic colours, safer for dumb terminals.
|
||||
#set -g status-style "bg=white,fg=black"
|
||||
#set -g status-right-style "bg=green,fg=black"
|
||||
#set -g window-status-current-style "bg=yellow,fg=black"
|
||||
#set -g message-style "bg=white,fg=black"
|
||||
#set -g window-status-activity-style "fg=blue"
|
||||
#set -g window-status-bell-style "fg=red"
|
||||
|
||||
## Moar colours! Not recommended if attaching from dumber terminals with 8 or 16 colours.
|
||||
#set -g default-terminal "tmux-256color"
|
||||
# A more compatible XTERM var.
|
||||
set -g default-terminal "screen-256color"
|
||||
set -g message-style "bg=#485548 fg=#ffffff"
|
||||
set -g pane-border-style "fg=#424954"
|
||||
set -g pane-active-border-style "fg=#ffffff"
|
||||
set -g status-style "bg=#424954 fg=#ffffff"
|
||||
set -g status-right-style "bg=#303338 fg=colour87"
|
||||
set -g window-status-current-style "bg=#303338"
|
||||
set -g window-status-last-style "bg=#364146"
|
||||
set -g window-status-format ' #I:#W#[fg=colour201]#F '
|
||||
set -g window-status-current-format ' #[fg=colour226]#I#[fg=#ffffff]:#[fg=colour119]#W#[fg=colour202]#F '
|
||||
set -g window-status-separator ""
|
||||
|
||||
# Uncomment and reload settings for sanity in a console with 8 colours.
|
||||
#set -g status-style "bg=white,fg=black"
|
||||
#set -g window-status-last-style "bg=white"
|
||||
|
||||
# Might help when graphical characters used for vertical and horizontal lines are drawn as x and q.
|
||||
#set-option -ga terminal-overrides ',*:enacs@:smacs@:rmacs@:acsc@'
|
||||
|
||||
# Count panes starting from 1.
|
||||
set -g base-index 1
|
||||
|
||||
# With this you set the window name in the status line.
|
||||
# Beware of outrageous prompts, such as the default one in RHEL 7.
|
||||
set -g set-titles on
|
||||
# Let status right consists of only the pane title (removes date and time).
|
||||
# Usually shows current path.
|
||||
set -g status-right ' #T '
|
||||
# Increase the default length of 40.
|
||||
set -g status-right-length 80
|
||||
|
||||
# Scroll up with the mouse.
|
||||
set -g mouse
|
||||
|
||||
# Clipboard integration, use this in tandem with the recommended xterm settings.
|
||||
set -g set-clipboard on
|
||||
# Pass through modifier keys, xterm style. You'll want this in vim.
|
||||
set -g xterm-keys on
|
||||
# Reduce time to wait for Escape key. You'll want this for neovim.
|
||||
set-option escape-time 40
|
||||
# Leave ESC alone...
|
||||
#set-option -s escape-time 0
|
||||
|
||||
# New-style mouse scroll (>2.1)
|
||||
bind -n WheelUpPane select-pane -t= \; copy-mode -e \; send-keys -M
|
||||
bind -n WheelDownPane select-pane -t= \; send-keys -M
|
||||
|
||||
# This is for scrolling up with the terminal using keys, but has issues...
|
||||
#set -ga terminal-overrides ',xterm*:smcup@:rmcup@'
|
||||
|
||||
# 10x more history.
|
||||
set -g history-limit 20000
|
||||
|
||||
# Swap the default Control-b with Control-s which usually stops the output in a shell.
|
||||
unbind C-b
|
||||
set-option -g terminal-overrides "xterm-rightclick:krightclick=^[[29~"
|
||||
set -g prefix C-s
|
||||
bind C-s send-prefix
|
||||
|
||||
# For renumbering windows when you get gaps in numbering.
|
||||
bind R \
|
||||
move-window -r\; \
|
||||
display-message "Windows reordered..."
|
||||
|
||||
# My shortcuts.
|
||||
#bind-key -n C-S-t new-window # Doesn't work :-/
|
||||
bind-key -n C-t new-window
|
||||
bind-key -n C-PgUp prev
|
||||
bind-key -n C-PgDn next
|
||||
#bind-key -n C-S-PgUp swap-window -t -1 # Doesn't work :-/
|
||||
#bind-key -n C-S-PgDn swap-window -t +1 # Doesn't work :-/
|
||||
bind-key -n C-S-Left swap-window -t -1
|
||||
bind-key -n C-S-Right swap-window -t +1
|
||||
bind-key -n M-` select-window -t 0
|
||||
bind-key -n M-1 select-window -t 1
|
||||
bind-key -n M-2 select-window -t 2
|
||||
bind-key -n M-3 select-window -t 3
|
||||
bind-key -n M-4 select-window -t 4
|
||||
bind-key -n M-5 select-window -t 5
|
||||
bind-key -n M-6 select-window -t 6
|
||||
bind-key -n M-7 select-window -t 7
|
||||
bind-key -n M-8 select-window -t 8
|
||||
bind-key -n M-9 select-window -t 9
|
||||
bind-key -n M-0 select-window -t 10
|
||||
|
||||
# switch panes without prefix using Alt-arrow
|
||||
bind -n M-Left select-pane -L
|
||||
bind -n M-Right select-pane -R
|
||||
bind -n M-Up select-pane -U
|
||||
bind -n M-Down select-pane -D
|
||||
|
||||
# join pane from inputted window (horizontally or vertically)
|
||||
#bind-key @ command-prompt -p "join pane from:" "join-pane -s ':%%' -h"
|
||||
bind-key @ command-prompt -p "join pane from:" "join-pane -s ':%%' -v"
|
||||
198
regress/conf/d2e576f947e108eb9903679b65c81fbc.conf
Normal file
198
regress/conf/d2e576f947e108eb9903679b65c81fbc.conf
Normal file
@@ -0,0 +1,198 @@
|
||||
### GENERAL
|
||||
|
||||
set-option -g prefix C-a # Set prefix to <C-a>
|
||||
bind a send-prefix # Send <C-a> with <C-a>a
|
||||
|
||||
bind R source-file ~/.tmux.conf \; display "~/.tmux.conf reloaded"
|
||||
bind -n M-R source-file ~/.tmux.conf \; display "~/.tmux.conf reloaded"
|
||||
|
||||
set -g history-limit 10000 # lines to keep in hisoty
|
||||
set-option -g display-panes-time 3000 # Timeout for pane-numbering in ms
|
||||
bind -n M-q display-panes
|
||||
set-option -sg escape-time 0 # speed up commands
|
||||
set -g mouse on # enable mouse (tmux 2.1+)
|
||||
set -g base-index 1 # start window numbering at 1
|
||||
set -g pane-base-index 1 # start pane numbering at 1
|
||||
set -g renumber-windows on # renumber windows automatically
|
||||
setw -g automatic-rename on # rename window after process
|
||||
|
||||
# Clear window name before renaming
|
||||
bind , rename-window "" \; command-prompt "rename-window '%%'"
|
||||
|
||||
#### APPEARANCE
|
||||
|
||||
set -g default-terminal "screen-256color" # use 256 colors
|
||||
setw -g aggressive-resize on # resize window to smallest client
|
||||
|
||||
set -g pane-border-style fg=colour238 # border color for inactive panes
|
||||
set -g pane-active-border-style fg=colour247 # border color for active panes
|
||||
|
||||
# Status bar colors and format
|
||||
setw -g window-status-format ' #[fg=#999999]#I #[fg=$666666]#W '
|
||||
setw -g window-status-current-format '#[fg=#ffffff] #I #W#[fg=#ffffff] '
|
||||
setw -g window-status-separator '#[fg=#292929]|#[fg=default]'
|
||||
set -g status-bg default # background color for status bar
|
||||
set -g status-position bottom # put status bar on top or bottom
|
||||
set -g status-interval 2 # interval in s to update status
|
||||
set -g status-justify left # horizontal alignment
|
||||
set -g message-style fg=white,bg=black # appearance of status messages
|
||||
set -g message-command-style fg=white # appearance of status message cmds
|
||||
|
||||
# Left section of status bar
|
||||
set -g status-left ""
|
||||
|
||||
# Status bar visibility
|
||||
set -g status off
|
||||
bind -r -n M-t set status on
|
||||
bind -r -n M-T set status off
|
||||
bind t set status on
|
||||
bind T set status off
|
||||
|
||||
# Right section of status bar
|
||||
if-shell 'uname | grep -qi Darwin' "set -g status-right \"#[fg=#81a2be]#(/usr/local/bin/mpc | head -n 1 | sed 's/volume.*$//') #[fg=cyan]#(~/bin/battery-osx) #(~/bin/mailstatus.sh) #[fg=yellow]#(uptime|sed 's/.* //') #[fg=#666666]%F #[fg=#bababa]%R\""
|
||||
|
||||
if-shell 'uname | grep -qi Linux' "set -g status-right \"#[fg=cyan]#(~/bin/battery-linux) #(~/bin/mailstatus.sh) #[fg=yellow]#(cat /proc/loadavg|awk '{print $1;}') #[fg=#666666]%F #[fg=#bababa]%R\""
|
||||
|
||||
# Scaling of status-bar sections
|
||||
set -g status-right-length 40
|
||||
|
||||
|
||||
#### NAVIGATION
|
||||
|
||||
# With C-a prefix
|
||||
bind h select-pane -L # navigate left with <C-a>h
|
||||
bind j select-pane -D # navigate down with <C-a>j
|
||||
bind k select-pane -U # navigate up with <C-a>k
|
||||
bind l select-pane -R # navigate right with <C-a>l
|
||||
bind -r H resize-pane -L 5 # resize pane left with <C-a>H
|
||||
bind -r J resize-pane -D 5 # resize pane down with <C-a>J
|
||||
bind -r K resize-pane -U 5 # resize pane up with <C-a>K
|
||||
bind -r L resize-pane -R 5 # resize pane right with <C-a>L
|
||||
|
||||
# Navigate panes with Meta (alt) modifier + hjkl
|
||||
bind -r -n M-h select-pane -L # navigate left with M-h
|
||||
bind -r -n M-j select-pane -D # navigate down with M-j
|
||||
bind -r -n M-k select-pane -U # navigate up with M-k
|
||||
bind -r -n M-l select-pane -R # navigate right with M-l
|
||||
bind -r -n M-H resize-pane -L 5 # resize pane left with M-H
|
||||
bind -r -n M-J resize-pane -D 5 # resize pane down with M-J
|
||||
bind -r -n M-K resize-pane -U 5 # resize pane up with M-K
|
||||
bind -r -n M-L resize-pane -R 5 # resize pane right with M-L
|
||||
|
||||
# Navigate windows with Meta (alt) modifier + number keys
|
||||
bind -n M-1 select-window -t :=1
|
||||
bind -n M-2 select-window -t :=2
|
||||
bind -n M-3 select-window -t :=3
|
||||
bind -n M-4 select-window -t :=4
|
||||
bind -n M-5 select-window -t :=5
|
||||
bind -n M-6 select-window -t :=6
|
||||
bind -n M-7 select-window -t :=7
|
||||
bind -n M-8 select-window -t :=8
|
||||
bind -n M-9 select-window -t :=9
|
||||
bind -n M-0 select-window -t :=10
|
||||
|
||||
bind C-s last-window # go to last window with <C-a><C-s>
|
||||
bind C-a last-pane # go to last pane with <C-a><C-a>
|
||||
bind -n M-s last-window # go to last pane with M-s
|
||||
bind -n M-a last-pane # go to last pane with M-a
|
||||
bind -r n next-window # next window with <C-a>n
|
||||
bind -r b previous-window # next window with <C-a>p
|
||||
|
||||
bind -n -r M-n next-window # next window with <M-n>
|
||||
bind -n -r M-b previous-window # previous window with <M-n>
|
||||
#bind -n M-, run-shell "tmux list-panes -as -F \"##I.##P ##{pane_current_command} . #{pane_current_path} (#W)#F\" | fzf-tmux | cut -d \" \" -f 1 | xargs tmux select-pane -t"
|
||||
bind -n M-, run-shell "tmux list-windows -F \"##I:##W\" | fzf-tmux | cut -d \":\" -f 1 | xargs tmux select-window -t"
|
||||
bind -n M-. run-shell "tmux list-sessions -F \"##S\" | fzf-tmux | xargs tmux switch -t"
|
||||
|
||||
|
||||
#### LAYOUT CHANGING BINDINGS
|
||||
|
||||
# create panes in same directory
|
||||
bind '"' split-window -c "#{pane_current_path}"
|
||||
bind '%' split-window -h -c "#{pane_current_path}"
|
||||
|
||||
bind -r z resize-pane -Z # toggle pane zoom with <C-a>z
|
||||
bind -r y next-layout # cycle to next pane layout with <C-a>y
|
||||
bind -r Y previous-layout # cycle to previous pane layout with <C-a>Y
|
||||
bind -r r rotate-window # rotate panes with <C-a>r
|
||||
|
||||
bind -n M-z resize-pane -Z # toggle pane zoom with <M-z>
|
||||
bind -n -r M-y next-layout # cycle to next pane layout with <M-y>
|
||||
bind -n -r M-Y previous-layout # cycle to previous pane layout with <M-Y>
|
||||
bind -n -r M-r rotate-window # rotate panes with <M-r>
|
||||
|
||||
bind -r Left swap-window -t -1 # Swap window left
|
||||
bind -r Right swap-window -t +1 # Swap window right
|
||||
|
||||
bind -r B swap-window -t -1 # Swap window left
|
||||
bind -r N swap-window -t +1 # Swap window right
|
||||
bind -n -r M-B swap-window -t -1 # Swap window left
|
||||
bind -n -r M-N swap-window -t +1 # Swap window right
|
||||
|
||||
#### CLIPBOARD
|
||||
|
||||
# enable reattach-to-user-namespace which fixes pasteboard access and launchctl
|
||||
bind Space copy-mode # enter copy mode with <C-a><Space>
|
||||
bind -n M-u copy-mode # enter copy mode with M-u
|
||||
bind -T copy-mode-vi M-u send -X halfpage-up # scroll up with M-u
|
||||
bind -T copy-mode-vi M-d send -X halfpage-down # scroll down with M-d
|
||||
bind -T copy-mode-vi v send -X begin-selection # start "visual" with v
|
||||
|
||||
# Copy (yank) with y
|
||||
if-shell 'uname | grep -qi Linux && which xclip > /dev/null' 'bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "DISPLAY=:0 xclip -i -sel clipboard"'
|
||||
if-shell 'uname | grep -qi Darwin' 'bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "pbcopy"'
|
||||
if-shell 'uname | grep -qi Cygwin' 'bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "cat > /dev/clipboard"'
|
||||
|
||||
# Paste with C-a p or M-p
|
||||
if-shell 'uname | grep -qi Linux && which xclip > /dev/null' 'bind p run "DISPLAY=:0 xclip -o | tmux load-buffer - ; tmux paste-buffer"'
|
||||
if-shell 'uname | grep -qi Darwin && which reattach-to-user-namespace > /dev/null' 'bind p run "pbpaste | tmux load-buffer - ; tmux paste-buffer"'
|
||||
if-shell 'uname | grep -qi Darwin' 'bind -n M-p run "pbpaste | tmux load-buffer - ; tmux paste-buffer"'
|
||||
if-shell 'uname | grep -qi Cygwin' 'bind p run "cat /dev/clipboard | tmux load-buffer - ; tmux paste-buffer"'
|
||||
if-shell 'uname | grep -qi Cygwin' 'bind -n M-p run "cat /dev/clipboard | tmux load-buffer - ; tmux paste-buffer"'
|
||||
|
||||
|
||||
#### LAUNCH PROCESSES
|
||||
|
||||
# use urlview to follow URLs in current pane
|
||||
bind u capture-pane -J \; \
|
||||
save-buffer "/tmp/active_tmux_buffer" \; \
|
||||
delete-buffer \; \
|
||||
split-window -l 10 "urlview '/tmp/active_tmux_buffer' && rm /tmp/active_tmux_buffer"
|
||||
|
||||
# Launch offlineimap in inactive splits
|
||||
bind o split-window -p 25 '$SHELL -c "offlineimap -qf INBOX"' \; select-pane -l
|
||||
bind O split-window -p 25 '$SHELL -c "offlineimap"' \; select-pane -l
|
||||
|
||||
# Use nested bindings (<C-a>l) for grouping process launch bindings
|
||||
bind -n C-M-v new-window -n vim "/usr/local/bin/vim"
|
||||
bind -n C-M-w new-window -n weather \
|
||||
"curl 'wttr.in/?m'; echo -e '\nPress <enter> to quit'; read -n 1 -s"
|
||||
|
||||
# Open new window and resize status accordingly (should be a hook instead)
|
||||
bind Enter new-window -c "#{pane_current_path}" "$SHELL"
|
||||
bind -n M-Enter new-window \
|
||||
"tmux set status-right-length `echo $(tput cols)/2|bc|tr -d '\n'`; zsh"
|
||||
|
||||
# Use nested bindings (<C-a>m) for grouping music-control bindings
|
||||
bind m switchc -Tmpd
|
||||
bind -n M-m switchc -Tmpd
|
||||
bind -Tmpd v new-window -n vimpc "vimpc"
|
||||
bind -Tmpd p display "#(mpc toggle | tr '\n' ' ')"
|
||||
bind -Tmpd s display "#(mpc stop | tr '\n' ' ')"
|
||||
bind -Tmpd n display "#(mpc next | tr '\n' ' ')"
|
||||
bind -Tmpd b display "#(mpc prev | tr '\n' ' ')"
|
||||
bind -Tmpd r display "#(mpc clear && mpc ls | mpc add && mpc random on && mpc play | tr '\n' ' ')"
|
||||
#bind -Tmpd r new-window -n mpc "mpc clear && mpc ls | mpc add && mpc shuffle && mpc play"
|
||||
|
||||
bind -n C-M-p display "#(mpc toggle | tr '\n' ' ')"
|
||||
bind -n C-M-s display "#(mpc stop | tr '\n' ' ')"
|
||||
bind -n C-M-n display "#(mpc next | tr '\n' ' ')"
|
||||
bind -n C-M-b display "#(mpc prev | tr '\n' ' ')"
|
||||
#bind -n C-M-r display "#(mpc clear && mpc ls | mpc add && mpc random on && mpc play | tr '\n' ' ')"
|
||||
bind -n C-M-a split-window -p 50 "source ~/code/fzf-mpd/fzf-mpd.zsh && fm"
|
||||
|
||||
# fzf-locate from entire file system and insert result in current pane (Alt-`)
|
||||
bind -n 'M-`' run "tmux split-window -p 40 'tmux send-keys -t #{pane_id} \"$(locate / | fzf -m | paste -sd\\ -)\"'"
|
||||
|
||||
# Change to the previous pane, repeat the last command, change back
|
||||
bind -n M-! last-pane \; send-keys C-p C-m \; last-pane
|
||||
148
regress/conf/d41d8cd98f00b204e9800998ecf8427e.conf
Normal file
148
regress/conf/d41d8cd98f00b204e9800998ecf8427e.conf
Normal file
@@ -0,0 +1,148 @@
|
||||
set-option -g prefix C-a
|
||||
unbind-key C-b
|
||||
bind-key C-a send-prefix
|
||||
|
||||
set-option -s set-clipboard on
|
||||
set -sg escape-time 0
|
||||
set -g bell-action other
|
||||
set -g lock-after-time 1800
|
||||
set -g lock-command 'tput civis && read -s -n1'
|
||||
set -g history-limit 10000
|
||||
set -g default-terminal "screen-256color"
|
||||
set -g pane-border-style fg=white,bg=default
|
||||
set -g pane-active-border-style fg=red,bg=default
|
||||
set -g repeat-time 100
|
||||
set -g terminal-overrides "xterm*:kLFT5=\eOD:kRIT5=\eOC:kUP5=\eOA:kDN5=\eOB:smkx@:rmkx@:Tc"
|
||||
|
||||
#set -g terminal-overrides '*88col*:colors=88,*256col*:colors=256,rxvt-uni*:Tc:XT:Ms=\E]52;%p1%s;%p2%s\007:Cc=\E]12;%p1%s\007:Cr=\E]12;green\007:Cs=\E]777;Cs;%p1%d\007'
|
||||
set -g mouse on
|
||||
set -g status-style bg=blue,fg=cyan
|
||||
|
||||
set-hook -g alert-bell 'run -b "notify-send \"Bell in session #{session_name}:#{window_index}:#{window_name}\""'
|
||||
|
||||
unbind-key /
|
||||
unbind-key c
|
||||
unbind-key d
|
||||
unbind-key f
|
||||
unbind-key i
|
||||
unbind-key l
|
||||
unbind-key n
|
||||
unbind-key o
|
||||
unbind-key p
|
||||
unbind-key r
|
||||
unbind-key s
|
||||
unbind-key t
|
||||
unbind-key w
|
||||
unbind-key x
|
||||
unbind-key |
|
||||
unbind-key -
|
||||
unbind-key A
|
||||
unbind-key S
|
||||
unbind-key .
|
||||
unbind-key "'"
|
||||
unbind-key '#'
|
||||
unbind-key ' '
|
||||
unbind-key z
|
||||
unbind-key ^z
|
||||
|
||||
bind a send-prefix
|
||||
bind c new-window -a -c '#{pane_current_path}'
|
||||
bind d detach-client
|
||||
bind "/" command-prompt "find-window '%%'"
|
||||
bind i display-message
|
||||
bind a last-window
|
||||
bind n next-window
|
||||
bind o select-pane -D
|
||||
bind p previous-window
|
||||
bind r respawn-window
|
||||
bind s choose-tree -Z
|
||||
bind t clock-mode
|
||||
bind w choose-window
|
||||
bind k confirm-before kill-pane
|
||||
bind x set lock-command '/usr/bin/vlock' \; lock-client \; set lock-command 'tput civis && read -s -n1'
|
||||
bind "|" split-window -v -c '#{pane_current_path}'
|
||||
bind "-" split-window -h -c '#{pane_current_path}'
|
||||
bind l command-prompt "rename-window '%%'"
|
||||
bind S command-prompt "rename-session '%%'"
|
||||
bind . display-panes
|
||||
bind "'" command-prompt -p "SSH: " "new-window -n %1 'ssh %1'"
|
||||
bind ' ' choose-window
|
||||
bind z resize-pane -Z
|
||||
|
||||
bind ^a last-window
|
||||
bind ^c new-window -a -c '#{pane_current_path}'
|
||||
bind ^d detach-client
|
||||
bind ^i display-message
|
||||
bind a last-window
|
||||
bind ^n next-window
|
||||
bind ^o select-pane -D
|
||||
bind ^p previous-window
|
||||
bind ^r respawn-window
|
||||
bind ^s choose-session
|
||||
bind ^t clock-mode
|
||||
bind ^w choose-window
|
||||
bind ^k confirm-before kill-pane
|
||||
bind ^x lock-client
|
||||
bind ^S command-prompt "rename-session '%%'"
|
||||
bind ^z resize-pane -Z
|
||||
|
||||
bind -n C-Left previous-window
|
||||
bind -n C-Right next-window
|
||||
bind -n C-s set status
|
||||
|
||||
bind -r C-Left swapw -t:-
|
||||
bind -r C-Right swapw -t:+
|
||||
|
||||
# Status stuff.
|
||||
set -g status-left-style "fg=white, bg=magenta"
|
||||
set -g status-left-length 30
|
||||
set -g status-left "#S "
|
||||
set -g status-right-length 30
|
||||
set -g status-right-fg white
|
||||
set -g status-right-bg blue
|
||||
set -g status-right "#{?client_prefix,#[reverse][^a]#[noreverse],}[%a %d/%m %H:%M]"
|
||||
set -g display-panes-time 4000
|
||||
set -g window-status-bell-style reverse
|
||||
|
||||
#setw -g window-status-current-fg white
|
||||
#setw -g window-status-current-bg colour34
|
||||
setw -g mode-keys vi
|
||||
|
||||
setw -g window-status-separator "| "
|
||||
#setw -g window-status-format "#[bg=blue]#I:#W:#{window_flags}#[bg=default]"
|
||||
#setw -g window-status-current-format "#[fg=black,bg=green]#I:#W:#{window_flags}"
|
||||
|
||||
setw -g window-status-format "#[bg=blue]#I:#W:#{?window_linked,+#{window_flags},#{window_flags} }#[bg=default]"
|
||||
setw -g window-status-current-format "#[fg=black,bg=green]#I:#W:#{?window_linked,+#{window_flags},#{window_flags}}"
|
||||
|
||||
set-window-option -g clock-mode-colour green
|
||||
|
||||
# Sessions
|
||||
new -d -sspecial
|
||||
new -d -swork -d -nmutt 'exec neomutt'
|
||||
neww -d
|
||||
neww -d
|
||||
neww -d
|
||||
neww -d
|
||||
|
||||
# FIXME -- the entire block below is required for taskwarrior.
|
||||
#new -d -stask -ntask -x237 -y 79
|
||||
#selectl -ttask tiled
|
||||
#set -ttask status off
|
||||
#splitw -ttask:task
|
||||
#splitw -ttask:task
|
||||
#splitw -ttask:task
|
||||
#splitw -ttask:task
|
||||
#splitw -ttask:task
|
||||
#selectl -ttask:task 4ada,237x79,0,0[237x67,0,0{156x67,0,0,5,80x67,157,0[80x27,157,0,19,80x22,157,28,20,80x16,157,51,21]},237x11,0,68,22]
|
||||
#send -ttask:task.0 'cyclenext list' 'C-m'
|
||||
#send -ttask:task.1 'clear ; tasksh' 'C-m'
|
||||
#send -ttask:task.2 'cyclenext summary' 'C-m'
|
||||
#send -ttask:task.3 'cyclenext burndown.daily' 'C-m'
|
||||
#send -ttask:task.4 'cyclenext ghistory.monthly' 'C-m'
|
||||
#selectp -ttask:task.1
|
||||
#linkw -stask:task -twork
|
||||
#set -t task:task remain-on-exit on
|
||||
|
||||
set -t work:irc remain-on-exit on
|
||||
set -t work:mutt remain-on-exit on
|
||||
52
regress/conf/dfd579a114a8366b5a665c264e29c084.conf
Normal file
52
regress/conf/dfd579a114a8366b5a665c264e29c084.conf
Normal file
@@ -0,0 +1,52 @@
|
||||
set -as terminal-overrides '\e\r\n\t\u12ab\U000012ab'
|
||||
set -as terminal-overrides "\e\r\n\t\u12ab\U000012ab"
|
||||
|
||||
# format #{abc #{def}}
|
||||
# abc
|
||||
|
||||
set -g status-left \
|
||||
"\u007c \
|
||||
abc"
|
||||
|
||||
%if #{TMUX}
|
||||
set -g status-bg red
|
||||
%endif
|
||||
|
||||
X=1
|
||||
Y=2 set -g status-bg blue; Z=3 set -g status-bg magenta
|
||||
|
||||
set -g status-left "~/abcdef"$HOME # abcdef
|
||||
|
||||
%if #{l:1} set -g status-bg red %endif
|
||||
|
||||
%if #{l:0}
|
||||
X=1
|
||||
%elif #{l:1}
|
||||
Y=1
|
||||
%if #{l:0}
|
||||
Y=2
|
||||
%else
|
||||
Y=3
|
||||
%endif
|
||||
%endif
|
||||
|
||||
bind x display-message \"hello\"
|
||||
|
||||
bind c neww -c ~
|
||||
bind ';' lsk
|
||||
|
||||
set -g status-left "a""b"
|
||||
set -g status-left ~
|
||||
|
||||
set -g status-left 'a $HOME b ~ c \e\e\e'
|
||||
set -g status-left "a $HOME b ~ c \e\e\e"
|
||||
|
||||
set -s command-alias[99] "foo=lsk;neww"
|
||||
bind-key -n C-s if-shell 'true' 'display-message hello'
|
||||
|
||||
set -g status-left-style \
|
||||
bg=red
|
||||
set -g status-left \\\
|
||||
abc
|
||||
|
||||
set -g status-left 'xyz' ; %if #{l:1} set -g status-bg red %endif ; bind x lsk
|
||||
78
regress/conf/e2661d67d0d45a8647fb95de76ec8174.conf
Normal file
78
regress/conf/e2661d67d0d45a8647fb95de76ec8174.conf
Normal file
@@ -0,0 +1,78 @@
|
||||
# Scott Rochford's tmux configuration
|
||||
#
|
||||
# change the prefix to the GNU screen default (avoids clash with page up in vi)
|
||||
set -g prefix C-a
|
||||
unbind-key C-b
|
||||
bind-key C-a send-prefix
|
||||
# toggle sending input to all panes
|
||||
bind-key b set-window-option synchronize-panes
|
||||
# alternative to ',' which doesn't pre-fill the prompt with the existing name
|
||||
bind-key < command-prompt "rename-window '%%'"
|
||||
|
||||
# Disabled all of these in favour of changing 'default-command' below.
|
||||
#bind-key C-p pipe-pane -o 'cat >>~/tmux_logs/output.$(echo #I-#P-#W-#T | sed "s/[^[:alnum:].-]/_/g")' \; display-message 'Toggled logging'
|
||||
# From http://unix.stackexchange.com/questions/5832/is-there-an-equivalent-of-gnu-screens-log-command-in-tmux
|
||||
# bind-key H pipe-pane -o "exec cat >>$HOME/'#W-tmux.log'" \; display-message 'Toggled logging to $HOME/#W-tmux.log'
|
||||
#bind-key H pipe-pane "exec cat >>$HOME/'#W-tmux.log'" \; display-message 'Started logging to $HOME/#W-tmux.log'
|
||||
#bind-key h pipe-pane \; display-message 'Ended logging to $HOME/#W-tmux.log'
|
||||
|
||||
#set -g utf8 on
|
||||
|
||||
set-option -g history-limit 32768
|
||||
|
||||
# no longer available in 2.2
|
||||
#set-option -g mouse-select-pane on
|
||||
#set-option -g mouse-select-window on
|
||||
set-option -g mouse on
|
||||
|
||||
# increase the amount of time status bar messages are displayed for (default 1000 I think)
|
||||
set-option -g display-time 1500
|
||||
# unfortunately this seems to have no effect in putty :-(
|
||||
set-option -g set-clipboard on
|
||||
set-option -g default-command 'tmux pipe-pane -o "cat >>~/tmux_logs/output-`date +%Y%m%d-%H%M%S-$$`" ; /bin/ksh -l'
|
||||
#
|
||||
# allow yank into system clipboard
|
||||
# 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
|
||||
# -b for background is needed because xclip continues to run to service the clipboard paste reqeusts until the
|
||||
# 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 save-buffer ~/etc/clipboard.pipe
|
||||
#
|
||||
# this was just for testing, but interestingly for some reason tmux-show-buffer >/tmp/t never terminates, writing to a pipe works fine??
|
||||
#bind C-z run-shell "tmux show-buffer | cat >/tmp/t"
|
||||
# move x clipboard into tmux paste buffer
|
||||
#bind C-p run-shell -b "xclip -o -selection clipboard | tmux load-buffer - ; tmux paste-buffer"
|
||||
bind C-p run-shell "DISPLAY=$(<~/.xdisplay) xclip -o -selection clipboard | tmux load-buffer - ; tmux paste-buffer"
|
||||
|
||||
# switch to last-but-one window (like prefix-l but last, last)
|
||||
# only works on tmux-2.4 + with Nicholas Marriott's patch from my feature request, unless it reached mainline....
|
||||
#bind k run-shell "tmux select-window -t $(tmux list-windows -F '#{session_stack}' | awk -F, '{print $3;exit}END{print $1}')"
|
||||
bind k run-shell "tmux select-window -t $(echo #{session_stack} | awk -F, '{w=$1}NF>=3{w=$3;exit}END{print w}')"
|
||||
|
||||
# switch to oldest window (for clean-up), not sure why brackets are required around (NF) here...
|
||||
bind K run-shell "tmux select-window -t $(echo #{session_stack} | awk -F, '{print $(NF)}')"
|
||||
|
||||
# prompt for hosts to connect to, open a new synchronized window with horizontally split panes for each host, supports brace expansion
|
||||
bind N command-prompt -p hosts: 'run-shell -b "bash -c \"~/lbin/nw %% >/dev/null\""'
|
||||
|
||||
# seems to cause unexpected resizes when focussing on putty :-(
|
||||
#set-option mouse-resize-pane on
|
||||
|
||||
#05:59 < Celti> annihilannic: I believe the #{pane_in_mode} format does what you want
|
||||
#05:59 < Celti> put it in your statusline
|
||||
#05:59 < Celti> annihilannic: No, my mistake, I should have read farther down, you want #{pane_synchronized}
|
||||
# only works in tmux 2.0?, higher than 1.6.3 anyawy
|
||||
set-option -g window-status-format ' #I:#W#F#{?pane_synchronized,S,}'
|
||||
#set-option -g window-status-current-format ' #I:#W#{?pane_synchronized,[sync],}#F'
|
||||
# to highlight in red when sync is on... not sure why I did this with set-window-option instead of set-option, perhaps
|
||||
# both work?
|
||||
set-window-option -g window-status-current-format "#{?pane_synchronized,#[bg=red],}#{?window_zoomed_flag,#[bg=yellow],} #I:#W#F#{?pane_synchronized,S,}"
|
||||
#
|
||||
# also only in 2.0? if I use this, don't need #F in window-status-*-format? - actually, nah,
|
||||
# still useful for showing [Z]oomed, or - last active, etc.
|
||||
set-option -g window-status-current-style bg=blue
|
||||
|
||||
# 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"
|
||||
283
regress/conf/ed08995f38b5a3079262a88d2563abe4.conf
Normal file
283
regress/conf/ed08995f38b5a3079262a88d2563abe4.conf
Normal file
@@ -0,0 +1,283 @@
|
||||
#---------------------------------------------------------------------------#
|
||||
# .tmux.conf
|
||||
# Helmut K. C. Tessarek, Last update 2018-10-16
|
||||
#---------------------------------------------------------------------------#
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# set prefix key to ctrl+a / ctrl-b is used in vi for going back one page
|
||||
#---------------------------------------------------------------------------#
|
||||
unbind C-b
|
||||
set -g prefix C-a
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# send the prefix to client inside window (nested sessions)
|
||||
#---------------------------------------------------------------------------#
|
||||
bind-key a send-prefix
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# toggle last window like screen
|
||||
#---------------------------------------------------------------------------#
|
||||
bind-key C-a last-window
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# start window indexing at one instead of zero
|
||||
#---------------------------------------------------------------------------#
|
||||
#set -g base-index 1
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# default terminal - we want 256 colors !!!
|
||||
#---------------------------------------------------------------------------#
|
||||
set -g default-terminal "screen-256color"
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# on-screen time for status messages in ms
|
||||
#---------------------------------------------------------------------------#
|
||||
set -g display-time 2000
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# on-screen time for display-panes in ms
|
||||
#---------------------------------------------------------------------------#
|
||||
set -g display-panes-time 2000
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# color for display pane indicator
|
||||
#---------------------------------------------------------------------------#
|
||||
set -g display-panes-colour "cyan"
|
||||
#set -g display-panes-active-colour "#0087ff"
|
||||
#set -g display-panes-active-colour "red"
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# open a man page in new window
|
||||
#---------------------------------------------------------------------------#
|
||||
unbind m
|
||||
bind m command-prompt "split-window 'exec man %%'"
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# quick view of processes
|
||||
#---------------------------------------------------------------------------#
|
||||
#bind '~' split-window "exec htop"
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# scrollback buffer n lines
|
||||
#---------------------------------------------------------------------------#
|
||||
set -g history-limit 5000
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# toggle status bar
|
||||
#---------------------------------------------------------------------------#
|
||||
unbind b
|
||||
bind-key b set-option status
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# resize panes like vim
|
||||
# feel free to change the "1" to however many lines you want to resize by,
|
||||
# only one at a time can be slow
|
||||
#---------------------------------------------------------------------------#
|
||||
unbind <
|
||||
unbind >
|
||||
unbind -
|
||||
unbind +
|
||||
bind -r < resize-pane -L 1
|
||||
bind -r > resize-pane -R 1
|
||||
bind -r - resize-pane -D 1
|
||||
bind -r + resize-pane -U 1
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# toggle mouse helpers
|
||||
#---------------------------------------------------------------------------#
|
||||
unbind Enter
|
||||
unbind C-m
|
||||
bind C-m set-option mouse \; display-message 'mouse -> #{?mouse,on,off}'
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# Reload config file
|
||||
#---------------------------------------------------------------------------#
|
||||
unbind R
|
||||
bind-key R source-file ~/.tmux.conf \; display-message "Reloading configuration done"
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# start ssh session in new window
|
||||
#---------------------------------------------------------------------------#
|
||||
unbind S
|
||||
bind-key S command-prompt "new-window -n %1 'ssh %1'"
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# start new session
|
||||
#---------------------------------------------------------------------------#
|
||||
unbind C
|
||||
bind-key C command-prompt "new-session -s %1"
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# Keys to switch session
|
||||
#---------------------------------------------------------------------------#
|
||||
bind Q switchc -t0
|
||||
bind W switchc -t compile
|
||||
bind E switchc -t config
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# break pane in background
|
||||
#---------------------------------------------------------------------------#
|
||||
unbind '@'
|
||||
bind '@' break-pane -d
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# join pane with target window
|
||||
#---------------------------------------------------------------------------#
|
||||
unbind ^
|
||||
bind ^ command-prompt "join-pane -t %1"
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# move around panes with hjkl, as one would in vim after pressing ctrl-w
|
||||
#---------------------------------------------------------------------------#
|
||||
#bind h select-pane -L
|
||||
#bind j select-pane -D
|
||||
#bind k select-pane -U
|
||||
#bind l select-pane -R
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# bind : to command-prompt like vim
|
||||
# this is the default in tmux already
|
||||
#---------------------------------------------------------------------------#
|
||||
bind : command-prompt
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# Remain on exit
|
||||
#---------------------------------------------------------------------------#
|
||||
#setw -g remain-on-exit on
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# vi-style controls for copy mode
|
||||
#---------------------------------------------------------------------------#
|
||||
setw -g mode-keys vi
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# Make mouse useful in copy mode
|
||||
#---------------------------------------------------------------------------#
|
||||
#setw -g mode-mouse on
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# More straight forward key bindings for splitting
|
||||
#---------------------------------------------------------------------------#
|
||||
unbind %
|
||||
unbind v
|
||||
#bind | split-window -h
|
||||
bind v split-window -h
|
||||
unbind '"'
|
||||
unbind h
|
||||
#bind - split-window -v
|
||||
bind h split-window -v
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# Synchronize panes
|
||||
#---------------------------------------------------------------------------#
|
||||
unbind y
|
||||
bind y set-window-option synchronize-panes \; display-message 'synchronize-panes -> #{?synchronize-panes,on,off}'
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# Other key codes: Tab, BTab, Escape
|
||||
#---------------------------------------------------------------------------#
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# Clock
|
||||
#---------------------------------------------------------------------------#
|
||||
setw -g clock-mode-colour green
|
||||
setw -g clock-mode-style 24
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# Terminal emulator window title
|
||||
#---------------------------------------------------------------------------#
|
||||
set -g set-titles on
|
||||
set -g set-titles-string '#S:#I.#P #W'
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# Status Bar
|
||||
#---------------------------------------------------------------------------#
|
||||
set -g status-bg black
|
||||
set -g status-fg white
|
||||
set -g status-interval 1
|
||||
set -g status-left-length 30
|
||||
set -g status-left '#[fg=green]#h#[default] '
|
||||
#set -g status-right '#[fg=yellow]#(cut -d " " -f 1-4 /proc/loadavg)#[default] #[fg=cyan,bold]%Y-%m-%d %H:%M:%S#[default]'
|
||||
#set -g status-right '#[fg=yellow,bold]%Y-%m-%d %H:%M#[default]'
|
||||
set -g status-right '#[fg=yellow]%Y-%m-%d %H:%M %Z#[default]'
|
||||
#set -g status-justify center
|
||||
#set -g status-keys vi
|
||||
|
||||
set -g allow-rename off
|
||||
setw -g automatic-rename on
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# Highlighting the active window in status bar
|
||||
#---------------------------------------------------------------------------#
|
||||
#setw -g window-status-current-bg red
|
||||
set-option -g window-status-format "#I:#W#F#{?pane_synchronized,S,}"
|
||||
set-window-option -g window-status-current-format "#{?pane_synchronized,#[bg=red],}#{?window_zoomed_flag,#[bg=colour130],}#I:#W#F#{?pane_synchronized,S,}"
|
||||
set-option -g window-status-current-style bg=blue
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# global update environment
|
||||
#---------------------------------------------------------------------------#
|
||||
set -g update-environment "DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY TZ"
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# settings for AIX
|
||||
# terminal overrides to enable colors
|
||||
# set default terminal to vt100 or xterm (screen does not exist on AIX)
|
||||
#---------------------------------------------------------------------------#
|
||||
if-shell "uname|grep AIX" 'set -g terminal-overrides "xterm*:XT,xterm*:setab=\\E[4%p1%dm,xterm*:setaf=\\E[3%p1%dm"'
|
||||
#if-shell "uname|grep AIX" "set -g default-terminal vt100"
|
||||
if-shell "uname|grep AIX" "set -g default-terminal xterm"
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# settings for macOS
|
||||
#---------------------------------------------------------------------------#
|
||||
if-shell "uname|grep Darwin" 'set -g default-command "/bin/bash -l"'
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# Pane coloring
|
||||
# set inactive/active window styles
|
||||
#---------------------------------------------------------------------------#
|
||||
set -g window-style "fg=colour247,bg=colour234"
|
||||
set -g window-active-style "fg=colour250,bg=black"
|
||||
set -g @TPCS "1"
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# pane border - different style / use cyan
|
||||
#---------------------------------------------------------------------------#
|
||||
#set -g pane-border-bg colour235
|
||||
#set -g pane-border-fg colour238
|
||||
#set -g pane-active-border-bg colour234
|
||||
#set -g pane-active-border-fg colour51
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# toggle pane coloring on/off
|
||||
#---------------------------------------------------------------------------#
|
||||
unbind C-b
|
||||
bind C-b if -F '#{@TPCS}' \
|
||||
'set -g window-style "fg=default,bg=default" ; set -g window-active-style "fg=default,bg=default" ; set -g @TPCS "0"; display-message "Pane coloring -> off"' \
|
||||
'set -g window-style "fg=colour247,bg=colour234" ; set -g window-active-style "fg=colour250,bg=black" ; set -g @TPCS "1"; display-message "Pane coloring -> on"'
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# List of plugins
|
||||
#---------------------------------------------------------------------------#
|
||||
set -g @plugin 'tmux-plugins/tpm'
|
||||
#set -g @plugin 'tmux-plugins/tmux-sensible'
|
||||
set -g @plugin 'tmux-plugins/tmux-resurrect'
|
||||
set -g @plugin 'tmux-plugins/tmux-logging'
|
||||
|
||||
set -g @resurrect-capture-pane-contents 'on'
|
||||
set -g @resurrect-save-bash-history 'on'
|
||||
|
||||
set -g @logging-path $HOME
|
||||
set -g @screen-capture-path $HOME
|
||||
set -g @save-complete-history-path $HOME
|
||||
|
||||
# Other examples:
|
||||
# set -g @plugin 'github_username/plugin_name'
|
||||
# set -g @plugin 'git@github.com/user/plugin'
|
||||
# set -g @plugin 'git@bitbucket.com/user/plugin'
|
||||
|
||||
#---------------------------------------------------------------------------#
|
||||
# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
|
||||
#---------------------------------------------------------------------------#
|
||||
run '~/.tmux/plugins/tpm/tpm'
|
||||
42
regress/control-client-sanity.sh
Normal file
42
regress/control-client-sanity.sh
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
|
||||
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)
|
||||
OUT=$(mktemp)
|
||||
trap "rm -f $TMP $OUT" 0 1 15
|
||||
|
||||
$TMUX -f/dev/null new -d -x200 -y200 || exit 1
|
||||
$TMUX -f/dev/null splitw || exit 1
|
||||
sleep 1
|
||||
cat <<EOF|$TMUX -C a >$TMP
|
||||
selectp -t%0
|
||||
splitw
|
||||
neww
|
||||
splitw
|
||||
selectp -t%0
|
||||
killp -t%1
|
||||
swapp -t%2 -s%3
|
||||
neww
|
||||
splitw
|
||||
splitw
|
||||
selectl tiled
|
||||
killw
|
||||
EOF
|
||||
sleep 1
|
||||
$TMUX has || exit 1
|
||||
$TMUX lsp -aF '#{pane_id} #{window_layout}' >$TMP || exit 1
|
||||
cat <<EOF|cmp -s $TMP - || exit 1
|
||||
%0 f5ab,200x200,0,0[200x50,0,0,0,200x149,0,51,3]
|
||||
%3 f5ab,200x200,0,0[200x50,0,0,0,200x149,0,51,3]
|
||||
%2 dcbd,200x200,0,0[200x100,0,0,2,200x99,0,101,4]
|
||||
%4 dcbd,200x200,0,0[200x100,0,0,2,200x99,0,101,4]
|
||||
EOF
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
exit 0
|
||||
@@ -23,7 +23,7 @@ refresh -C 100,50
|
||||
ls -F':#{window_width} #{window_height}'
|
||||
EOF
|
||||
grep ^: $TMP >$OUT
|
||||
printf ":80 24\n:100 49\n"|cmp -s $OUT - || exit 1
|
||||
printf ":80 24\n:100 50\n"|cmp -s $OUT - || exit 1
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
$TMUX -f/dev/null new -d || exit 1
|
||||
@@ -34,7 +34,7 @@ refresh -C 80,24
|
||||
ls -F':#{window_width} #{window_height}'
|
||||
EOF
|
||||
grep ^: $TMP >$OUT
|
||||
printf ":80 24\n:80 23\n"|cmp -s $OUT - || exit 1
|
||||
printf ":80 24\n:80 24\n"|cmp -s $OUT - || exit 1
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
cat <<EOF|$TMUX -f/dev/null -C new -x 100 -y 50 >$TMP
|
||||
@@ -43,7 +43,7 @@ refresh -C 80,24
|
||||
ls -F':#{window_width} #{window_height}'
|
||||
EOF
|
||||
grep ^: $TMP >$OUT
|
||||
printf ":100 50\n:80 23\n"|cmp -s $OUT - || exit 1
|
||||
printf ":100 50\n:80 24\n"|cmp -s $OUT - || exit 1
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
exit 0
|
||||
|
||||
5
resize.c
5
resize.c
@@ -174,11 +174,12 @@ recalculate_sizes(void)
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (ignore_client_size(c))
|
||||
continue;
|
||||
if (c->tty.sy <= status_line_size(c))
|
||||
s = c->session;
|
||||
if (c->tty.sy <= s->statuslines || (c->flags & CLIENT_CONTROL))
|
||||
c->flags |= CLIENT_STATUSOFF;
|
||||
else
|
||||
c->flags &= ~CLIENT_STATUSOFF;
|
||||
c->session->attached++;
|
||||
s->attached++;
|
||||
}
|
||||
|
||||
/* Walk each window and adjust the size. */
|
||||
|
||||
188
screen-redraw.c
188
screen-redraw.c
@@ -23,27 +23,11 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
struct screen_redraw_ctx {
|
||||
struct client *c;
|
||||
|
||||
u_int lines;
|
||||
int top;
|
||||
|
||||
int pane_status;
|
||||
|
||||
u_int sx;
|
||||
u_int sy;
|
||||
u_int ox;
|
||||
u_int oy;
|
||||
};
|
||||
|
||||
static void screen_redraw_draw_borders(struct screen_redraw_ctx *);
|
||||
static void screen_redraw_draw_panes(struct screen_redraw_ctx *);
|
||||
static void screen_redraw_draw_status(struct screen_redraw_ctx *);
|
||||
static void screen_redraw_draw_pane(struct screen_redraw_ctx *,
|
||||
struct window_pane *);
|
||||
static void screen_redraw_draw_number(struct screen_redraw_ctx *,
|
||||
struct window_pane *);
|
||||
|
||||
#define CELL_INSIDE 0
|
||||
#define CELL_LEFTRIGHT 1
|
||||
@@ -374,8 +358,8 @@ screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
|
||||
width = size - x;
|
||||
}
|
||||
|
||||
if (ctx->top)
|
||||
yoff += ctx->lines;
|
||||
if (ctx->statustop)
|
||||
yoff += ctx->statuslines;
|
||||
tty_draw_line(tty, NULL, s, i, 0, width, x, yoff - ctx->oy);
|
||||
}
|
||||
tty_cursor(tty, 0, 0);
|
||||
@@ -399,6 +383,9 @@ screen_redraw_update(struct client *c, int flags)
|
||||
if (!redraw && (~flags & CLIENT_REDRAWSTATUSALWAYS))
|
||||
flags &= ~CLIENT_REDRAWSTATUS;
|
||||
|
||||
if (c->overlay_draw != NULL)
|
||||
flags |= CLIENT_REDRAWOVERLAY;
|
||||
|
||||
if (options_get_number(wo, "pane-border-status") != CELL_STATUS_OFF) {
|
||||
redraw = 0;
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
@@ -419,21 +406,25 @@ screen_redraw_set_context(struct client *c, struct screen_redraw_ctx *ctx)
|
||||
struct options *oo = s->options;
|
||||
struct window *w = s->curw->window;
|
||||
struct options *wo = w->options;
|
||||
u_int lines;
|
||||
|
||||
memset(ctx, 0, sizeof *ctx);
|
||||
ctx->c = c;
|
||||
|
||||
ctx->lines = status_line_size(c);
|
||||
lines = status_line_size(c);
|
||||
if (c->message_string != NULL || c->prompt_string != NULL)
|
||||
ctx->lines = (ctx->lines == 0) ? 1 : ctx->lines;
|
||||
if (ctx->lines != 0 && options_get_number(oo, "status-position") == 0)
|
||||
ctx->top = 1;
|
||||
lines = (lines == 0) ? 1 : lines;
|
||||
if (lines != 0 && options_get_number(oo, "status-position") == 0)
|
||||
ctx->statustop = 1;
|
||||
ctx->statuslines = lines;
|
||||
|
||||
ctx->pane_status = options_get_number(wo, "pane-border-status");
|
||||
|
||||
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,
|
||||
w->id, ctx->ox, ctx->oy, ctx->sx, ctx->sy, ctx->lines, ctx->top);
|
||||
w->id, ctx->ox, ctx->oy, ctx->sx, ctx->sy, ctx->statuslines,
|
||||
ctx->statustop);
|
||||
}
|
||||
|
||||
/* Redraw entire screen. */
|
||||
@@ -456,9 +447,11 @@ screen_redraw_screen(struct client *c)
|
||||
}
|
||||
if (flags & CLIENT_REDRAWWINDOW)
|
||||
screen_redraw_draw_panes(&ctx);
|
||||
if (ctx.lines != 0 &&
|
||||
if (ctx.statuslines != 0 &&
|
||||
(flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS)))
|
||||
screen_redraw_draw_status(&ctx);
|
||||
if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY))
|
||||
c->overlay_draw(c, &ctx);
|
||||
tty_reset(&c->tty);
|
||||
}
|
||||
|
||||
@@ -468,7 +461,7 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
|
||||
{
|
||||
struct screen_redraw_ctx ctx;
|
||||
|
||||
if (!window_pane_visible(wp))
|
||||
if (c->overlay_draw != NULL || !window_pane_visible(wp))
|
||||
return;
|
||||
|
||||
screen_redraw_set_context(c, &ctx);
|
||||
@@ -508,8 +501,8 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j,
|
||||
tty_attributes(tty, active_gc, NULL);
|
||||
else
|
||||
tty_attributes(tty, other_gc, NULL);
|
||||
if (ctx->top)
|
||||
tty_cursor(tty, i, ctx->lines + j);
|
||||
if (ctx->statustop)
|
||||
tty_cursor(tty, i, ctx->statuslines + j);
|
||||
else
|
||||
tty_cursor(tty, i, j);
|
||||
tty_putc(tty, CELL_BORDERS[type]);
|
||||
@@ -538,7 +531,7 @@ screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
|
||||
memcpy(&m_active_gc, &active_gc, sizeof m_active_gc);
|
||||
m_active_gc.attr ^= GRID_ATTR_REVERSE;
|
||||
|
||||
for (j = 0; j < tty->sy - ctx->lines; j++) {
|
||||
for (j = 0; j < tty->sy - ctx->statuslines; j++) {
|
||||
for (i = 0; i < tty->sx; i++) {
|
||||
screen_redraw_draw_borders_cell(ctx, i, j,
|
||||
&m_active_gc, &active_gc, &m_other_gc, &other_gc);
|
||||
@@ -557,11 +550,8 @@ screen_redraw_draw_panes(struct screen_redraw_ctx *ctx)
|
||||
log_debug("%s: %s @%u", __func__, c->name, w->id);
|
||||
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (!window_pane_visible(wp))
|
||||
continue;
|
||||
screen_redraw_draw_pane(ctx, wp);
|
||||
if (c->flags & CLIENT_IDENTIFY)
|
||||
screen_redraw_draw_number(ctx, wp);
|
||||
if (window_pane_visible(wp))
|
||||
screen_redraw_draw_pane(ctx, wp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -577,11 +567,11 @@ screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
|
||||
|
||||
log_debug("%s: %s @%u", __func__, c->name, w->id);
|
||||
|
||||
if (ctx->top)
|
||||
if (ctx->statustop)
|
||||
y = 0;
|
||||
else
|
||||
y = c->tty.sy - ctx->lines;
|
||||
for (i = 0; i < ctx->lines; i++)
|
||||
y = c->tty.sy - ctx->statuslines;
|
||||
for (i = 0; i < ctx->statuslines; i++)
|
||||
tty_draw_line(tty, NULL, s, 0, i, UINT_MAX, 0, y + i);
|
||||
}
|
||||
|
||||
@@ -599,8 +589,8 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
|
||||
|
||||
if (wp->xoff + wp->sx <= ctx->ox || wp->xoff >= ctx->ox + ctx->sx)
|
||||
return;
|
||||
if (ctx->top)
|
||||
top = ctx->lines;
|
||||
if (ctx->statustop)
|
||||
top = ctx->statuslines;
|
||||
else
|
||||
top = 0;
|
||||
|
||||
@@ -639,125 +629,3 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
|
||||
tty_draw_line(tty, wp, s, i, j, width, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw number on a pane. */
|
||||
static void
|
||||
screen_redraw_draw_number(struct screen_redraw_ctx *ctx, struct window_pane *wp)
|
||||
{
|
||||
struct client *c = ctx->c;
|
||||
struct tty *tty = &c->tty;
|
||||
struct session *s = c->session;
|
||||
struct options *oo = s->options;
|
||||
struct window *w = wp->window;
|
||||
struct grid_cell gc;
|
||||
u_int idx, px, py, i, j, xoff, yoff, sx, sy;
|
||||
int colour, active_colour;
|
||||
char buf[16], *ptr;
|
||||
size_t len;
|
||||
|
||||
if (wp->xoff + wp->sx <= ctx->ox ||
|
||||
wp->xoff >= ctx->ox + ctx->sx ||
|
||||
wp->yoff + wp->sy <= ctx->oy ||
|
||||
wp->yoff >= ctx->oy + ctx->sy)
|
||||
return;
|
||||
|
||||
if (wp->xoff >= ctx->ox && wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
|
||||
/* All visible. */
|
||||
xoff = wp->xoff - ctx->ox;
|
||||
sx = wp->sx;
|
||||
} else if (wp->xoff < ctx->ox &&
|
||||
wp->xoff + wp->sx > ctx->ox + ctx->sx) {
|
||||
/* Both left and right not visible. */
|
||||
xoff = 0;
|
||||
sx = ctx->sx;
|
||||
} else if (wp->xoff < ctx->ox) {
|
||||
/* Left not visible. */
|
||||
xoff = 0;
|
||||
sx = wp->sx - (ctx->ox - wp->xoff);
|
||||
} else {
|
||||
/* Right not visible. */
|
||||
xoff = wp->xoff - ctx->ox;
|
||||
sx = wp->sx - xoff;
|
||||
}
|
||||
if (wp->yoff >= ctx->oy && wp->yoff + wp->sy <= ctx->oy + ctx->sy) {
|
||||
/* All visible. */
|
||||
yoff = wp->yoff - ctx->oy;
|
||||
sy = wp->sy;
|
||||
} else if (wp->yoff < ctx->oy &&
|
||||
wp->yoff + wp->sy > ctx->oy + ctx->sy) {
|
||||
/* Both top and bottom not visible. */
|
||||
yoff = 0;
|
||||
sy = ctx->sy;
|
||||
} else if (wp->yoff < ctx->oy) {
|
||||
/* Top not visible. */
|
||||
yoff = 0;
|
||||
sy = wp->sy - (ctx->oy - wp->yoff);
|
||||
} else {
|
||||
/* Bottom not visible. */
|
||||
yoff = wp->yoff - ctx->oy;
|
||||
sy = wp->sy - yoff;
|
||||
}
|
||||
|
||||
if (ctx->top)
|
||||
yoff += ctx->lines;
|
||||
px = sx / 2;
|
||||
py = sy / 2;
|
||||
|
||||
if (window_pane_index(wp, &idx) != 0)
|
||||
fatalx("index not found");
|
||||
len = xsnprintf(buf, sizeof buf, "%u", idx);
|
||||
|
||||
if (sx < len)
|
||||
return;
|
||||
colour = options_get_number(oo, "display-panes-colour");
|
||||
active_colour = options_get_number(oo, "display-panes-active-colour");
|
||||
|
||||
if (sx < len * 6 || sy < 5) {
|
||||
tty_cursor(tty, xoff + px - len / 2, yoff + py);
|
||||
goto draw_text;
|
||||
}
|
||||
|
||||
px -= len * 3;
|
||||
py -= 2;
|
||||
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
if (w->active == wp)
|
||||
gc.bg = active_colour;
|
||||
else
|
||||
gc.bg = colour;
|
||||
gc.flags |= GRID_FLAG_NOPALETTE;
|
||||
|
||||
tty_attributes(tty, &gc, wp);
|
||||
for (ptr = buf; *ptr != '\0'; ptr++) {
|
||||
if (*ptr < '0' || *ptr > '9')
|
||||
continue;
|
||||
idx = *ptr - '0';
|
||||
|
||||
for (j = 0; j < 5; j++) {
|
||||
for (i = px; i < px + 5; i++) {
|
||||
tty_cursor(tty, xoff + i, yoff + py + j);
|
||||
if (window_clock_table[idx][j][i - px])
|
||||
tty_putc(tty, ' ');
|
||||
}
|
||||
}
|
||||
px += 6;
|
||||
}
|
||||
|
||||
len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy);
|
||||
if (sx < len || sy < 6)
|
||||
return;
|
||||
tty_cursor(tty, xoff + sx - len, yoff);
|
||||
|
||||
draw_text:
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
if (w->active == wp)
|
||||
gc.fg = active_colour;
|
||||
else
|
||||
gc.fg = colour;
|
||||
gc.flags |= GRID_FLAG_NOPALETTE;
|
||||
|
||||
tty_attributes(tty, &gc, wp);
|
||||
tty_puts(tty, buf);
|
||||
|
||||
tty_cursor(tty, 0, 0);
|
||||
}
|
||||
|
||||
@@ -403,6 +403,51 @@ screen_write_vline(struct screen_write_ctx *ctx, u_int ny, int top, int bottom)
|
||||
screen_write_set_cursor(ctx, cx, cy);
|
||||
}
|
||||
|
||||
/* Draw a menu on screen. */
|
||||
void
|
||||
screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu, int choice)
|
||||
{
|
||||
struct screen *s = ctx->s;
|
||||
struct grid_cell gc;
|
||||
u_int cx, cy, i, j;
|
||||
const char *name;
|
||||
|
||||
cx = s->cx;
|
||||
cy = s->cy;
|
||||
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
|
||||
screen_write_box(ctx, menu->width + 4, menu->count + 2);
|
||||
screen_write_cursormove(ctx, cx + 2, cy, 0);
|
||||
format_draw(ctx, &gc, menu->width, menu->title, NULL);
|
||||
|
||||
for (i = 0; i < menu->count; i++) {
|
||||
name = menu->items[i].name;
|
||||
if (name == NULL) {
|
||||
screen_write_cursormove(ctx, cx, cy + 1 + i, 0);
|
||||
screen_write_hline(ctx, menu->width + 4, 1, 1);
|
||||
} else {
|
||||
if (choice >= 0 && i == (u_int)choice && *name != '-')
|
||||
gc.attr |= GRID_ATTR_REVERSE;
|
||||
screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0);
|
||||
for (j = 0; j < menu->width; j++)
|
||||
screen_write_putc(ctx, &gc, ' ');
|
||||
screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0);
|
||||
if (*name == '-') {
|
||||
name++;
|
||||
gc.attr |= GRID_ATTR_DIM;
|
||||
format_draw(ctx, &gc, menu->width, name, NULL);
|
||||
gc.attr &= ~GRID_ATTR_DIM;
|
||||
} else
|
||||
format_draw(ctx, &gc, menu->width, name, NULL);
|
||||
if (choice >= 0 && i == (u_int)choice)
|
||||
gc.attr &= ~GRID_ATTR_REVERSE;
|
||||
}
|
||||
}
|
||||
|
||||
screen_write_set_cursor(ctx, cx, cy);
|
||||
}
|
||||
|
||||
/* Draw a box on screen. */
|
||||
void
|
||||
screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny)
|
||||
@@ -1139,7 +1184,7 @@ screen_write_collect_clear(struct screen_write_ctx *ctx, u_int y, u_int n)
|
||||
u_int i;
|
||||
size_t size;
|
||||
|
||||
for (i = y ; i < y + n; i++) {
|
||||
for (i = y; i < y + n; i++) {
|
||||
if (TAILQ_EMPTY(&ctx->list[i].items))
|
||||
continue;
|
||||
size = 0;
|
||||
|
||||
225
server-client.c
225
server-client.c
@@ -33,7 +33,7 @@
|
||||
static void server_client_free(int, short, void *);
|
||||
static void server_client_check_focus(struct window_pane *);
|
||||
static void server_client_check_resize(struct window_pane *);
|
||||
static key_code server_client_check_mouse(struct client *);
|
||||
static key_code server_client_check_mouse(struct client *, struct key_event *);
|
||||
static void server_client_repeat_timer(int, short, void *);
|
||||
static void server_client_click_timer(int, short, void *);
|
||||
static void server_client_check_exit(struct client *);
|
||||
@@ -41,8 +41,7 @@ static void server_client_check_redraw(struct client *);
|
||||
static void server_client_set_title(struct client *);
|
||||
static void server_client_reset_state(struct client *);
|
||||
static int server_client_assume_paste(struct session *);
|
||||
static void server_client_clear_identify(struct client *,
|
||||
struct window_pane *);
|
||||
static void server_client_clear_overlay(struct client *);
|
||||
|
||||
static void server_client_dispatch(struct imsg *, void *);
|
||||
static void server_client_dispatch_command(struct client *, struct imsg *);
|
||||
@@ -64,44 +63,56 @@ server_client_how_many(void)
|
||||
return (n);
|
||||
}
|
||||
|
||||
/* Identify mode callback. */
|
||||
/* Overlay timer callback. */
|
||||
static void
|
||||
server_client_callback_identify(__unused int fd, __unused short events,
|
||||
void *data)
|
||||
server_client_overlay_timer(__unused int fd, __unused short events, void *data)
|
||||
{
|
||||
server_client_clear_identify(data, NULL);
|
||||
server_client_clear_overlay(data);
|
||||
}
|
||||
|
||||
/* Set identify mode on client. */
|
||||
/* Set an overlay on client. */
|
||||
void
|
||||
server_client_set_identify(struct client *c, u_int delay)
|
||||
server_client_set_overlay(struct client *c, u_int delay, overlay_draw_cb drawcb,
|
||||
overlay_key_cb keycb, overlay_free_cb freecb, void *data)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
if (c->overlay_draw != NULL)
|
||||
server_client_clear_overlay(c);
|
||||
|
||||
tv.tv_sec = delay / 1000;
|
||||
tv.tv_usec = (delay % 1000) * 1000L;
|
||||
|
||||
if (event_initialized(&c->identify_timer))
|
||||
evtimer_del(&c->identify_timer);
|
||||
evtimer_set(&c->identify_timer, server_client_callback_identify, c);
|
||||
if (event_initialized(&c->overlay_timer))
|
||||
evtimer_del(&c->overlay_timer);
|
||||
evtimer_set(&c->overlay_timer, server_client_overlay_timer, c);
|
||||
if (delay != 0)
|
||||
evtimer_add(&c->identify_timer, &tv);
|
||||
evtimer_add(&c->overlay_timer, &tv);
|
||||
|
||||
c->overlay_draw = drawcb;
|
||||
c->overlay_key = keycb;
|
||||
c->overlay_free = freecb;
|
||||
c->overlay_data = data;
|
||||
|
||||
c->flags |= CLIENT_IDENTIFY;
|
||||
c->tty.flags |= (TTY_FREEZE|TTY_NOCURSOR);
|
||||
server_redraw_client(c);
|
||||
}
|
||||
|
||||
/* Clear identify mode on client. */
|
||||
/* Clear overlay mode on client. */
|
||||
static void
|
||||
server_client_clear_identify(struct client *c, struct window_pane *wp)
|
||||
server_client_clear_overlay(struct client *c)
|
||||
{
|
||||
if (~c->flags & CLIENT_IDENTIFY)
|
||||
if (c->overlay_draw == NULL)
|
||||
return;
|
||||
c->flags &= ~CLIENT_IDENTIFY;
|
||||
|
||||
if (c->identify_callback != NULL)
|
||||
c->identify_callback(c, wp);
|
||||
if (event_initialized(&c->overlay_timer))
|
||||
evtimer_del(&c->overlay_timer);
|
||||
|
||||
if (c->overlay_free != NULL)
|
||||
c->overlay_free(c);
|
||||
|
||||
c->overlay_draw = NULL;
|
||||
c->overlay_key = NULL;
|
||||
|
||||
c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR);
|
||||
server_redraw_client(c);
|
||||
@@ -255,7 +266,7 @@ server_client_lost(struct client *c)
|
||||
|
||||
c->flags |= CLIENT_DEAD;
|
||||
|
||||
server_client_clear_identify(c, NULL);
|
||||
server_client_clear_overlay(c);
|
||||
status_prompt_clear(c);
|
||||
status_message_clear(c);
|
||||
|
||||
@@ -289,9 +300,6 @@ server_client_lost(struct client *c)
|
||||
|
||||
key_bindings_unref_table(c->keytable);
|
||||
|
||||
if (event_initialized(&c->identify_timer))
|
||||
evtimer_del(&c->identify_timer);
|
||||
|
||||
free(c->message_string);
|
||||
if (event_initialized(&c->message_timer))
|
||||
evtimer_del(&c->message_timer);
|
||||
@@ -405,10 +413,10 @@ server_client_exec(struct client *c, const char *cmd)
|
||||
|
||||
/* Check for mouse keys. */
|
||||
static key_code
|
||||
server_client_check_mouse(struct client *c)
|
||||
server_client_check_mouse(struct client *c, struct key_event *event)
|
||||
{
|
||||
struct mouse_event *m = &event->m;
|
||||
struct session *s = c->session;
|
||||
struct mouse_event *m = &c->tty.mouse;
|
||||
struct winlink *wl;
|
||||
struct window_pane *wp;
|
||||
u_int x, y, b, sx, sy, px, py;
|
||||
@@ -416,11 +424,21 @@ server_client_check_mouse(struct client *c)
|
||||
key_code key;
|
||||
struct timeval tv;
|
||||
struct style_range *sr;
|
||||
enum { NOTYPE, MOVE, DOWN, UP, DRAG, WHEEL, DOUBLE, TRIPLE } type;
|
||||
enum { NOWHERE, PANE, STATUS, STATUS_LEFT, STATUS_RIGHT, STATUS_DEFAULT, BORDER } where;
|
||||
|
||||
type = NOTYPE;
|
||||
where = NOWHERE;
|
||||
enum { NOTYPE,
|
||||
MOVE,
|
||||
DOWN,
|
||||
UP,
|
||||
DRAG,
|
||||
WHEEL,
|
||||
DOUBLE,
|
||||
TRIPLE } type = NOTYPE;
|
||||
enum { NOWHERE,
|
||||
PANE,
|
||||
STATUS,
|
||||
STATUS_LEFT,
|
||||
STATUS_RIGHT,
|
||||
STATUS_DEFAULT,
|
||||
BORDER } where = NOWHERE;
|
||||
|
||||
log_debug("%s mouse %02x at %u,%u (last %u,%u) (%d)", c->name, m->b,
|
||||
m->x, m->y, m->lx, m->ly, c->tty.mouse_drag_flag);
|
||||
@@ -440,9 +458,11 @@ server_client_check_mouse(struct client *c)
|
||||
type = DRAG;
|
||||
if (c->tty.mouse_drag_flag) {
|
||||
x = m->x, y = m->y, b = m->b;
|
||||
if (x == m->lx && y == m->ly)
|
||||
return (KEYC_UNKNOWN);
|
||||
log_debug("drag update at %u,%u", x, y);
|
||||
} else {
|
||||
x = m->lx - m->ox, y = m->ly - m->oy, b = m->lb;
|
||||
x = m->lx, y = m->ly, b = m->lb;
|
||||
log_debug("drag start at %u,%u", x, y);
|
||||
}
|
||||
} else if (MOUSE_WHEEL(m->b)) {
|
||||
@@ -547,8 +567,6 @@ have_event:
|
||||
return (KEYC_UNKNOWN);
|
||||
px = px + m->ox;
|
||||
py = py + m->oy;
|
||||
m->x = x + m->ox;
|
||||
m->y = y + m->oy;
|
||||
|
||||
/* Try the pane borders if not zoomed. */
|
||||
if (~s->curw->window->flags & WINDOW_ZOOMED) {
|
||||
@@ -974,14 +992,19 @@ server_client_assume_paste(struct session *s)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Handle data key input from client. */
|
||||
void
|
||||
server_client_handle_key(struct client *c, key_code key)
|
||||
/*
|
||||
* Handle data key input from client. This owns and can modify the key event it
|
||||
* is given and is responsible for freeing it.
|
||||
*/
|
||||
static enum cmd_retval
|
||||
server_client_key_callback(struct cmdq_item *item, void *data)
|
||||
{
|
||||
struct mouse_event *m = &c->tty.mouse;
|
||||
struct client *c = item->client;
|
||||
struct key_event *event = data;
|
||||
key_code key = event->key;
|
||||
struct mouse_event *m = &event->m;
|
||||
struct session *s = c->session;
|
||||
struct winlink *wl;
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
struct window_mode_entry *wme;
|
||||
struct timeval tv;
|
||||
@@ -993,45 +1016,32 @@ server_client_handle_key(struct client *c, key_code key)
|
||||
|
||||
/* Check the client is good to accept input. */
|
||||
if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
|
||||
return;
|
||||
goto out;
|
||||
wl = s->curw;
|
||||
w = wl->window;
|
||||
|
||||
/* Update the activity timer. */
|
||||
if (gettimeofday(&c->activity_time, NULL) != 0)
|
||||
fatal("gettimeofday failed");
|
||||
session_update_activity(s, &c->activity_time);
|
||||
|
||||
/* Number keys jump to pane in identify mode. */
|
||||
if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
|
||||
if (c->flags & CLIENT_READONLY)
|
||||
return;
|
||||
window_unzoom(w);
|
||||
wp = window_pane_at_index(w, key - '0');
|
||||
server_client_clear_identify(c, wp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle status line. */
|
||||
if (!(c->flags & CLIENT_READONLY)) {
|
||||
if (~c->flags & CLIENT_READONLY)
|
||||
status_message_clear(c);
|
||||
server_client_clear_identify(c, NULL);
|
||||
}
|
||||
if (c->prompt_string != NULL) {
|
||||
if (c->flags & CLIENT_READONLY)
|
||||
return;
|
||||
goto out;
|
||||
if (status_prompt_key(c, key) == 0)
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check for mouse keys. */
|
||||
m->valid = 0;
|
||||
if (key == KEYC_MOUSE) {
|
||||
if (c->flags & CLIENT_READONLY)
|
||||
return;
|
||||
key = server_client_check_mouse(c);
|
||||
goto out;
|
||||
key = server_client_check_mouse(c, event);
|
||||
if (key == KEYC_UNKNOWN)
|
||||
return;
|
||||
goto out;
|
||||
|
||||
m->valid = 1;
|
||||
m->key = key;
|
||||
@@ -1042,10 +1052,9 @@ server_client_handle_key(struct client *c, key_code key)
|
||||
*/
|
||||
if (key == KEYC_DRAGGING) {
|
||||
c->tty.mouse_drag_update(c, m);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
} else
|
||||
m->valid = 0;
|
||||
}
|
||||
|
||||
/* Find affected pane. */
|
||||
if (!KEYC_IS_MOUSE(key) || cmd_find_from_mouse(&fs, m, 0) != 0)
|
||||
@@ -1084,7 +1093,7 @@ table_changed:
|
||||
strcmp(table->name, "prefix") != 0) {
|
||||
server_client_set_key_table(c, "prefix");
|
||||
server_status_client(c);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
flags = c->flags;
|
||||
|
||||
@@ -1142,9 +1151,9 @@ try_again:
|
||||
server_status_client(c);
|
||||
|
||||
/* Execute the key binding. */
|
||||
key_bindings_dispatch(bd, NULL, c, m, &fs);
|
||||
key_bindings_dispatch(bd, item, c, m, &fs);
|
||||
key_bindings_unref_table(table);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1179,14 +1188,48 @@ try_again:
|
||||
if (first != table && (~flags & CLIENT_REPEAT)) {
|
||||
server_client_set_key_table(c, NULL);
|
||||
server_status_client(c);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
forward_key:
|
||||
if (c->flags & CLIENT_READONLY)
|
||||
return;
|
||||
goto out;
|
||||
if (wp != NULL)
|
||||
window_pane_key(wp, c, s, wl, key, m);
|
||||
|
||||
out:
|
||||
free(event);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
/* Handle a key event. */
|
||||
int
|
||||
server_client_handle_key(struct client *c, struct key_event *event)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct cmdq_item *item;
|
||||
|
||||
/* Check the client is good to accept input. */
|
||||
if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Key presses in overlay mode are a special case. The queue might be
|
||||
* blocked so they need to be processed immediately rather than queued.
|
||||
*/
|
||||
if ((~c->flags & CLIENT_READONLY) && c->overlay_key != NULL) {
|
||||
if (c->overlay_key(c, event) != 0)
|
||||
server_client_clear_overlay(c);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the key to the queue so it happens after any commands queued by
|
||||
* previous keys.
|
||||
*/
|
||||
item = cmdq_get_callback(server_client_key_callback, event);
|
||||
cmdq_append(c, item);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Client functions that need to happen every loop. */
|
||||
@@ -1379,6 +1422,7 @@ focused:
|
||||
if (wp->base.mode & MODE_FOCUSON)
|
||||
bufferevent_write(wp->event, "\033[I", 3);
|
||||
notify_pane("pane-focus-in", wp);
|
||||
session_update_activity(c->session, NULL);
|
||||
}
|
||||
wp->flags |= PANE_FOCUSED;
|
||||
}
|
||||
@@ -1404,6 +1448,8 @@ server_client_reset_state(struct client *c)
|
||||
|
||||
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
|
||||
return;
|
||||
if (c->overlay_draw != NULL)
|
||||
return;
|
||||
mode = s->mode;
|
||||
|
||||
tty_region_off(&c->tty);
|
||||
@@ -1514,10 +1560,11 @@ server_client_check_redraw(struct client *c)
|
||||
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
|
||||
return;
|
||||
if (c->flags & CLIENT_ALLREDRAWFLAGS) {
|
||||
log_debug("%s: redraw%s%s%s", c->name,
|
||||
log_debug("%s: redraw%s%s%s%s", c->name,
|
||||
(c->flags & CLIENT_REDRAWWINDOW) ? " window" : "",
|
||||
(c->flags & CLIENT_REDRAWSTATUS) ? " status" : "",
|
||||
(c->flags & CLIENT_REDRAWBORDERS) ? " borders" : "");
|
||||
(c->flags & CLIENT_REDRAWBORDERS) ? " borders" : "",
|
||||
(c->flags & CLIENT_REDRAWOVERLAY) ? " overlay" : "");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1665,8 +1712,7 @@ server_client_dispatch(struct imsg *imsg, void *arg)
|
||||
evbuffer_add(c->stdin_data, stdindata.data,
|
||||
stdindata.size);
|
||||
}
|
||||
c->stdin_callback(c, c->stdin_closed,
|
||||
c->stdin_callback_data);
|
||||
c->stdin_callback(c, c->stdin_closed, c->stdin_callback_data);
|
||||
break;
|
||||
case MSG_RESIZE:
|
||||
if (datalen != 0)
|
||||
@@ -1674,6 +1720,7 @@ server_client_dispatch(struct imsg *imsg, void *arg)
|
||||
|
||||
if (c->flags & CLIENT_CONTROL)
|
||||
break;
|
||||
server_client_clear_overlay(c);
|
||||
tty_resize(&c->tty);
|
||||
recalculate_sizes();
|
||||
server_redraw_client(c);
|
||||
@@ -1731,18 +1778,6 @@ server_client_command_done(struct cmdq_item *item, __unused void *data)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
/* Show an error message. */
|
||||
static enum cmd_retval
|
||||
server_client_command_error(struct cmdq_item *item, void *data)
|
||||
{
|
||||
char *error = data;
|
||||
|
||||
cmdq_error(item, "%s", error);
|
||||
free(error);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
/* Handle command message. */
|
||||
static void
|
||||
server_client_dispatch_command(struct client *c, struct imsg *imsg)
|
||||
@@ -1750,9 +1785,9 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg)
|
||||
struct msg_command_data data;
|
||||
char *buf;
|
||||
size_t len;
|
||||
struct cmd_list *cmdlist = NULL;
|
||||
int argc;
|
||||
char **argv, *cause;
|
||||
struct cmd_parse_result *pr;
|
||||
|
||||
if (c->flags & CLIENT_EXIT)
|
||||
return;
|
||||
@@ -1778,22 +1813,30 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg)
|
||||
*argv = xstrdup("new-session");
|
||||
}
|
||||
|
||||
if ((cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause)) == NULL) {
|
||||
cmd_free_argv(argc, argv);
|
||||
pr = cmd_parse_from_arguments(argc, argv, NULL);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_EMPTY:
|
||||
cause = xstrdup("empty command");
|
||||
goto error;
|
||||
case CMD_PARSE_ERROR:
|
||||
cause = pr->error;
|
||||
goto error;
|
||||
case CMD_PARSE_SUCCESS:
|
||||
break;
|
||||
}
|
||||
cmd_free_argv(argc, argv);
|
||||
|
||||
cmdq_append(c, cmdq_get_command(cmdlist, NULL, NULL, 0));
|
||||
cmdq_append(c, cmdq_get_command(pr->cmdlist, NULL, NULL, 0));
|
||||
cmdq_append(c, cmdq_get_callback(server_client_command_done, NULL));
|
||||
cmd_list_free(cmdlist);
|
||||
|
||||
cmd_list_free(pr->cmdlist);
|
||||
return;
|
||||
|
||||
error:
|
||||
cmdq_append(c, cmdq_get_callback(server_client_command_error, cause));
|
||||
cmd_free_argv(argc, argv);
|
||||
|
||||
if (cmdlist != NULL)
|
||||
cmd_list_free(cmdlist);
|
||||
cmdq_append(c, cmdq_get_error(cause));
|
||||
free(cause);
|
||||
|
||||
c->flags |= CLIENT_EXIT;
|
||||
}
|
||||
|
||||
@@ -369,7 +369,7 @@ server_destroy_session_group(struct session *s)
|
||||
else {
|
||||
TAILQ_FOREACH_SAFE(s, &sg->sessions, gentry, s1) {
|
||||
server_destroy_session(s);
|
||||
session_destroy(s, __func__);
|
||||
session_destroy(s, 1, __func__);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -436,11 +436,10 @@ server_check_unattached(void)
|
||||
if (s->attached != 0)
|
||||
continue;
|
||||
if (options_get_number (s->options, "destroy-unattached"))
|
||||
session_destroy(s, __func__);
|
||||
session_destroy(s, 1, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set stdin callback. */
|
||||
int
|
||||
server_set_stdin_callback(struct client *c, void (*cb)(struct client *, int,
|
||||
void *), void *cb_data, char **cause)
|
||||
@@ -454,7 +453,7 @@ server_set_stdin_callback(struct client *c, void (*cb)(struct client *, int,
|
||||
return (-1);
|
||||
}
|
||||
if (c->stdin_callback != NULL) {
|
||||
*cause = xstrdup("stdin in use");
|
||||
*cause = xstrdup("stdin is in use");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user