mirror of
https://github.com/tmux/tmux.git
synced 2026-03-11 11:05:46 +00:00
Compare commits
237 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2365b09d6a | ||
|
|
dcef4f8084 | ||
|
|
030d284006 | ||
|
|
1b037f74f4 | ||
|
|
750e6ad542 | ||
|
|
5f72510edf | ||
|
|
5d86284a1a | ||
|
|
3cd9ea1789 | ||
|
|
3585feca54 | ||
|
|
a373235106 | ||
|
|
9f3399da00 | ||
|
|
c05a47ad0d | ||
|
|
a932742a8a | ||
|
|
bb728b89a7 | ||
|
|
64d16cf2d6 | ||
|
|
b8eae3902b | ||
|
|
d1bdc9a161 | ||
|
|
cd92f44686 | ||
|
|
206ae727f9 | ||
|
|
5fcd6711e4 | ||
|
|
d227a2e661 | ||
|
|
0b8ce56d73 | ||
|
|
095ffe9cd1 | ||
|
|
1a4d78c7af | ||
|
|
286fef9b4d | ||
|
|
1891f1ce99 | ||
|
|
3ab25ac5b5 | ||
|
|
3a4f765a51 | ||
|
|
d0adcbc98a | ||
|
|
e75187310d | ||
|
|
7a0468c95c | ||
|
|
1b0d235e3a | ||
|
|
36e537bcef | ||
|
|
fd51bf61c9 | ||
|
|
fe4f760eba | ||
|
|
3a4b82d27a | ||
|
|
ccdafdabca | ||
|
|
39e277be3c | ||
|
|
1650155589 | ||
|
|
42327f06df | ||
|
|
1585b1e928 | ||
|
|
9ab191b053 | ||
|
|
13032d1d88 | ||
|
|
64387d18dd | ||
|
|
25bf0faf21 | ||
|
|
112fc58e6e | ||
|
|
ba68bed10e | ||
|
|
30e8ed393e | ||
|
|
a6fc49ae08 | ||
|
|
94c2adf499 | ||
|
|
9c541e42f0 | ||
|
|
96601ce9fe | ||
|
|
1cec111af3 | ||
|
|
ae7a7be819 | ||
|
|
58684ea998 | ||
|
|
914f8584ef | ||
|
|
2287ec7b3e | ||
|
|
8f84217023 | ||
|
|
83447580b1 | ||
|
|
1cd9ff4460 | ||
|
|
cd079e8fbf | ||
|
|
8703e9f2f9 | ||
|
|
2da0730f78 | ||
|
|
bdbd4e28c2 | ||
|
|
1276ea3653 | ||
|
|
f79b467dce | ||
|
|
d4b58c71a2 | ||
|
|
5fb4f8c1fa | ||
|
|
5a0ecc5931 | ||
|
|
e7a4b68f73 | ||
|
|
a7e5092bd4 | ||
|
|
b73ac822fb | ||
|
|
0ad532d9c2 | ||
|
|
b0ad6e94bb | ||
|
|
b2ae7c6261 | ||
|
|
6c9269baa7 | ||
|
|
45784bd5d6 | ||
|
|
b5349ab5d9 | ||
|
|
7874b00d4c | ||
|
|
6139fac10d | ||
|
|
d0d98d4ec0 | ||
|
|
29f04400b5 | ||
|
|
5126037ea0 | ||
|
|
d7a3fc3df4 | ||
|
|
59dc08a7a0 | ||
|
|
fe3621cbc5 | ||
|
|
89c07dedd9 | ||
|
|
28a0b6fd20 | ||
|
|
f54482a461 | ||
|
|
afcc29a51d | ||
|
|
33df467d40 | ||
|
|
510b43569f | ||
|
|
a8b22d3673 | ||
|
|
19923625d4 | ||
|
|
3b4d26d16b | ||
|
|
01052ca38e | ||
|
|
ee44a8dca9 | ||
|
|
89acd757d0 | ||
|
|
56040be346 | ||
|
|
e6bb3d6942 | ||
|
|
aba555509e | ||
|
|
c50c4ec834 | ||
|
|
9858071dd0 | ||
|
|
b0169d9b84 | ||
|
|
e34c6e2305 | ||
|
|
761bd3c9e3 | ||
|
|
5e9429e2d6 | ||
|
|
4387db506f | ||
|
|
d7bae0edce | ||
|
|
482bd7b65e | ||
|
|
f42364b4b5 | ||
|
|
5be8175b0b | ||
|
|
5576fe42b2 | ||
|
|
1944747759 | ||
|
|
28c4c86589 | ||
|
|
7ed9b0f8fb | ||
|
|
11497af4dd | ||
|
|
b0878774e0 | ||
|
|
e71f0842ce | ||
|
|
9b47a48393 | ||
|
|
0482983d53 | ||
|
|
2b512dc49d | ||
|
|
ae45c2ea45 | ||
|
|
11f81e8134 | ||
|
|
ad6a528f61 | ||
|
|
46f27eab22 | ||
|
|
e4703bacb5 | ||
|
|
e4573de97b | ||
|
|
63e76b555d | ||
|
|
13e7f060b1 | ||
|
|
fa34c76275 | ||
|
|
985cd3a4de | ||
|
|
03c1c1cd9f | ||
|
|
0e70c8801c | ||
|
|
617386370b | ||
|
|
bf1e237410 | ||
|
|
8d3b726396 | ||
|
|
47b335dee7 | ||
|
|
6c76724201 | ||
|
|
29434cb043 | ||
|
|
b7454e37cb | ||
|
|
e2a5e02022 | ||
|
|
cac532c3d1 | ||
|
|
e186450788 | ||
|
|
3e8092709c | ||
|
|
1b77ae2684 | ||
|
|
60134cebda | ||
|
|
f34861bad4 | ||
|
|
6503207185 | ||
|
|
3bba401609 | ||
|
|
31657820bc | ||
|
|
be3643fba0 | ||
|
|
f62d3d22bb | ||
|
|
67dc249d0e | ||
|
|
0778ef230b | ||
|
|
bebfd7c2c8 | ||
|
|
348c3e69de | ||
|
|
0d6a64070c | ||
|
|
bb4d770e45 | ||
|
|
e55a59eebc | ||
|
|
11cd05db27 | ||
|
|
6c6255f2d7 | ||
|
|
227e458ebb | ||
|
|
89eb95265a | ||
|
|
d98efa5378 | ||
|
|
a9c6976268 | ||
|
|
d9c99b83c7 | ||
|
|
d27956f160 | ||
|
|
e334deb872 | ||
|
|
e50dc0745f | ||
|
|
f11f71752a | ||
|
|
9e7a5fa5ef | ||
|
|
9c01a3d0db | ||
|
|
278effd7ea | ||
|
|
59c13133de | ||
|
|
41afc38dcc | ||
|
|
0beb31c261 | ||
|
|
6694a01861 | ||
|
|
9900e28ba8 | ||
|
|
fc69b9ccb7 | ||
|
|
d3dd6709bc | ||
|
|
3cded44623 | ||
|
|
50cad52ae6 | ||
|
|
701b5bdf61 | ||
|
|
4e120c00f7 | ||
|
|
7d4588f470 | ||
|
|
893be14cf8 | ||
|
|
342a47bc77 | ||
|
|
18ed37622e | ||
|
|
ec56ec7920 | ||
|
|
0c5a964e63 | ||
|
|
c4c542efb9 | ||
|
|
2bc150d16d | ||
|
|
7163907ab6 | ||
|
|
02fc1fe0da | ||
|
|
8e67b07489 | ||
|
|
0ed80637e7 | ||
|
|
b03418fc6b | ||
|
|
c0f03afbac | ||
|
|
0646b3caf2 | ||
|
|
b2e752b384 | ||
|
|
08632b4f0a | ||
|
|
10b73b7a11 | ||
|
|
cd0f22b96e | ||
|
|
610056abbe | ||
|
|
3743238a86 | ||
|
|
531db321e3 | ||
|
|
642f549e4d | ||
|
|
0fc65537a3 | ||
|
|
091db41bc9 | ||
|
|
67300e9524 | ||
|
|
f2a4ef5260 | ||
|
|
7dc1720522 | ||
|
|
07dcf8610f | ||
|
|
2d74ce1d3a | ||
|
|
5879e2a32b | ||
|
|
1392fba63d | ||
|
|
1c6ab725f5 | ||
|
|
4012917302 | ||
|
|
dd7abd9b4c | ||
|
|
51c776fe93 | ||
|
|
9382e546df | ||
|
|
659d15786a | ||
|
|
2307b91ecb | ||
|
|
a2c87eb899 | ||
|
|
33a90efc93 | ||
|
|
009d8d2ea7 | ||
|
|
aa8f9018ea | ||
|
|
4de04fac2c | ||
|
|
593bcbdd49 | ||
|
|
9f5b9ba0d6 | ||
|
|
b1a3090877 | ||
|
|
4271320bb7 | ||
|
|
51eab54102 | ||
|
|
51c135ed73 | ||
|
|
f6d36e60cf | ||
|
|
38bc7e87c5 |
89
CHANGES
89
CHANGES
@@ -1,3 +1,90 @@
|
||||
CHANGES FROM 1.3 TO 1.4, 27 December 2010
|
||||
|
||||
* Window bell reporting fixed.
|
||||
* Show which pane is active in the list-panes output.
|
||||
* Backoff reworked.
|
||||
* Prevent the server from dying when switching into copy mode when already
|
||||
in a different mode.
|
||||
* Reset running jobs when the status line is enabled or disabled.
|
||||
* Simplify xterm modifier detection.
|
||||
* Avoid crashing in copy mode if the screen size is too small for the
|
||||
indicator.
|
||||
* Flags -n and -p added to switch-client.
|
||||
* Use UTF-8 line drawing characters on UTF-8 terminals, thus fixing some
|
||||
terminals (eg putty) which disable the vt100 ACS mode switching sequences
|
||||
in UTF-8 mode. On terminals without ACS, use ASCII equivalents.
|
||||
* New server option exit-unattached added.
|
||||
* New session option destroy-unattached added.
|
||||
* Fall back on normal session choice method if $TMUX exists but is invalid
|
||||
rather than rejecting.
|
||||
* Mark repeating keys with "(repeat)" in the key list.
|
||||
* When removing a pane, don't change the active pane unless the active pane
|
||||
is actually the one being removed.
|
||||
* New command last-pane added.
|
||||
* AIX fixes.
|
||||
* Flag -a added to unbind-key.
|
||||
* Add XAUTHORITY to update-environment.
|
||||
* More info regarding window and pane flags is now shown in list-*.
|
||||
* If VISUAL or EDITOR contains "vi" configure mode-keys and status-key to vi.
|
||||
* New window option monitor-silence and session option visual-silence added.
|
||||
* In the built-in layouts distribute the panes more evenly.
|
||||
* Set the default value of main-pane-width to 80 instead of 81.
|
||||
* Command-line flag -V added.
|
||||
* Instead of keeping a per-client prompt history make it global.
|
||||
* Fix rectangle copy to behave like emacs (the cursor is not part of the
|
||||
selection on the right edge but on the left it is).
|
||||
* Flag -l added to switch-client.
|
||||
* Retrieve environment variables from the global environment rather than
|
||||
getenv(3), thus allowing them to be updated during the configuration file.
|
||||
* New window options other-pane-{height,width} added.
|
||||
* More minor bugs fixed and manpage improvements.
|
||||
|
||||
CHANGES FROM 1.2 TO 1.3, 18 July 2010
|
||||
|
||||
* New input parser.
|
||||
* Flags to move through panes -UDLR added to select-pane.
|
||||
* Commands up-pane, and down-pane removed, since equivalent behaviour is now
|
||||
available through the target flag (-t:+ and -t:-).
|
||||
* Jump-forward/backward in copy move (based on vi's F, and f commands).
|
||||
* Make paste-buffer accept a pane as a target.
|
||||
* Flag -a added to new-window to insert a window after an existing one, moving
|
||||
windows up if necessary.
|
||||
* Merge more mode into copy mode.
|
||||
* Run job commands explicitly in the global environment (which can be modified
|
||||
with setenv -g), rather than with the environment tmux started with.
|
||||
* Use the machine's hostname as the default title, instead of an empty string.
|
||||
* Prevent double free if the window option remain-on-exit is set.
|
||||
* Key string conversions rewritten.
|
||||
* Mark zombie windows as dead in the choose-window list.
|
||||
* Tiled layout added.
|
||||
* Signal handling reworked.
|
||||
* Reset SIGCHLD after fork to fix problems with some shells.
|
||||
* Select-prompt command removed. Therefore, bound ' to command-prompt -p index
|
||||
"select-window -t:%%" by default.
|
||||
* Catch SIGHUP and terminate if running as a client, thus avoiding clients from
|
||||
being left hanging around when, for instance, a SSH session is disconnected.
|
||||
* Solaris 9 fixes (such as adding compat {get,set}env(3) code).
|
||||
* Accept none instead of default for attributes.
|
||||
* Window options window-status-alert-{alert,bg,fg} added.
|
||||
* Flag -s added to the paste-buffer command to specify a custom separator.
|
||||
* Allow dragging to make a selection in copy mode if the mode-mouse option is
|
||||
set.
|
||||
* Support the mouse scroll wheel.
|
||||
* Make pipe-pane accept special character sequences (eg #I).
|
||||
* Fix problems with window sizing when starting tmux from .xinitrc.
|
||||
* Give tmux sockets (but not the containing folder) group permissions.
|
||||
* Extend the target flags (ie -t) to accept an offset (for example -t:+2), and
|
||||
make it wrap windows, and panes.
|
||||
* New command choose-buffer added.
|
||||
* New server option detach-on-destroy to set what happens to a client when the
|
||||
session it is attached to is destroyed. If on (default), the client is
|
||||
detached. Otherwise, the client is switched to the most recently active of
|
||||
the remaining sessions.
|
||||
* The commands load-buffer, and save-buffer now accept a dash (-) as the file
|
||||
to read from stdin, or write to stdout.
|
||||
* Custom layouts added.
|
||||
* Additional code reduction, bug fixes, and manpage enhancements.
|
||||
|
||||
CHANGES FROM 1.1 TO 1.2, 10 March 2010
|
||||
|
||||
* Switch to libevent.
|
||||
@@ -1467,7 +1554,7 @@ The list of older changes is below.
|
||||
(including mutt, emacs). No status bar yet and no key remapping or other
|
||||
customisation.
|
||||
|
||||
$Id: CHANGES,v 1.302 2010-03-10 15:18:11 tcunha Exp $
|
||||
$Id: CHANGES,v 1.304 2010-12-27 21:37:42 tcunha Exp $
|
||||
|
||||
LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr
|
||||
LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms
|
||||
|
||||
173
FAQ
173
FAQ
@@ -12,29 +12,99 @@ tmux frequently asked questions
|
||||
* and derivatives. *
|
||||
******************************************************************************
|
||||
|
||||
* How is tmux different from GNU screen? What else does it offer?
|
||||
* How is tmux different from GNU screen?
|
||||
|
||||
tmux offers several advantages over screen:
|
||||
tmux and GNU screen have many similarities. Some of the main differences I am
|
||||
aware of are (bearing in mind I haven't used screen for a few years now):
|
||||
|
||||
- a clearly-defined client-server model: windows are independent entities which
|
||||
may be attached simultaneously to multiple sessions and viewed from multiple
|
||||
clients (terminals), as well as moved freely between sessions within the same
|
||||
tmux server;
|
||||
- a consistent, well-documented command interface, with the same syntax
|
||||
whether used interactively, as a key binding, or from the shell;
|
||||
- easily scriptable from the shell;
|
||||
- multiple paste buffers;
|
||||
- choice of vi or emacs key layouts;
|
||||
- an option to limit the window size;
|
||||
- a more usable status line syntax, with the ability to display the first line
|
||||
of output of a specific command;
|
||||
- a cleaner, modern, easily extended, BSD-licensed codebase.
|
||||
- tmux uses a client-server model. Each server has single Unix domain socket in
|
||||
/tmp and within one server there are multiple sessions which may be attached
|
||||
to multiple clients (terminals).
|
||||
|
||||
There are still a few features screen includes that tmux omits:
|
||||
This has advantages, notably: windows may be linked simultaneously to
|
||||
multiple sessions; windows may be moved freely between sessions; and a client
|
||||
may be switched between sessions easily (C-b D). There is one major
|
||||
disadvantage: if the server crashes, game over, all sessions die. In
|
||||
practice, however, tmux is quite stable and gets more so as people report any
|
||||
bugs they hit :-).
|
||||
|
||||
- builtin serial and telnet support; this is bloat and is unlikely to be added
|
||||
to tmux;
|
||||
- wider platform support, for example IRIX and HP-UX, and for odd terminals.
|
||||
This model is different from screen, where typically each new screen instance
|
||||
is independent. tmux supports the same behaviour by using multiple servers
|
||||
with the -L option but it is not typically recommended.
|
||||
|
||||
- Different command interfaces. One of the goals of tmux is that the shell
|
||||
should be easily usable as a scripting language - almost all tmux commands
|
||||
can be used from the shell and behave identically whether used from the
|
||||
shell, from a key binding or from the command prompt. Personally I also find
|
||||
tmux's command interface much more consistent and clearer, but this is
|
||||
subjective.
|
||||
|
||||
- tmux calls window names (what you see in the status line) "names", screen
|
||||
calls them "titles".
|
||||
|
||||
- tmux has a multiple paste buffers. Not a major one but comes in handy quite a
|
||||
lot.
|
||||
|
||||
- tmux supports automatically renaming windows to the running application
|
||||
without gross hacks using escape sequences. Its even on by default.
|
||||
|
||||
- tmux has a choice of vi or emacs key layouts. Again, not major, but I use
|
||||
emacs so if tmux did support only one key set it would be emacs and then all
|
||||
the vi users would get humpy. Key bindings may be completely reconfigured in
|
||||
any case.
|
||||
|
||||
- tmux has an option to limit the window size.
|
||||
|
||||
- tmux has search in windows (C-b f).
|
||||
|
||||
- The window split (pane) model is different. tmux has two objects, windows and
|
||||
panes; screen has just windows. This difference has several implications:
|
||||
|
||||
* In screen you can have a window appear in several layouts, in tmux a pane
|
||||
can only be in one window (fixing this is a big todo item but quite
|
||||
invasive).
|
||||
|
||||
* tmux layouts are immutable and do not get changed unless you modify them.
|
||||
|
||||
* In tmux, all panes are closed when you kill a window.
|
||||
|
||||
* tmux panes do not have individual names, titles and so on.
|
||||
|
||||
I think tmux's model is much easier to manage and navigate within a window,
|
||||
but breaking panes off from and joining them to windows is more clumsy.
|
||||
|
||||
tmux also has support for preset pane layouts.
|
||||
|
||||
- tmux's status line syntax is more readable and easier to use. I think it'd be
|
||||
hard for anyone to argue with this. tmux doesn't support running a command
|
||||
constantly and always using the last line of its output, commands must be run
|
||||
again each time.
|
||||
|
||||
- tmux has modern, easily extended code. Again hard to argue screen is better
|
||||
if you have looked at the code.
|
||||
|
||||
- tmux depends on libevent. I don't see this as a disadvantage: libevent is
|
||||
small and portable, and on modern systems with current package management
|
||||
systems dependencies are not an issue. libevent brings advantages in code
|
||||
simplicity and performance.
|
||||
|
||||
- screen allows the window to be bigger than the terminal and can pan around
|
||||
it. tmux limits the size to the largest attached client. This is a big todo
|
||||
item for tmux but it is not trivial.
|
||||
|
||||
- screen has builtin serial and telnet support; this is bloat and is unlikely
|
||||
to be added to tmux.
|
||||
|
||||
- screen has support for updating utmp. Nobody has really come up with a clean,
|
||||
portable way to do this without making tmux setuid or setgid yet.
|
||||
|
||||
- Environment handling is different.
|
||||
|
||||
- tmux tends to be more demanding on the terminal so tends to show up terminal
|
||||
and application bugs which screen does not.
|
||||
|
||||
- screen has wider platform support, for example IRIX and HP-UX, and for odd
|
||||
terminals.
|
||||
|
||||
* I found a bug! What do I do?
|
||||
|
||||
@@ -167,6 +237,8 @@ the ctrl (bit 5 set, for example ^[[5~ to ^[[5^) modifier in non-xterm(1) mode;
|
||||
it may be possible to configure vim to accept these, an example of how to do so
|
||||
would be welcome.
|
||||
|
||||
vim users may also want to set the "ttyfast" option inside tmux.
|
||||
|
||||
* Why doesn't elinks set the window title inside tmux?
|
||||
|
||||
There isn't a way to detect if a terminal supports setting the window title, so
|
||||
@@ -239,4 +311,65 @@ set -g terminal-overrides "xterm*:kLFT5=\eOD:kRIT5=\eOC:kUP5=\eOA:kDN5=\eOB:smkx
|
||||
|
||||
Note that this will only work in tmux 1.2 and above.
|
||||
|
||||
$Id: FAQ,v 1.36 2010-02-04 21:01:59 nicm Exp $
|
||||
* How can I blank the tmux window?
|
||||
|
||||
GNU screen has a feature whereby it will blank the screen after a period of
|
||||
inactivity. To do the same thing in tmux, use the lock-command setting, for
|
||||
example (with GNU bash):
|
||||
|
||||
set -g lock-command 'tput civis && read -s -n1'
|
||||
|
||||
This will remove the cursor and tell the shell to quit once a key has been
|
||||
pressed. For zsh, use "read -s -k1".
|
||||
|
||||
In addition, it's possible to have both blanking and locking (for instance via
|
||||
lock(1) or vlock(1)) by using the following:
|
||||
|
||||
bind x set lock-command '/usr/bin/vlock' \; lock-client \; set lock-command 'tput civis && read -s -n1'
|
||||
|
||||
* How can I open a new window in the same directory as the current window?
|
||||
|
||||
One option is to just run "TMUX= tmux" in the window. However, this only works if no
|
||||
command is running, so that you can input the command.
|
||||
|
||||
A workaround is to let tmux know about the current path through an environment
|
||||
variable. To do so, use the following command:
|
||||
|
||||
[ -n "$TMUX" ] && tmux setenv TMUXPWD_$(tmux display -p "#I") $PWD
|
||||
|
||||
Which sets TMUXPWD_i (where i is the number of the current window) to the path
|
||||
of the current directory. This command can be added to PS1, for example:
|
||||
|
||||
PS1='$([ -n "$TMUX" ] && tmux setenv TMUXPWD_$(tmux display -p "#I") $PWD)\h$ '
|
||||
|
||||
When a new window is created, the shell should be asked to change
|
||||
directory. You can define a new binding (for example, if using GNU bash):
|
||||
|
||||
bind-key C-c run-shell 'tmux neww "cd $(tmux display -p "\$TMUXPWD_#I"); exec bash"'
|
||||
|
||||
This solution will work even if a command is currently running in the terminal,
|
||||
but it will not work from a window that has just been swapped with another
|
||||
because TMUXPWD_i will not be updated after a swap. However, once a new prompt
|
||||
is displayed, TMUXPWD_i is updated properly.
|
||||
|
||||
* tmux doesn't start with "daemon failed"
|
||||
|
||||
tmux shows something similar to this when started:
|
||||
|
||||
fatal: server_start: daemon failed: No such file or directory
|
||||
fatal: main_dispatch: imsg_read failed
|
||||
|
||||
A possible reason is that /dev/null is not a character device or is otherwise
|
||||
inaccessible.
|
||||
|
||||
Check with:
|
||||
|
||||
file /dev/null
|
||||
ls -l /dev/null
|
||||
|
||||
If it is not a character device or has incorrect permissions, it can typically
|
||||
be recreated with:
|
||||
|
||||
cd /dev && rm null && ./MAKEDEV null
|
||||
|
||||
$Id: FAQ,v 1.41 2010-12-15 23:31:30 nicm Exp $
|
||||
|
||||
15
GNUmakefile
15
GNUmakefile
@@ -1,4 +1,4 @@
|
||||
# $Id: GNUmakefile,v 1.122 2010-03-10 15:15:33 tcunha Exp $
|
||||
# $Id: GNUmakefile,v 1.130 2010-12-27 21:32:16 tcunha Exp $
|
||||
#
|
||||
# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
#
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
VERSION= 1.2
|
||||
VERSION= 1.4
|
||||
|
||||
#FDEBUG= 1
|
||||
|
||||
@@ -28,7 +28,7 @@ LIBS+=
|
||||
|
||||
# Sun CC
|
||||
ifneq ($(shell ($(CC) -V 2>&1|awk '/Sun C/' || true)), )
|
||||
CFLAGS+=-erroff=E_EMPTY_DECLARATION
|
||||
CFLAGS+= -erroff=E_EMPTY_DECLARATION
|
||||
FDEBUG=
|
||||
endif
|
||||
|
||||
@@ -52,11 +52,12 @@ endif
|
||||
endif
|
||||
|
||||
PREFIX?= /usr/local
|
||||
INSTALLDIR= install -d
|
||||
INSTALLBIN= install -g bin -o root -m 555
|
||||
INSTALLMAN= install -g bin -o root -m 444
|
||||
INSTALL?= install
|
||||
INSTALLDIR= $(INSTALL) -d
|
||||
INSTALLBIN= $(INSTALL) -m 555
|
||||
INSTALLMAN= $(INSTALL) -m 444
|
||||
|
||||
SRCS= $(shell echo *.c|sed 's|osdep-[a-z0-9]*.c||g')
|
||||
SRCS= $(shell echo *.c|LC_ALL=C sed 's|osdep-[a-z0-9]*.c||g')
|
||||
include config.mk
|
||||
OBJS= $(patsubst %.c,%.o,$(SRCS))
|
||||
|
||||
|
||||
13
Makefile
13
Makefile
@@ -1,4 +1,4 @@
|
||||
# $Id: Makefile,v 1.155 2010-03-10 15:15:33 tcunha Exp $
|
||||
# $Id: Makefile,v 1.162 2010-12-27 21:32:16 tcunha Exp $
|
||||
#
|
||||
# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
#
|
||||
@@ -18,7 +18,7 @@
|
||||
.SUFFIXES: .c .o
|
||||
.PHONY: clean
|
||||
|
||||
VERSION= 1.2
|
||||
VERSION= 1.4
|
||||
|
||||
#FDEBUG= 1
|
||||
|
||||
@@ -48,11 +48,12 @@ CFLAGS+= -Wno-pointer-sign
|
||||
.endif
|
||||
|
||||
PREFIX?= /usr/local
|
||||
INSTALLDIR= install -d
|
||||
INSTALLBIN= install -g bin -o root -m 555
|
||||
INSTALLMAN= install -g bin -o root -m 444
|
||||
INSTALL?= install
|
||||
INSTALLDIR= ${INSTALL} -d
|
||||
INSTALLBIN= ${INSTALL} -m 555
|
||||
INSTALLMAN= ${INSTALL} -m 444
|
||||
|
||||
SRCS!= echo *.c|sed 's|osdep-[a-z0-9]*.c||g'
|
||||
SRCS!= echo *.c|LC_ALL=C sed 's|osdep-[a-z0-9]*.c||g'
|
||||
.include "config.mk"
|
||||
OBJS= ${SRCS:S/.c/.o/}
|
||||
|
||||
|
||||
25
NOTES
25
NOTES
@@ -25,34 +25,11 @@ windows into several simultaneously displayed panes; and to bind and unbind
|
||||
command keys (invoked preceded by a prefix key, by default ctrl-b). Please see
|
||||
the tmux(1) man page for further information.
|
||||
|
||||
The following is a summary of major features implemented in this version:
|
||||
|
||||
- Basic multiplexing, window switching, attaching and detaching.
|
||||
- Window listing and renaming.
|
||||
- Key binding.
|
||||
- Handling of client terminal resize.
|
||||
- Terminal emulation sufficient to handle most curses applications.
|
||||
- A optional status line (enabled by default).
|
||||
- Window history and copy and paste.
|
||||
- Support for VT100 line drawing characters.
|
||||
- A large command set.
|
||||
- Vertical window splitting and layout.
|
||||
- Automatic server locking on inactivity by running an external command.
|
||||
- A configuration file.
|
||||
- UTF-8 support.
|
||||
|
||||
A more extensive, but rough, todo list is included in the TODO file.
|
||||
|
||||
tmux also depends on several features of the client terminal (TERM), if these
|
||||
are missing it may refuse to run, or not behave correctly.
|
||||
|
||||
tmux supports UTF-8. To use it, the utf8 option must be set on each window;
|
||||
this may be turned on for all windows by setting it as a global option, see
|
||||
tmux(1) and the FAQ file. As of 0.9, tmux attempts to autodetect a
|
||||
UTF-8 capable terminal by checking the LC_ALL, LC_CTYPE and LANG environment
|
||||
variables. list-clients may be used to check if this is detected correctly; if
|
||||
not, the -u command-line flag may be specified.
|
||||
|
||||
A Vim syntax file is available in the examples directory. To install it:
|
||||
|
||||
- Drop the file in the syntax directory in your runtimepath (such as
|
||||
@@ -86,4 +63,4 @@ start. Please contact me with any queries.
|
||||
|
||||
-- Nicholas Marriott <nicm@users.sf.net>
|
||||
|
||||
$Id: NOTES,v 1.53 2010-03-10 15:18:11 tcunha Exp $
|
||||
$Id: NOTES,v 1.54 2010-12-27 21:36:37 tcunha Exp $
|
||||
|
||||
91
TODO
91
TODO
@@ -1,4 +1,3 @@
|
||||
- window creation/idle time
|
||||
- better errors when creating new windows/sessions (how?)
|
||||
- implicitly add exec to the commands for new windows (switch to disable it)?
|
||||
- it would be nice to have multichar commands eg C-b K K
|
||||
@@ -7,27 +6,18 @@
|
||||
bring back detach-session to detach all clients on a session?
|
||||
- allow fnmatch for -c, so that you can, eg, detach all clients
|
||||
- garbage collect window history (100 lines at a time?) if it hasn't been used
|
||||
in $x time (need window creation/use times)
|
||||
in $x time
|
||||
- lift SHRT_MAX limits for history?
|
||||
- flags to centre screen in window
|
||||
- better terminal emulation
|
||||
- activity/bell should be per-window not per-link? what if it is cur win in
|
||||
session not being watched?
|
||||
- next prev word etc in command prompt
|
||||
- many more info() displays for various things
|
||||
- input.c is too complicated. simplify?
|
||||
- use a better termcap internally instead of screen, perhaps xterm
|
||||
- fix rxvt cursor fg issue (text under cursor can have non-white fg)
|
||||
- should be able to move to a hidden pane and it would be moved into view. pane
|
||||
number in status line/top-right would be cool for this
|
||||
- support other mouse modes (highlight etc) and use it in copy mode
|
||||
- set-remain-on-exit is a bit of a hack, some way to do it generically?
|
||||
- set-option should be set-session-option and should be overall global options
|
||||
also quiet, utf8 and maybe other flags?
|
||||
-g is a bit unexpected in conf file
|
||||
- clear window title on exit
|
||||
- the output code (tty.c) could do with optimisation depending on term
|
||||
capabilities
|
||||
- would be nice to be able to use "--" to mark start of command w/ neww etc
|
||||
to avoid quoting
|
||||
- make command sequences more usable: don't require space after ;, handle
|
||||
@@ -38,11 +28,7 @@
|
||||
"new-session" if-shell "[ -e $HOME/.tmux-session.conf ]" source-file
|
||||
$HOME/.tmux-session.conf
|
||||
- get it passing all the vttest tests that don't require resizing the terminal
|
||||
- esc seq to set window name and title should be documented, and name variant
|
||||
should clear automatic-rename
|
||||
- way to set socket path from config file
|
||||
- XXX once env stuff is in, default-path and VISUAL/EDITOR should be picked up
|
||||
when session is started
|
||||
- what about utmp etc? can tmux update it like screen? setgid?
|
||||
- warts on current naming:
|
||||
- display-time but message-fg/bg/attr
|
||||
@@ -50,48 +36,30 @@
|
||||
- server-info
|
||||
- up-pane/down-pane/swap-pane -U/swap-pane -D vs next-*/previous-*
|
||||
- split-window -> split-pane??
|
||||
- tidy up and prioritise todo list ;-)
|
||||
- neww and attach can create a session if none exists?
|
||||
would work fine with config file since
|
||||
- a way for force-width/height to apply to only one pane (how?)
|
||||
- command to list what is actually running in each window with command line,
|
||||
pid (need some adaption of the osdep code)
|
||||
- support for bce
|
||||
- it would be nice if the start/end line keys in copy mode were aware of
|
||||
wrapped lines
|
||||
- some way to force a screen to use the entire terminal even if it is forced
|
||||
to be smaller by other clients. pan smaller terminal? (like screen F)
|
||||
-- idea of a "view" onto a window, need base x/y offsets
|
||||
for redraw
|
||||
-- idea of a "view" onto a window, need base x/y offsets for redraw
|
||||
- handle resize better in copy mode
|
||||
- way to copy stuff that is off screen due to resize
|
||||
- commands should be able to succeed or fail and have || or && for command
|
||||
lists
|
||||
- support the mouse wheel to scroll through history
|
||||
- some way to KEEP a command running continually and just use its LAST line of
|
||||
output
|
||||
- bind commands to mouse buttons
|
||||
- UTF-8 to a non-UTF-8 terminal should not be able to balls up
|
||||
the terminal - www/ruby-addressable; make regress
|
||||
- copy mode needs a tidy/cleanup
|
||||
- ability to save history (to buffer?)
|
||||
- multiple keys could be done with tables, ie have prefixes go and instead
|
||||
bind -n ^A prefix-table "default"
|
||||
where prefix-table sets command lookup table and sets prefix flag, then next
|
||||
key is looked up in that table
|
||||
- UTF-8 should be a pointer into a combined string buffer
|
||||
- check irssi (term_charset) works with UTF-8
|
||||
- support esc-esc to quit in modes
|
||||
- fix ctrl+F1-F4 output. to what?
|
||||
- look into xterm clearing its selection when scrolling etc
|
||||
- better utf8 support:
|
||||
window names
|
||||
prompt input
|
||||
message display
|
||||
copy and paste cursor and wide characters
|
||||
...?
|
||||
- option so that when session is destroyed, attach client to another session
|
||||
rather than exiting
|
||||
- better utf8 support: window names, prompt input, message display
|
||||
- session history for client and last-session command
|
||||
- option to change status line colour when current window is in a mode?
|
||||
- option to move copy mode indicator into status line
|
||||
@@ -99,13 +67,10 @@
|
||||
- selection behaviour closer to vi in vi mode
|
||||
- live update: server started with -U connects to server, requests sessions and
|
||||
windows, receives fds
|
||||
- convert status line history to be server global (anything else?)
|
||||
- something for -t "last window in session" so a session can be used as a stack
|
||||
- command to show a tree of sessions-windows-panes (active marked with *)
|
||||
- sort out inheriting config from shell on new sessions/windows:
|
||||
should pick up default-path/termios/etc from client if possible,
|
||||
else leave empty/default
|
||||
- define custom layouts
|
||||
- link panes into multiple windows
|
||||
- -h option to capture-pane to capture the history as well
|
||||
- bells should be passed between sessions with visual-bell etc
|
||||
@@ -115,21 +80,51 @@
|
||||
- better session sharing: create-socket command to create socket somewhere (-r
|
||||
flag for readonly)
|
||||
- allow buffer to be specified when copying in copy mode
|
||||
- multiline status line
|
||||
- multiline status line (no?)
|
||||
- flag for absolute pane size to resize-pane
|
||||
- sanity check input to socket
|
||||
- stdin fd should be passed up to parent so load-buffer and others could use it
|
||||
for nonattaching clients
|
||||
- environment should be set up for jobs
|
||||
- select-buffer command
|
||||
- fix jobs so they block in config file rather than executing at an arbitrary
|
||||
future point -- need state stored in client so other clients can proceed
|
||||
- rectangle copy:
|
||||
when selecting leftward, cursor should be inside block per emacs
|
||||
key to rotate corner at which cursor is
|
||||
- double C-a should walk back over wrapped lines like C-e
|
||||
- support title stack, both internally and externally
|
||||
http://docs.freebsd.org/cgi/getmsg.cgi?fetch=1149299+0+archive/2010/freebsd-questions/20100207.freebsd-questions
|
||||
- copy buffers should be global, limit can be server option, nuke copy-buffer
|
||||
command
|
||||
- command to show status line information briefly when it is off
|
||||
- some way to pad # stuff with spaces, #!2T maybe
|
||||
- FreeBSD console problems
|
||||
- a binding to "scroll down and exit at bottom" copy mode
|
||||
- some way to pass keystrokes in copy mode through to underlying window
|
||||
- last window update time and # replacement for it for display-message
|
||||
- find-window across sessions - other ways to make session handling easier?
|
||||
- ' and " should be parsed the same (eg "\e" vs '\e') in config and command
|
||||
prompt?
|
||||
- command to toggle selection not to move it in copy-mode
|
||||
- why are alerts per-winlink? try per window?
|
||||
- audit of escape sequence support vs xterm
|
||||
- support binding keys to mouse (mouse-select-pane -> mouse-keys or something,
|
||||
mouse click == select-pane -t %%, mouse scroll up == copy-mode)
|
||||
- something for -t "last window in session" so a session can be used as a stack
|
||||
- synchronous commands - client sends cmd and blocks, neww/splitw saves client
|
||||
ptr then when program inside died, sends MSG_SOMETHING with wait status to
|
||||
client
|
||||
- documentation improvements - rlpowell's tutorial - build instructions
|
||||
- better configure? with-libevent
|
||||
- bind commands to key sequences?
|
||||
- monitor, bell etc should monitor /all/ panes in the window not just one
|
||||
- a history of commands that can be reversed (reverse member of each command,
|
||||
and a buffer) info() when changing to same window
|
||||
- don't pass UTF-8 through vis for titles
|
||||
- clearing screen should push lines into history
|
||||
- add a unique ever-increasing pane id to each pane, export it in $TMUX_PANE
|
||||
(as %1, %2 etc) and allow it to be used as a target
|
||||
- way to add dest for break-pane; maybe some easier way to unbreak-pane
|
||||
- case insensitive searching
|
||||
- dynamically generated jobs (eg "date ...") do not work well because
|
||||
their entries are never collected, should either store status jobs in
|
||||
a different tree or flush all unused persist jobs every update rather
|
||||
than just updating them
|
||||
- pane-index option like base-index
|
||||
- option to move status line to top
|
||||
- support "xterm2" mouse mode
|
||||
- respawn-pane command
|
||||
- configurable borders and empty space filler for when panes < window?
|
||||
|
||||
|
||||
4
array.h
4
array.h
@@ -1,4 +1,4 @@
|
||||
/* $Id: array.h,v 1.10 2010-02-08 18:29:32 tcunha Exp $ */
|
||||
/* $Id: array.h,v 1.11 2010-06-06 00:27:08 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -47,7 +47,7 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ARRAY_EMPTY(a) ((a) == NULL || (a)->num == 0)
|
||||
#define ARRAY_EMPTY(a) (((void *) (a)) == NULL || (a)->num == 0)
|
||||
#define ARRAY_LENGTH(a) ((a)->num)
|
||||
#define ARRAY_DATA(a) ((a)->list)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: attributes.c,v 1.3 2009-11-28 14:46:23 tcunha Exp $ */
|
||||
/* $Id: attributes.c,v 1.4 2010-06-05 23:54:51 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org>
|
||||
@@ -28,7 +28,7 @@ attributes_tostring(u_char attr)
|
||||
static char buf[128];
|
||||
|
||||
if (attr == 0)
|
||||
return ("default");
|
||||
return ("none");
|
||||
|
||||
buf[0] = '\0';
|
||||
if (attr & GRID_ATTR_BRIGHT)
|
||||
@@ -63,7 +63,7 @@ attributes_fromstring(const char *str)
|
||||
if (strchr(delimiters, str[strlen(str) - 1]) != NULL)
|
||||
return (-1);
|
||||
|
||||
if (strcasecmp(str, "default") == 0)
|
||||
if (strcasecmp(str, "default") == 0 || strcasecmp(str, "none") == 0)
|
||||
return (0);
|
||||
|
||||
attr = 0;
|
||||
|
||||
4
cfg.c
4
cfg.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: cfg.c,v 1.26 2010-02-08 18:29:32 tcunha Exp $ */
|
||||
/* $Id: cfg.c,v 1.27 2010-06-06 00:04:18 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -69,7 +69,7 @@ cfg_add_cause(struct causelist *causes, const char *fmt, ...)
|
||||
|
||||
/*
|
||||
* Load configuration file. Returns -1 for an error with a list of messages in
|
||||
* causes. Note that causes and ncauses must be initialised by the caller!
|
||||
* causes. Note that causes must be initialised by the caller!
|
||||
*/
|
||||
int
|
||||
load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)
|
||||
|
||||
381
client.c
381
client.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: client.c,v 1.90 2009-12-04 22:14:47 tcunha Exp $ */
|
||||
/* $Id: client.c,v 1.100 2010-10-24 19:54:41 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
@@ -29,7 +28,6 @@
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
@@ -38,93 +36,180 @@ struct imsgbuf client_ibuf;
|
||||
struct event client_event;
|
||||
const char *client_exitmsg;
|
||||
int client_exitval;
|
||||
int client_attached;
|
||||
|
||||
int client_connect(char *, int);
|
||||
void client_send_identify(int);
|
||||
void client_send_environ(void);
|
||||
void client_write_server(enum msgtype, void *, size_t);
|
||||
void client_update_event(void);
|
||||
void client_signal(int, short, void *);
|
||||
void client_callback(int, short, void *);
|
||||
int client_dispatch(void);
|
||||
int client_dispatch_attached(void);
|
||||
int client_dispatch_wait(void *);
|
||||
|
||||
struct imsgbuf *
|
||||
client_init(char *path, int cmdflags, int flags)
|
||||
/* Connect client to server. */
|
||||
int
|
||||
client_connect(char *path, int start_server)
|
||||
{
|
||||
struct sockaddr_un sa;
|
||||
size_t size;
|
||||
int fd, mode;
|
||||
#ifdef HAVE_SETPROCTITLE
|
||||
char rpathbuf[MAXPATHLEN];
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SETPROCTITLE
|
||||
if (realpath(path, rpathbuf) == NULL)
|
||||
strlcpy(rpathbuf, path, sizeof rpathbuf);
|
||||
setproctitle("client (%s)", rpathbuf);
|
||||
#endif
|
||||
|
||||
memset(&sa, 0, sizeof sa);
|
||||
sa.sun_family = AF_UNIX;
|
||||
size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
|
||||
if (size >= sizeof sa.sun_path) {
|
||||
errno = ENAMETOOLONG;
|
||||
goto not_found;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||
fatal("socket failed");
|
||||
|
||||
if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
|
||||
if (!(cmdflags & CMD_STARTSERVER))
|
||||
goto not_found;
|
||||
if (!start_server)
|
||||
goto failed;
|
||||
switch (errno) {
|
||||
case ECONNREFUSED:
|
||||
if (unlink(path) != 0)
|
||||
goto not_found;
|
||||
goto failed;
|
||||
/* FALLTHROUGH */
|
||||
case ENOENT:
|
||||
if ((fd = server_start(path)) == -1)
|
||||
goto start_failed;
|
||||
goto server_started;
|
||||
if ((fd = server_start()) == -1)
|
||||
goto failed;
|
||||
break;
|
||||
default:
|
||||
goto failed;
|
||||
}
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
server_started:
|
||||
if ((mode = fcntl(fd, F_GETFL)) == -1)
|
||||
fatal("fcntl failed");
|
||||
if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
|
||||
fatal("fcntl failed");
|
||||
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
|
||||
fatal("fcntl failed");
|
||||
imsg_init(&client_ibuf, fd);
|
||||
return (fd);
|
||||
|
||||
if (cmdflags & CMD_SENDENVIRON)
|
||||
client_send_environ();
|
||||
if (isatty(STDIN_FILENO))
|
||||
client_send_identify(flags);
|
||||
|
||||
return (&client_ibuf);
|
||||
|
||||
start_failed:
|
||||
log_warnx("server failed to start");
|
||||
return (NULL);
|
||||
|
||||
not_found:
|
||||
log_warn("server not found");
|
||||
return (NULL);
|
||||
failed:
|
||||
close(fd);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Client main loop. */
|
||||
int
|
||||
client_main(int argc, char **argv, int flags)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
struct cmd_list *cmdlist;
|
||||
struct msg_command_data cmddata;
|
||||
int cmdflags, fd;
|
||||
enum msgtype msg;
|
||||
char *cause;
|
||||
|
||||
/* Set up the initial command. */
|
||||
cmdflags = 0;
|
||||
if (shell_cmd != NULL) {
|
||||
msg = MSG_SHELL;
|
||||
cmdflags = CMD_STARTSERVER;
|
||||
} else if (argc == 0) {
|
||||
msg = MSG_COMMAND;
|
||||
cmdflags = CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST;
|
||||
} else {
|
||||
msg = MSG_COMMAND;
|
||||
|
||||
/*
|
||||
* It sucks parsing the command string twice (in client and
|
||||
* later in server) but it is necessary to get the start server
|
||||
* flag.
|
||||
*/
|
||||
if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
|
||||
log_warnx("%s", cause);
|
||||
return (1);
|
||||
}
|
||||
cmdflags &= ~CMD_STARTSERVER;
|
||||
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
|
||||
if (cmd->entry->flags & CMD_STARTSERVER)
|
||||
cmdflags |= CMD_STARTSERVER;
|
||||
if (cmd->entry->flags & CMD_SENDENVIRON)
|
||||
cmdflags |= CMD_SENDENVIRON;
|
||||
if (cmd->entry->flags & CMD_CANTNEST)
|
||||
cmdflags |= CMD_CANTNEST;
|
||||
}
|
||||
cmd_list_free(cmdlist);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if this could be a nested session, if the command can't nest:
|
||||
* if the socket path matches $TMUX, this is probably the same server.
|
||||
*/
|
||||
if (shell_cmd == NULL && environ_path != NULL &&
|
||||
cmdflags & CMD_CANTNEST && strcmp(socket_path, environ_path) == 0) {
|
||||
log_warnx("sessions should be nested with care. "
|
||||
"unset $TMUX to force.");
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Initialise the client socket and start the server. */
|
||||
fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER);
|
||||
if (fd == -1) {
|
||||
log_warn("failed to connect to server");
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Set process title, log and signals now this is the client. */
|
||||
#ifdef HAVE_SETPROCTITLE
|
||||
setproctitle("client (%s)", socket_path);
|
||||
#endif
|
||||
logfile("client");
|
||||
|
||||
/* Create imsg. */
|
||||
imsg_init(&client_ibuf, fd);
|
||||
event_set(&client_event, fd, EV_READ, client_callback, shell_cmd);
|
||||
|
||||
/* Establish signal handlers. */
|
||||
set_signals(client_signal);
|
||||
|
||||
/* Send initial environment. */
|
||||
if (cmdflags & CMD_SENDENVIRON)
|
||||
client_send_environ();
|
||||
client_send_identify(flags);
|
||||
|
||||
/* Send first command. */
|
||||
if (msg == MSG_COMMAND) {
|
||||
/* Fill in command line arguments. */
|
||||
cmddata.pid = environ_pid;
|
||||
cmddata.idx = environ_idx;
|
||||
|
||||
/* Prepare command for server. */
|
||||
cmddata.argc = argc;
|
||||
if (cmd_pack_argv(
|
||||
argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) {
|
||||
log_warnx("command too long");
|
||||
return (1);
|
||||
}
|
||||
|
||||
client_write_server(msg, &cmddata, sizeof cmddata);
|
||||
} else if (msg == MSG_SHELL)
|
||||
client_write_server(msg, NULL, 0);
|
||||
|
||||
/* Set the event and dispatch. */
|
||||
client_update_event();
|
||||
event_dispatch();
|
||||
|
||||
/* Print the exit message, if any, and exit. */
|
||||
if (client_attached && client_exitmsg != NULL && !login_shell)
|
||||
printf("[%s]\n", client_exitmsg);
|
||||
return (client_exitval);
|
||||
}
|
||||
|
||||
/* Send identify message to server with the file descriptors. */
|
||||
void
|
||||
client_send_identify(int flags)
|
||||
{
|
||||
struct msg_identify_data data;
|
||||
struct winsize ws;
|
||||
char *term;
|
||||
int fd;
|
||||
|
||||
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
|
||||
fatal("ioctl(TIOCGWINSZ)");
|
||||
data.flags = flags;
|
||||
|
||||
if (getcwd(data.cwd, sizeof data.cwd) == NULL)
|
||||
@@ -139,8 +224,19 @@ client_send_identify(int flags)
|
||||
fatal("dup failed");
|
||||
imsg_compose(&client_ibuf,
|
||||
MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
|
||||
|
||||
if ((fd = dup(STDOUT_FILENO)) == -1)
|
||||
fatal("dup failed");
|
||||
imsg_compose(&client_ibuf,
|
||||
MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0);
|
||||
|
||||
if ((fd = dup(STDERR_FILENO)) == -1)
|
||||
fatal("dup failed");
|
||||
imsg_compose(&client_ibuf,
|
||||
MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0);
|
||||
}
|
||||
|
||||
/* Forward entire environment to server. */
|
||||
void
|
||||
client_send_environ(void)
|
||||
{
|
||||
@@ -154,12 +250,14 @@ client_send_environ(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Write a message to the server without a file descriptor. */
|
||||
void
|
||||
client_write_server(enum msgtype type, void *buf, size_t len)
|
||||
{
|
||||
imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
|
||||
}
|
||||
|
||||
/* Update client event based on whether it needs to read or read and write. */
|
||||
void
|
||||
client_update_event(void)
|
||||
{
|
||||
@@ -169,102 +267,74 @@ client_update_event(void)
|
||||
events = EV_READ;
|
||||
if (client_ibuf.w.queued > 0)
|
||||
events |= EV_WRITE;
|
||||
event_set(&client_event, client_ibuf.fd, events, client_callback, NULL);
|
||||
event_set(
|
||||
&client_event, client_ibuf.fd, events, client_callback, shell_cmd);
|
||||
event_add(&client_event, NULL);
|
||||
}
|
||||
|
||||
__dead void
|
||||
client_main(void)
|
||||
{
|
||||
struct event ev_sigcont, ev_sigterm, ev_sigwinch;
|
||||
struct sigaction sigact;
|
||||
|
||||
logfile("client");
|
||||
|
||||
/* Note: event_init() has already been called. */
|
||||
|
||||
/* Set up signals. */
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGINT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR1, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
|
||||
signal_set(&ev_sigcont, SIGCONT, client_signal, NULL);
|
||||
signal_add(&ev_sigcont, NULL);
|
||||
signal_set(&ev_sigterm, SIGTERM, client_signal, NULL);
|
||||
signal_add(&ev_sigterm, NULL);
|
||||
signal_set(&ev_sigwinch, SIGWINCH, client_signal, NULL);
|
||||
signal_add(&ev_sigwinch, NULL);
|
||||
|
||||
/*
|
||||
* imsg_read in the first client poll loop (before the terminal has
|
||||
* been initialised) may have read messages into the buffer after the
|
||||
* MSG_READY switched to here. Process anything outstanding now to
|
||||
* avoid hanging waiting for messages that have already arrived.
|
||||
*/
|
||||
if (client_dispatch() != 0)
|
||||
goto out;
|
||||
|
||||
/* Set the event and dispatch. */
|
||||
client_update_event();
|
||||
event_dispatch();
|
||||
|
||||
out:
|
||||
/* Print the exit message, if any, and exit. */
|
||||
if (client_exitmsg != NULL && !login_shell)
|
||||
printf("[%s]\n", client_exitmsg);
|
||||
exit(client_exitval);
|
||||
}
|
||||
|
||||
/* Callback to handle signals in the client. */
|
||||
/* ARGSUSED */
|
||||
void
|
||||
client_signal(int sig, unused short events, unused void *data)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
struct sigaction sigact;
|
||||
int status;
|
||||
|
||||
switch (sig) {
|
||||
case SIGTERM:
|
||||
client_exitmsg = "terminated";
|
||||
client_exitval = 1;
|
||||
client_write_server(MSG_EXITING, NULL, 0);
|
||||
break;
|
||||
case SIGWINCH:
|
||||
client_write_server(MSG_RESIZE, NULL, 0);
|
||||
break;
|
||||
case SIGCONT:
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
client_write_server(MSG_WAKEUP, NULL, 0);
|
||||
break;
|
||||
if (!client_attached) {
|
||||
switch (sig) {
|
||||
case SIGCHLD:
|
||||
waitpid(WAIT_ANY, &status, WNOHANG);
|
||||
break;
|
||||
case SIGTERM:
|
||||
event_loopexit(NULL);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (sig) {
|
||||
case SIGHUP:
|
||||
client_exitmsg = "lost tty";
|
||||
client_exitval = 1;
|
||||
client_write_server(MSG_EXITING, NULL, 0);
|
||||
break;
|
||||
case SIGTERM:
|
||||
client_exitmsg = "terminated";
|
||||
client_exitval = 1;
|
||||
client_write_server(MSG_EXITING, NULL, 0);
|
||||
break;
|
||||
case SIGWINCH:
|
||||
client_write_server(MSG_RESIZE, NULL, 0);
|
||||
break;
|
||||
case SIGCONT:
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
client_write_server(MSG_WAKEUP, NULL, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
client_update_event();
|
||||
}
|
||||
|
||||
/* Callback for client imsg read events. */
|
||||
/* ARGSUSED */
|
||||
void
|
||||
client_callback(unused int fd, short events, unused void *data)
|
||||
client_callback(unused int fd, short events, void *data)
|
||||
{
|
||||
ssize_t n;
|
||||
int retval;
|
||||
|
||||
if (events & EV_READ) {
|
||||
if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
|
||||
goto lost_server;
|
||||
if (client_dispatch() != 0) {
|
||||
if (client_attached)
|
||||
retval = client_dispatch_attached();
|
||||
else
|
||||
retval = client_dispatch_wait(data);
|
||||
if (retval != 0) {
|
||||
event_loopexit(NULL);
|
||||
return;
|
||||
}
|
||||
@@ -284,8 +354,76 @@ lost_server:
|
||||
event_loopexit(NULL);
|
||||
}
|
||||
|
||||
/* Dispatch imsgs when in wait state (before MSG_READY). */
|
||||
int
|
||||
client_dispatch(void)
|
||||
client_dispatch_wait(void *data)
|
||||
{
|
||||
struct imsg imsg;
|
||||
ssize_t n, datalen;
|
||||
struct msg_shell_data shelldata;
|
||||
struct msg_exit_data exitdata;
|
||||
const char *shellcmd = data;
|
||||
|
||||
if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
|
||||
fatalx("imsg_read failed");
|
||||
|
||||
for (;;) {
|
||||
if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
|
||||
fatalx("imsg_get failed");
|
||||
if (n == 0)
|
||||
return (0);
|
||||
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
|
||||
|
||||
switch (imsg.hdr.type) {
|
||||
case MSG_EXIT:
|
||||
case MSG_SHUTDOWN:
|
||||
if (datalen != sizeof exitdata) {
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_EXIT size");
|
||||
} else {
|
||||
memcpy(&exitdata, imsg.data, sizeof exitdata);
|
||||
client_exitval = exitdata.retcode;
|
||||
}
|
||||
imsg_free(&imsg);
|
||||
return (-1);
|
||||
case MSG_READY:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_READY size");
|
||||
|
||||
client_attached = 1;
|
||||
break;
|
||||
case MSG_VERSION:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_VERSION size");
|
||||
|
||||
log_warnx("protocol version mismatch (client %u, "
|
||||
"server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
|
||||
client_exitval = 1;
|
||||
|
||||
imsg_free(&imsg);
|
||||
return (-1);
|
||||
case MSG_SHELL:
|
||||
if (datalen != sizeof shelldata)
|
||||
fatalx("bad MSG_SHELL size");
|
||||
memcpy(&shelldata, imsg.data, sizeof shelldata);
|
||||
shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
|
||||
|
||||
clear_signals(0);
|
||||
|
||||
shell_exec(shelldata.shell, shellcmd);
|
||||
/* NOTREACHED */
|
||||
default:
|
||||
fatalx("unexpected message");
|
||||
}
|
||||
|
||||
imsg_free(&imsg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Dispatch imsgs in attached state (after MSG_READY). */
|
||||
/* ARGSUSED */
|
||||
int
|
||||
client_dispatch_attached(void)
|
||||
{
|
||||
struct imsg imsg;
|
||||
struct msg_lock_data lockdata;
|
||||
@@ -309,7 +447,8 @@ client_dispatch(void)
|
||||
client_exitmsg = "detached";
|
||||
break;
|
||||
case MSG_EXIT:
|
||||
if (datalen != 0)
|
||||
if (datalen != 0 &&
|
||||
datalen != sizeof (struct msg_exit_data))
|
||||
fatalx("bad MSG_EXIT size");
|
||||
|
||||
client_write_server(MSG_EXITING, NULL, 0);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-attach-session.c,v 1.36 2010-02-08 18:27:34 tcunha Exp $ */
|
||||
/* $Id: cmd-attach-session.c,v 1.37 2010-12-22 15:36:44 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -47,7 +47,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
char *overrides, *cause;
|
||||
u_int i;
|
||||
|
||||
if (ARRAY_LENGTH(&sessions) == 0) {
|
||||
if (RB_EMPTY(&sessions)) {
|
||||
ctx->error(ctx, "no sessions");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-bind-key.c,v 1.28 2010-01-25 17:12:44 tcunha Exp $ */
|
||||
/* $Id: cmd-bind-key.c,v 1.29 2010-07-02 02:43:01 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -130,7 +130,7 @@ cmd_bind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
|
||||
return (cmd_bind_key_table(self, ctx));
|
||||
|
||||
key_bindings_add(data->key, data->can_repeat, data->cmdlist);
|
||||
data->cmdlist = NULL; /* avoid free */
|
||||
data->cmdlist->references++;
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -192,8 +192,17 @@ cmd_bind_key_print(struct cmd *self, char *buf, size_t len)
|
||||
off += xsnprintf(buf, len, "%s", self->entry->name);
|
||||
if (data == NULL)
|
||||
return (off);
|
||||
|
||||
if (off < len && data->command_key)
|
||||
off += xsnprintf(buf + off, len - off, " -c");
|
||||
if (off < len && !(data->key & KEYC_PREFIX))
|
||||
off += xsnprintf(buf + off, len - off, " -n");
|
||||
if (off < len && data->can_repeat)
|
||||
off += xsnprintf(buf + off, len - off, " -r");
|
||||
if (off < len && data->tablename != NULL)
|
||||
off += cmd_prarg(buf + off, len - off, " -t ", data->tablename);
|
||||
if (off < len) {
|
||||
skey = key_string_lookup_key(data->key);
|
||||
skey = key_string_lookup_key(data->key & ~KEYC_PREFIX);
|
||||
off += xsnprintf(buf + off, len - off, " %s ", skey);
|
||||
}
|
||||
if (off < len)
|
||||
|
||||
146
cmd-choose-buffer.c
Normal file
146
cmd-choose-buffer.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/* $Id: cmd-choose-buffer.c,v 1.1 2010-06-22 23:35:20 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF 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 <ctype.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* Enter choice mode to choose a buffer.
|
||||
*/
|
||||
|
||||
int cmd_choose_buffer_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
void cmd_choose_buffer_callback(void *, int);
|
||||
void cmd_choose_buffer_free(void *);
|
||||
|
||||
const struct cmd_entry cmd_choose_buffer_entry = {
|
||||
"choose-buffer", NULL,
|
||||
CMD_TARGET_WINDOW_USAGE " [template]",
|
||||
CMD_ARG01, "",
|
||||
cmd_target_init,
|
||||
cmd_target_parse,
|
||||
cmd_choose_buffer_exec,
|
||||
cmd_target_free,
|
||||
cmd_target_print
|
||||
};
|
||||
|
||||
struct cmd_choose_buffer_data {
|
||||
struct client *client;
|
||||
char *template;
|
||||
};
|
||||
|
||||
int
|
||||
cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct cmd_target_data *data = self->data;
|
||||
struct cmd_choose_buffer_data *cdata;
|
||||
struct session *s;
|
||||
struct winlink *wl;
|
||||
struct paste_buffer *pb;
|
||||
u_int idx;
|
||||
char *tmp;
|
||||
|
||||
if (ctx->curclient == NULL) {
|
||||
ctx->error(ctx, "must be run interactively");
|
||||
return (-1);
|
||||
}
|
||||
s = ctx->curclient->session;
|
||||
|
||||
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
|
||||
return (-1);
|
||||
|
||||
if (paste_get_top(&s->buffers) == NULL)
|
||||
return (0);
|
||||
|
||||
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
|
||||
return (0);
|
||||
|
||||
idx = 0;
|
||||
while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) {
|
||||
tmp = paste_print(pb, 50);
|
||||
window_choose_add(wl->window->active, idx - 1,
|
||||
"%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp);
|
||||
xfree(tmp);
|
||||
}
|
||||
|
||||
cdata = xmalloc(sizeof *cdata);
|
||||
if (data->arg != NULL)
|
||||
cdata->template = xstrdup(data->arg);
|
||||
else
|
||||
cdata->template = xstrdup("paste-buffer -b '%%'");
|
||||
cdata->client = ctx->curclient;
|
||||
cdata->client->references++;
|
||||
|
||||
window_choose_ready(wl->window->active,
|
||||
0, cmd_choose_buffer_callback, cmd_choose_buffer_free, cdata);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_choose_buffer_callback(void *data, int idx)
|
||||
{
|
||||
struct cmd_choose_buffer_data *cdata = data;
|
||||
struct cmd_list *cmdlist;
|
||||
struct cmd_ctx ctx;
|
||||
char *template, *cause, tmp[16];
|
||||
|
||||
if (idx == -1)
|
||||
return;
|
||||
if (cdata->client->flags & CLIENT_DEAD)
|
||||
return;
|
||||
|
||||
xsnprintf(tmp, sizeof tmp, "%u", idx);
|
||||
template = cmd_template_replace(cdata->template, tmp, 1);
|
||||
|
||||
if (cmd_string_parse(template, &cmdlist, &cause) != 0) {
|
||||
if (cause != NULL) {
|
||||
*cause = toupper((u_char) *cause);
|
||||
status_message_set(cdata->client, "%s", cause);
|
||||
xfree(cause);
|
||||
}
|
||||
xfree(template);
|
||||
return;
|
||||
}
|
||||
xfree(template);
|
||||
|
||||
ctx.msgdata = NULL;
|
||||
ctx.curclient = cdata->client;
|
||||
|
||||
ctx.error = key_bindings_error;
|
||||
ctx.print = key_bindings_print;
|
||||
ctx.info = key_bindings_info;
|
||||
|
||||
ctx.cmdclient = NULL;
|
||||
|
||||
cmd_list_exec(cmdlist, &ctx);
|
||||
cmd_list_free(cmdlist);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_choose_buffer_free(void *data)
|
||||
{
|
||||
struct cmd_choose_buffer_data *cdata = data;
|
||||
|
||||
cdata->client->references--;
|
||||
xfree(cdata->template);
|
||||
xfree(cdata);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-choose-session.c,v 1.15 2009-11-14 17:56:39 tcunha Exp $ */
|
||||
/* $Id: cmd-choose-session.c,v 1.17 2010-12-22 15:36:44 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -55,7 +55,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
struct winlink *wl;
|
||||
struct session *s;
|
||||
struct session_group *sg;
|
||||
u_int i, idx, cur;
|
||||
u_int idx, sgidx, cur;
|
||||
char tmp[64];
|
||||
|
||||
if (ctx->curclient == NULL) {
|
||||
@@ -70,10 +70,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
return (0);
|
||||
|
||||
cur = idx = 0;
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
s = ARRAY_ITEM(&sessions, i);
|
||||
if (s == NULL)
|
||||
continue;
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
if (s == ctx->curclient->session)
|
||||
cur = idx;
|
||||
idx++;
|
||||
@@ -82,11 +79,11 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
if (sg == NULL)
|
||||
*tmp = '\0';
|
||||
else {
|
||||
idx = session_group_index(sg);
|
||||
xsnprintf(tmp, sizeof tmp, " (group %u)", idx);
|
||||
sgidx = session_group_index(sg);
|
||||
xsnprintf(tmp, sizeof tmp, " (group %u)", sgidx);
|
||||
}
|
||||
|
||||
window_choose_add(wl->window->active, i,
|
||||
window_choose_add(wl->window->active, s->idx,
|
||||
"%s: %u windows [%ux%u]%s%s", s->name,
|
||||
winlink_count(&s->windows), s->sx, s->sy,
|
||||
tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)");
|
||||
@@ -120,9 +117,7 @@ cmd_choose_session_callback(void *data, int idx)
|
||||
if (cdata->client->flags & CLIENT_DEAD)
|
||||
return;
|
||||
|
||||
if ((u_int) idx > ARRAY_LENGTH(&sessions) - 1)
|
||||
return;
|
||||
s = ARRAY_ITEM(&sessions, idx);
|
||||
s = session_find_by_index(idx);
|
||||
if (s == NULL)
|
||||
return;
|
||||
template = cmd_template_replace(cdata->template, s->name, 1);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-choose-window.c,v 1.20 2009-12-04 22:14:47 tcunha Exp $ */
|
||||
/* $Id: cmd-choose-window.c,v 1.24 2010-12-22 15:28:50 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -81,12 +81,14 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
idx++;
|
||||
|
||||
flag = ' ';
|
||||
if (session_alert_has(s, wm, WINDOW_ACTIVITY))
|
||||
if (wm->flags & WINLINK_ACTIVITY)
|
||||
flag = '#';
|
||||
else if (session_alert_has(s, wm, WINDOW_BELL))
|
||||
else if (wm->flags & WINLINK_BELL)
|
||||
flag = '!';
|
||||
else if (session_alert_has(s, wm, WINDOW_CONTENT))
|
||||
else if (wm->flags & WINLINK_CONTENT)
|
||||
flag = '+';
|
||||
else if (wm->flags & WINLINK_SILENCE)
|
||||
flag = '~';
|
||||
else if (wm == s->curw)
|
||||
flag = '*';
|
||||
else if (wm == TAILQ_FIRST(&s->lastw))
|
||||
@@ -101,8 +103,9 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
left = right = "";
|
||||
|
||||
window_choose_add(wl->window->active,
|
||||
wm->idx, "%3d: %s%c [%ux%u] (%u panes)%s%s%s",
|
||||
wm->idx, "%3d: %s%c [%ux%u] (%u panes%s)%s%s%s",
|
||||
wm->idx, w->name, flag, w->sx, w->sy, window_count_panes(w),
|
||||
w->active->fd == -1 ? ", dead" : "",
|
||||
left, title, right);
|
||||
}
|
||||
|
||||
@@ -126,20 +129,19 @@ void
|
||||
cmd_choose_window_callback(void *data, int idx)
|
||||
{
|
||||
struct cmd_choose_window_data *cdata = data;
|
||||
struct session *s = cdata->session;
|
||||
struct cmd_list *cmdlist;
|
||||
struct cmd_ctx ctx;
|
||||
char *target, *template, *cause;
|
||||
|
||||
if (idx == -1)
|
||||
return;
|
||||
if (!session_alive(s))
|
||||
return;
|
||||
if (cdata->client->flags & CLIENT_DEAD)
|
||||
return;
|
||||
if (cdata->session->flags & SESSION_DEAD)
|
||||
return;
|
||||
if (cdata->client->session != cdata->session)
|
||||
return;
|
||||
|
||||
xasprintf(&target, "%s:%d", cdata->session->name, idx);
|
||||
xasprintf(&target, "%s:%d", s->name, idx);
|
||||
template = cmd_template_replace(cdata->template, target, 1);
|
||||
xfree(target);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-command-prompt.c,v 1.27 2009-11-14 17:56:39 tcunha Exp $ */
|
||||
/* $Id: cmd-command-prompt.c,v 1.28 2010-05-14 14:33:39 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -81,6 +81,10 @@ cmd_command_prompt_init(struct cmd *self, int key)
|
||||
case 'f':
|
||||
data->template = xstrdup("find-window '%%'");
|
||||
break;
|
||||
case '\'':
|
||||
data->template = xstrdup("select-window -t ':%%'");
|
||||
data->prompts = xstrdup("index");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-copy-mode.c,v 1.26 2010-01-05 23:50:22 tcunha Exp $ */
|
||||
/* $Id: cmd-copy-mode.c,v 1.28 2010-08-11 22:18:28 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -62,7 +62,9 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
|
||||
return (-1);
|
||||
|
||||
window_pane_set_mode(wp, &window_copy_mode);
|
||||
if (window_pane_set_mode(wp, &window_copy_mode) != 0)
|
||||
return (0);
|
||||
window_copy_init_from_pane(wp);
|
||||
if (wp->mode == &window_copy_mode && cmd_check_flag(data->chflags, 'u'))
|
||||
window_copy_pageup(wp);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-find-window.c,v 1.14 2009-11-14 17:56:39 tcunha Exp $ */
|
||||
/* $Id: cmd-find-window.c,v 1.15 2010-12-22 15:28:50 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -30,6 +30,7 @@
|
||||
int cmd_find_window_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
void cmd_find_window_callback(void *, int);
|
||||
void cmd_find_window_free(void *);
|
||||
|
||||
const struct cmd_entry cmd_find_window_entry = {
|
||||
"find-window", "findw",
|
||||
@@ -43,7 +44,7 @@ const struct cmd_entry cmd_find_window_entry = {
|
||||
};
|
||||
|
||||
struct cmd_find_window_data {
|
||||
u_int session;
|
||||
struct session *session;
|
||||
};
|
||||
|
||||
int
|
||||
@@ -134,11 +135,11 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
}
|
||||
|
||||
cdata = xmalloc(sizeof *cdata);
|
||||
if (session_index(s, &cdata->session) != 0)
|
||||
fatalx("session not found");
|
||||
cdata->session = s;
|
||||
cdata->session->references++;
|
||||
|
||||
window_choose_ready(
|
||||
wl->window->active, 0, cmd_find_window_callback, xfree, cdata);
|
||||
window_choose_ready(wl->window->active,
|
||||
0, cmd_find_window_callback, cmd_find_window_free, cdata);
|
||||
|
||||
out:
|
||||
ARRAY_FREE(&list_idx);
|
||||
@@ -151,12 +152,24 @@ void
|
||||
cmd_find_window_callback(void *data, int idx)
|
||||
{
|
||||
struct cmd_find_window_data *cdata = data;
|
||||
struct session *s;
|
||||
struct session *s = cdata->session;
|
||||
|
||||
if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) {
|
||||
s = ARRAY_ITEM(&sessions, cdata->session);
|
||||
if (s != NULL && session_select(s, idx) == 0)
|
||||
server_redraw_session(s);
|
||||
if (idx == -1)
|
||||
return;
|
||||
if (!session_alive(s))
|
||||
return;
|
||||
|
||||
if (session_select(s, idx) == 0) {
|
||||
server_redraw_session(s);
|
||||
recalculate_sizes();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cmd_find_window_free(void *data)
|
||||
{
|
||||
struct cmd_find_window_data *cdata = data;
|
||||
|
||||
cdata->session->references--;
|
||||
xfree(cdata);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-if-shell.c,v 1.8 2009-11-14 17:56:39 tcunha Exp $ */
|
||||
/* $Id: cmd-if-shell.c,v 1.10 2010-08-09 21:44:25 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
@@ -104,10 +104,12 @@ cmd_if_shell_free(void *data)
|
||||
{
|
||||
struct cmd_if_shell_data *cdata = data;
|
||||
struct cmd_ctx *ctx = &cdata->ctx;
|
||||
struct msg_exit_data exitdata;
|
||||
|
||||
if (ctx->cmdclient != NULL) {
|
||||
ctx->cmdclient->references--;
|
||||
server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0);
|
||||
exitdata.retcode = ctx->cmdclient->retcode;
|
||||
ctx->cmdclient->flags |= CLIENT_EXIT;
|
||||
}
|
||||
if (ctx->curclient != NULL)
|
||||
ctx->curclient->references--;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-join-pane.c,v 1.2 2010-01-08 16:34:17 tcunha Exp $ */
|
||||
/* $Id: cmd-join-pane.c,v 1.5 2010-08-11 22:17:32 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -44,7 +44,7 @@ struct cmd_join_pane_data {
|
||||
|
||||
const struct cmd_entry cmd_join_pane_entry = {
|
||||
"join-pane", "joinp",
|
||||
"[-dhv] [-p percentage|-l size] [-t src-pane] [-t dst-pane] [command]",
|
||||
"[-dhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]",
|
||||
0, "",
|
||||
cmd_join_pane_init,
|
||||
cmd_join_pane_parse,
|
||||
@@ -150,13 +150,14 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
struct winlink *src_wl, *dst_wl;
|
||||
struct window *src_w, *dst_w;
|
||||
struct window_pane *src_wp, *dst_wp;
|
||||
int size;
|
||||
int size, dst_idx;
|
||||
enum layout_type type;
|
||||
struct layout_cell *lc;
|
||||
|
||||
if ((dst_wl = cmd_find_pane(ctx, data->dst, &dst_s, &dst_wp)) == NULL)
|
||||
return (-1);
|
||||
dst_w = dst_wl->window;
|
||||
dst_idx = dst_wl->idx;
|
||||
|
||||
if ((src_wl = cmd_find_pane(ctx, data->src, NULL, &src_wp)) == NULL)
|
||||
return (-1);
|
||||
@@ -209,7 +210,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
|
||||
if (!data->flag_detached) {
|
||||
window_set_active_pane(dst_w, src_wp);
|
||||
session_select(dst_s, dst_wl->idx);
|
||||
session_select(dst_s, dst_idx);
|
||||
server_redraw_session(dst_s);
|
||||
} else
|
||||
server_status_session(dst_s);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-kill-session.c,v 1.17 2009-12-04 22:14:47 tcunha Exp $ */
|
||||
/* $Id: cmd-kill-session.c,v 1.18 2010-07-02 02:43:50 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -45,21 +45,11 @@ cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct cmd_target_data *data = self->data;
|
||||
struct session *s;
|
||||
struct client *c;
|
||||
u_int i;
|
||||
|
||||
if ((s = cmd_find_session(ctx, data->target)) == NULL)
|
||||
return (-1);
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
c = ARRAY_ITEM(&clients, i);
|
||||
if (c != NULL && c->session == s) {
|
||||
c->session = NULL;
|
||||
server_write_client(c, MSG_EXIT, NULL, 0);
|
||||
}
|
||||
}
|
||||
recalculate_sizes();
|
||||
|
||||
server_destroy_session(s);
|
||||
session_destroy(s);
|
||||
|
||||
return (0);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* $Id: cmd-down-pane.c,v 1.14 2010-01-05 23:52:37 tcunha Exp $ */
|
||||
/* $Id: cmd-last-pane.c,v 1.1 2010-10-24 01:34:30 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
* Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@@ -21,24 +21,24 @@
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* Move down a pane.
|
||||
* Move to last pane.
|
||||
*/
|
||||
|
||||
int cmd_down_pane_exec(struct cmd *, struct cmd_ctx *);
|
||||
int cmd_last_pane_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
const struct cmd_entry cmd_down_pane_entry = {
|
||||
"down-pane", "downp",
|
||||
const struct cmd_entry cmd_last_pane_entry = {
|
||||
"last-pane", "lastp",
|
||||
CMD_TARGET_WINDOW_USAGE,
|
||||
0, "",
|
||||
cmd_target_init,
|
||||
cmd_target_parse,
|
||||
cmd_down_pane_exec,
|
||||
cmd_last_pane_exec,
|
||||
cmd_target_free,
|
||||
cmd_target_print
|
||||
};
|
||||
|
||||
int
|
||||
cmd_down_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
cmd_last_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct cmd_target_data *data = self->data;
|
||||
struct winlink *wl;
|
||||
@@ -48,13 +48,11 @@ cmd_down_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
return (-1);
|
||||
w = wl->window;
|
||||
|
||||
do {
|
||||
w->active = TAILQ_NEXT(w->active, entry);
|
||||
if (w->active == NULL)
|
||||
w->active = TAILQ_FIRST(&w->panes);
|
||||
} while (!window_pane_visible(w->active));
|
||||
server_status_window(wl->window);
|
||||
server_redraw_window_borders(wl->window);
|
||||
if (w->last == NULL) {
|
||||
ctx->error(ctx, "no last pane");
|
||||
return (-1);
|
||||
}
|
||||
window_set_active_pane(w, w->last);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-list-buffers.c,v 1.15 2009-12-04 22:14:47 tcunha Exp $ */
|
||||
/* $Id: cmd-list-buffers.c,v 1.16 2010-06-22 23:35:20 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -46,32 +46,17 @@ cmd_list_buffers_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
struct session *s;
|
||||
struct paste_buffer *pb;
|
||||
u_int idx;
|
||||
char tmp[51 * 4 + 1];
|
||||
size_t size, len;
|
||||
char *tmp;
|
||||
|
||||
if ((s = cmd_find_session(ctx, data->target)) == NULL)
|
||||
return (-1);
|
||||
|
||||
idx = 0;
|
||||
while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) {
|
||||
size = pb->size;
|
||||
|
||||
/* Translate the first 50 characters. */
|
||||
len = size;
|
||||
if (len > 50)
|
||||
len = 50;
|
||||
strvisx(tmp, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL);
|
||||
|
||||
/*
|
||||
* If the first 50 characters were encoded as a longer string,
|
||||
* or there is definitely more data, add "...".
|
||||
*/
|
||||
if (size > 50 || strlen(tmp) > 50) {
|
||||
tmp[50 - 3] = '\0';
|
||||
strlcat(tmp, "...", sizeof tmp);
|
||||
}
|
||||
|
||||
ctx->print(ctx, "%u: %zu bytes: \"%s\"", idx - 1, size, tmp);
|
||||
tmp = paste_print(pb, 50);
|
||||
ctx->print(ctx,
|
||||
"%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp);
|
||||
xfree(tmp);
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-list-keys.c,v 1.24 2009-12-04 22:14:47 tcunha Exp $ */
|
||||
/* $Id: cmd-list-keys.c,v 1.25 2010-10-24 01:31:57 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -80,6 +80,11 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
if (used >= sizeof tmp)
|
||||
continue;
|
||||
}
|
||||
if (bd->can_repeat) {
|
||||
used = strlcat(tmp, "(repeat) ", sizeof tmp);
|
||||
if (used >= sizeof tmp)
|
||||
continue;
|
||||
}
|
||||
cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used);
|
||||
ctx->print(ctx, "%s", tmp);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-list-panes.c,v 1.4 2009-12-04 22:14:47 tcunha Exp $ */
|
||||
/* $Id: cmd-list-panes.c,v 1.6 2010-12-06 21:56:32 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -65,8 +65,10 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
}
|
||||
size += gd->hsize * sizeof *gd->linedata;
|
||||
|
||||
ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]",
|
||||
n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size);
|
||||
ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]%s%s",
|
||||
n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size,
|
||||
wp == wp->window->active ? " (active)" : "",
|
||||
wp->fd == -1 ? " (dead)" : "");
|
||||
n++;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-list-sessions.c,v 1.25 2009-11-28 14:50:36 tcunha Exp $ */
|
||||
/* $Id: cmd-list-sessions.c,v 1.26 2010-12-22 15:36:44 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -46,14 +46,10 @@ cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx)
|
||||
struct session *s;
|
||||
struct session_group *sg;
|
||||
char *tim, tmp[64];
|
||||
u_int i, idx;
|
||||
u_int idx;
|
||||
time_t t;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
s = ARRAY_ITEM(&sessions, i);
|
||||
if (s == NULL)
|
||||
continue;
|
||||
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
sg = session_group_find(s);
|
||||
if (sg == NULL)
|
||||
*tmp = '\0';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-list-windows.c,v 1.42 2009-11-14 17:56:39 tcunha Exp $ */
|
||||
/* $Id: cmd-list-windows.c,v 1.44 2010-12-06 21:56:32 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -45,13 +45,17 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
struct cmd_target_data *data = self->data;
|
||||
struct session *s;
|
||||
struct winlink *wl;
|
||||
char *layout;
|
||||
|
||||
if ((s = cmd_find_session(ctx, data->target)) == NULL)
|
||||
return (-1);
|
||||
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
ctx->print(ctx, "%d: %s [%ux%u]",
|
||||
wl->idx, wl->window->name, wl->window->sx, wl->window->sy);
|
||||
layout = layout_dump(wl->window);
|
||||
ctx->print(ctx, "%d: %s [%ux%u] [layout %s]%s",
|
||||
wl->idx, wl->window->name, wl->window->sx, wl->window->sy,
|
||||
layout, wl == s->curw ? " (active)" : "");
|
||||
xfree(layout);
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
46
cmd-list.c
46
cmd-list.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-list.c,v 1.7 2010-02-02 23:51:04 tcunha Exp $ */
|
||||
/* $Id: cmd-list.c,v 1.10 2010-12-06 21:48:56 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -29,47 +29,52 @@ cmd_list_parse(int argc, char **argv, char **cause)
|
||||
struct cmd *cmd;
|
||||
int i, lastsplit;
|
||||
size_t arglen, new_argc;
|
||||
char **new_argv;
|
||||
char **copy_argv, **new_argv;
|
||||
|
||||
copy_argv = cmd_copy_argv(argc, argv);
|
||||
|
||||
cmdlist = xmalloc(sizeof *cmdlist);
|
||||
TAILQ_INIT(cmdlist);
|
||||
cmdlist->references = 1;
|
||||
TAILQ_INIT(&cmdlist->list);
|
||||
|
||||
lastsplit = 0;
|
||||
for (i = 0; i < argc; i++) {
|
||||
arglen = strlen(argv[i]);
|
||||
if (arglen == 0 || argv[i][arglen - 1] != ';')
|
||||
arglen = strlen(copy_argv[i]);
|
||||
if (arglen == 0 || copy_argv[i][arglen - 1] != ';')
|
||||
continue;
|
||||
argv[i][arglen - 1] = '\0';
|
||||
copy_argv[i][arglen - 1] = '\0';
|
||||
|
||||
if (arglen > 1 && argv[i][arglen - 2] == '\\') {
|
||||
argv[i][arglen - 2] = ';';
|
||||
if (arglen > 1 && copy_argv[i][arglen - 2] == '\\') {
|
||||
copy_argv[i][arglen - 2] = ';';
|
||||
continue;
|
||||
}
|
||||
|
||||
new_argc = i - lastsplit;
|
||||
new_argv = argv + lastsplit;
|
||||
new_argv = copy_argv + lastsplit;
|
||||
if (arglen != 1)
|
||||
new_argc++;
|
||||
|
||||
cmd = cmd_parse(new_argc, new_argv, cause);
|
||||
if (cmd == NULL)
|
||||
goto bad;
|
||||
TAILQ_INSERT_TAIL(cmdlist, cmd, qentry);
|
||||
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
|
||||
|
||||
lastsplit = i + 1;
|
||||
}
|
||||
|
||||
if (lastsplit != argc) {
|
||||
cmd = cmd_parse(argc - lastsplit, argv + lastsplit, cause);
|
||||
cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit, cause);
|
||||
if (cmd == NULL)
|
||||
goto bad;
|
||||
TAILQ_INSERT_TAIL(cmdlist, cmd, qentry);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -80,7 +85,7 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx)
|
||||
int n, retval;
|
||||
|
||||
retval = 0;
|
||||
TAILQ_FOREACH(cmd, cmdlist, qentry) {
|
||||
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
|
||||
if ((n = cmd_exec(cmd, ctx)) == -1)
|
||||
return (-1);
|
||||
|
||||
@@ -99,6 +104,10 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx)
|
||||
if (ctx->curclient == NULL) {
|
||||
ctx->curclient = ctx->cmdclient;
|
||||
ctx->cmdclient = NULL;
|
||||
|
||||
ctx->error = key_bindings_error;
|
||||
ctx->print = key_bindings_print;
|
||||
ctx->info = key_bindings_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,9 +119,12 @@ cmd_list_free(struct cmd_list *cmdlist)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
|
||||
while (!TAILQ_EMPTY(cmdlist)) {
|
||||
cmd = TAILQ_FIRST(cmdlist);
|
||||
TAILQ_REMOVE(cmdlist, cmd, qentry);
|
||||
if (--cmdlist->references != 0)
|
||||
return;
|
||||
|
||||
while (!TAILQ_EMPTY(&cmdlist->list)) {
|
||||
cmd = TAILQ_FIRST(&cmdlist->list);
|
||||
TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
|
||||
cmd_free(cmd);
|
||||
}
|
||||
xfree(cmdlist);
|
||||
@@ -125,7 +137,7 @@ cmd_list_print(struct cmd_list *cmdlist, char *buf, size_t len)
|
||||
size_t off;
|
||||
|
||||
off = 0;
|
||||
TAILQ_FOREACH(cmd, cmdlist, qentry) {
|
||||
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
|
||||
if (off >= len)
|
||||
break;
|
||||
off += cmd_print(cmd, buf + off, len - off);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-load-buffer.c,v 1.15 2010-02-26 13:30:07 tcunha Exp $ */
|
||||
/* $Id: cmd-load-buffer.c,v 1.18 2010-12-22 15:28:50 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
@@ -16,10 +16,13 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
@@ -28,6 +31,7 @@
|
||||
*/
|
||||
|
||||
int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *);
|
||||
void cmd_load_buffer_callback(struct client *, void *);
|
||||
|
||||
const struct cmd_entry cmd_load_buffer_entry = {
|
||||
"load-buffer", "loadb",
|
||||
@@ -40,20 +44,53 @@ const struct cmd_entry cmd_load_buffer_entry = {
|
||||
cmd_buffer_print
|
||||
};
|
||||
|
||||
struct cmd_load_buffer_cdata {
|
||||
struct session *session;
|
||||
int buffer;
|
||||
};
|
||||
|
||||
int
|
||||
cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct cmd_buffer_data *data = self->data;
|
||||
struct session *s;
|
||||
FILE *f;
|
||||
char *pdata, *new_pdata;
|
||||
size_t psize;
|
||||
u_int limit;
|
||||
int ch;
|
||||
struct cmd_buffer_data *data = self->data;
|
||||
struct cmd_load_buffer_cdata *cdata;
|
||||
struct session *s;
|
||||
struct client *c = ctx->cmdclient;
|
||||
FILE *f;
|
||||
char *pdata, *new_pdata;
|
||||
size_t psize;
|
||||
u_int limit;
|
||||
int ch;
|
||||
|
||||
if ((s = cmd_find_session(ctx, data->target)) == NULL)
|
||||
return (-1);
|
||||
|
||||
if (strcmp(data->arg, "-") == 0) {
|
||||
if (c == NULL) {
|
||||
ctx->error(ctx, "%s: can't read from stdin", data->arg);
|
||||
return (-1);
|
||||
}
|
||||
if (c->flags & CLIENT_TERMINAL) {
|
||||
ctx->error(ctx, "%s: stdin is a tty", data->arg);
|
||||
return (-1);
|
||||
}
|
||||
if (c->stdin_fd == -1) {
|
||||
ctx->error(ctx, "%s: can't read from stdin", data->arg);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
cdata = xmalloc(sizeof *cdata);
|
||||
cdata->session = s;
|
||||
cdata->session->references++;
|
||||
cdata->buffer = data->buffer;
|
||||
c->stdin_data = cdata;
|
||||
c->stdin_callback = cmd_load_buffer_callback;
|
||||
|
||||
c->references++;
|
||||
bufferevent_enable(c->stdin_event, EV_READ);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if ((f = fopen(data->arg, "rb")) == NULL) {
|
||||
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
|
||||
return (-1);
|
||||
@@ -78,6 +115,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
pdata[psize] = '\0';
|
||||
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
|
||||
limit = options_get_number(&s->options, "buffer-limit");
|
||||
if (data->buffer == -1) {
|
||||
@@ -86,7 +124,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
}
|
||||
if (paste_replace(&s->buffers, data->buffer, pdata, psize) != 0) {
|
||||
ctx->error(ctx, "no buffer %d", data->buffer);
|
||||
goto error;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
@@ -94,6 +132,54 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
error:
|
||||
if (pdata != NULL)
|
||||
xfree(pdata);
|
||||
fclose(f);
|
||||
if (f != NULL)
|
||||
fclose(f);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_load_buffer_callback(struct client *c, void *data)
|
||||
{
|
||||
struct cmd_load_buffer_cdata *cdata = data;
|
||||
struct session *s = cdata->session;
|
||||
char *pdata;
|
||||
size_t psize;
|
||||
u_int limit;
|
||||
|
||||
/*
|
||||
* Event callback has already checked client is not dead and reduced
|
||||
* its reference count. But tell it to exit.
|
||||
*/
|
||||
c->flags |= CLIENT_EXIT;
|
||||
|
||||
/* Does the target session still exist? */
|
||||
if (!session_alive(s))
|
||||
goto out;
|
||||
|
||||
psize = EVBUFFER_LENGTH(c->stdin_event->input);
|
||||
if (psize == 0)
|
||||
goto out;
|
||||
|
||||
pdata = malloc(psize + 1);
|
||||
if (pdata == NULL)
|
||||
goto out;
|
||||
bufferevent_read(c->stdin_event, pdata, psize);
|
||||
pdata[psize] = '\0';
|
||||
|
||||
limit = options_get_number(&s->options, "buffer-limit");
|
||||
if (cdata->buffer == -1) {
|
||||
paste_add(&s->buffers, pdata, psize, limit);
|
||||
goto out;
|
||||
}
|
||||
if (paste_replace(&s->buffers, cdata->buffer, pdata, psize) != 0) {
|
||||
/* No context so can't use server_client_msg_error. */
|
||||
evbuffer_add_printf(
|
||||
c->stderr_event->output, "no buffer %d\n", cdata->buffer);
|
||||
bufferevent_enable(c->stderr_event, EV_WRITE);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
cdata->session->references--;
|
||||
xfree(cdata);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-new-session.c,v 1.76 2010-02-26 13:28:15 tcunha Exp $ */
|
||||
/* $Id: cmd-new-session.c,v 1.80 2010-12-22 15:31:00 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -18,8 +18,10 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <pwd.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
@@ -120,13 +122,14 @@ int
|
||||
cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct cmd_new_session_data *data = self->data;
|
||||
struct session *s, *groupwith;
|
||||
struct session *s, *old_s, *groupwith;
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
struct environ env;
|
||||
struct termios tio, *tiop;
|
||||
const char *update;
|
||||
char *overrides, *cmd, *cwd, *cause;
|
||||
struct passwd *pw;
|
||||
const char *update, *cwd;
|
||||
char *overrides, *cmd, *cause;
|
||||
int detached, idx;
|
||||
u_int sx, sy, i;
|
||||
|
||||
@@ -198,8 +201,13 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
/* Get the new session working directory. */
|
||||
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
|
||||
cwd = ctx->cmdclient->cwd;
|
||||
else
|
||||
cwd = options_get_string(&global_s_options, "default-path");
|
||||
else {
|
||||
pw = getpwuid(getuid());
|
||||
if (pw->pw_dir != NULL && *pw->pw_dir != '\0')
|
||||
cwd = pw->pw_dir;
|
||||
else
|
||||
cwd = "/";
|
||||
}
|
||||
|
||||
/* Find new session size. */
|
||||
if (detached) {
|
||||
@@ -271,9 +279,16 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
if (!detached) {
|
||||
if (ctx->cmdclient != NULL) {
|
||||
server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
|
||||
|
||||
old_s = ctx->cmdclient->session;
|
||||
if (old_s != NULL)
|
||||
ctx->cmdclient->last_session = old_s;
|
||||
ctx->cmdclient->session = s;
|
||||
server_redraw_client(ctx->cmdclient);
|
||||
} else {
|
||||
old_s = ctx->curclient->session;
|
||||
if (old_s != NULL)
|
||||
ctx->curclient->last_session = old_s;
|
||||
ctx->curclient->session = s;
|
||||
server_redraw_client(ctx->curclient);
|
||||
}
|
||||
@@ -287,10 +302,11 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
*/
|
||||
if (cfg_finished && !ARRAY_EMPTY(&cfg_causes)) {
|
||||
wp = s->curw->window->active;
|
||||
window_pane_set_mode(wp, &window_more_mode);
|
||||
window_pane_set_mode(wp, &window_copy_mode);
|
||||
window_copy_init_for_output(wp);
|
||||
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
|
||||
cause = ARRAY_ITEM(&cfg_causes, i);
|
||||
window_more_add(wp, "%s", cause);
|
||||
window_copy_add(wp, "%s", cause);
|
||||
xfree(cause);
|
||||
}
|
||||
ARRAY_FREE(&cfg_causes);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-new-window.c,v 1.43 2010-01-22 17:28:34 tcunha Exp $ */
|
||||
/* $Id: cmd-new-window.c,v 1.47 2010-07-02 02:49:19 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -36,13 +36,14 @@ struct cmd_new_window_data {
|
||||
char *target;
|
||||
char *name;
|
||||
char *cmd;
|
||||
int flag_insert_after;
|
||||
int flag_detached;
|
||||
int flag_kill;
|
||||
};
|
||||
|
||||
const struct cmd_entry cmd_new_window_entry = {
|
||||
"new-window", "neww",
|
||||
"[-dk] [-n window-name] [-t target-window] [command]",
|
||||
"[-adk] [-n window-name] [-t target-window] [command]",
|
||||
0, "",
|
||||
cmd_new_window_init,
|
||||
cmd_new_window_parse,
|
||||
@@ -61,6 +62,7 @@ cmd_new_window_init(struct cmd *self, unused int arg)
|
||||
data->target = NULL;
|
||||
data->name = NULL;
|
||||
data->cmd = NULL;
|
||||
data->flag_insert_after = 0;
|
||||
data->flag_detached = 0;
|
||||
data->flag_kill = 0;
|
||||
}
|
||||
@@ -74,8 +76,11 @@ cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause)
|
||||
self->entry->init(self, KEYC_NONE);
|
||||
data = self->data;
|
||||
|
||||
while ((opt = getopt(argc, argv, "dkt:n:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "adkt:n:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
data->flag_insert_after = 1;
|
||||
break;
|
||||
case 'd':
|
||||
data->flag_detached = 1;
|
||||
break;
|
||||
@@ -118,13 +123,36 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
struct session *s;
|
||||
struct winlink *wl;
|
||||
char *cmd, *cwd, *cause;
|
||||
int idx;
|
||||
int idx, last;
|
||||
|
||||
if (data == NULL)
|
||||
return (0);
|
||||
|
||||
if ((idx = cmd_find_index(ctx, data->target, &s)) == -2)
|
||||
return (-1);
|
||||
if (data->flag_insert_after) {
|
||||
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
|
||||
return (-1);
|
||||
idx = wl->idx + 1;
|
||||
|
||||
/* Find the next free index. */
|
||||
for (last = idx; last < INT_MAX; last++) {
|
||||
if (winlink_find_by_index(&s->windows, last) == NULL)
|
||||
break;
|
||||
}
|
||||
if (last == INT_MAX) {
|
||||
ctx->error(ctx, "no free window indexes");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Move everything from last - 1 to idx up a bit. */
|
||||
for (; last > idx; last--) {
|
||||
wl = winlink_find_by_index(&s->windows, last - 1);
|
||||
server_link_window(s, wl, s, last, 0, 0, NULL);
|
||||
server_unlink_window(s, wl);
|
||||
}
|
||||
} else {
|
||||
if ((idx = cmd_find_index(ctx, data->target, &s)) == -2)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
wl = NULL;
|
||||
if (idx != -1)
|
||||
@@ -134,7 +162,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
* Can't use session_detach as it will destroy session if this
|
||||
* makes it empty.
|
||||
*/
|
||||
session_alert_cancel(s, wl);
|
||||
wl->flags &= ~WINLINK_ALERTFLAGS;
|
||||
winlink_stack_remove(&s->lastw, wl);
|
||||
winlink_remove(&s->windows, wl);
|
||||
|
||||
@@ -148,10 +176,13 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
cmd = data->cmd;
|
||||
if (cmd == NULL)
|
||||
cmd = options_get_string(&s->options, "default-command");
|
||||
if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL)
|
||||
cwd = options_get_string(&s->options, "default-path");
|
||||
else
|
||||
cwd = ctx->cmdclient->cwd;
|
||||
cwd = options_get_string(&s->options, "default-path");
|
||||
if (*cwd == '\0') {
|
||||
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
|
||||
cwd = ctx->cmdclient->cwd;
|
||||
else
|
||||
cwd = s->cwd;
|
||||
}
|
||||
|
||||
if (idx == -1)
|
||||
idx = -1 - options_get_number(&s->options, "base-index");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-paste-buffer.c,v 1.24 2009-12-04 22:14:47 tcunha Exp $ */
|
||||
/* $Id: cmd-paste-buffer.c,v 1.29 2010-08-11 22:17:32 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
@@ -26,32 +27,112 @@
|
||||
* Paste paste buffer if present.
|
||||
*/
|
||||
|
||||
struct cmd_paste_buffer_data {
|
||||
char *target;
|
||||
int buffer;
|
||||
|
||||
int flag_delete;
|
||||
char *sepstr;
|
||||
};
|
||||
|
||||
void cmd_paste_buffer_init(struct cmd *, int);
|
||||
int cmd_paste_buffer_parse(struct cmd *, int, char **, char **);
|
||||
int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *);
|
||||
void cmd_paste_buffer_lf2cr(struct window_pane *, const char *, size_t);
|
||||
void cmd_paste_buffer_filter(
|
||||
struct window_pane *, const char *, size_t, char *);
|
||||
void cmd_paste_buffer_free(struct cmd *);
|
||||
size_t cmd_paste_buffer_print(struct cmd *, char *, size_t);
|
||||
|
||||
const struct cmd_entry cmd_paste_buffer_entry = {
|
||||
"paste-buffer", "pasteb",
|
||||
"[-dr] " CMD_BUFFER_WINDOW_USAGE,
|
||||
0, "dr",
|
||||
cmd_buffer_init,
|
||||
cmd_buffer_parse,
|
||||
"[-dr] [-s separator] [-b buffer-index] [-t target-pane]",
|
||||
0, "",
|
||||
cmd_paste_buffer_init,
|
||||
cmd_paste_buffer_parse,
|
||||
cmd_paste_buffer_exec,
|
||||
cmd_buffer_free,
|
||||
cmd_buffer_print
|
||||
cmd_paste_buffer_free,
|
||||
cmd_paste_buffer_print
|
||||
};
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
cmd_paste_buffer_init(struct cmd *self, unused int arg)
|
||||
{
|
||||
struct cmd_paste_buffer_data *data;
|
||||
|
||||
self->data = data = xmalloc(sizeof *data);
|
||||
data->target = NULL;
|
||||
data->buffer = -1;
|
||||
data->flag_delete = 0;
|
||||
data->sepstr = xstrdup("\r");
|
||||
}
|
||||
|
||||
int
|
||||
cmd_paste_buffer_parse(struct cmd *self, int argc, char **argv, char **cause)
|
||||
{
|
||||
struct cmd_paste_buffer_data *data;
|
||||
int opt, n;
|
||||
const char *errstr;
|
||||
|
||||
cmd_paste_buffer_init(self, 0);
|
||||
data = self->data;
|
||||
|
||||
while ((opt = getopt(argc, argv, "b:ds:t:r")) != -1) {
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
if (data->buffer == -1) {
|
||||
n = strtonum(optarg, 0, INT_MAX, &errstr);
|
||||
if (errstr != NULL) {
|
||||
xasprintf(cause, "buffer %s", errstr);
|
||||
goto error;
|
||||
}
|
||||
data->buffer = n;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
data->flag_delete = 1;
|
||||
break;
|
||||
case 's':
|
||||
if (data->sepstr != NULL)
|
||||
xfree(data->sepstr);
|
||||
data->sepstr = xstrdup(optarg);
|
||||
break;
|
||||
case 't':
|
||||
if (data->target == NULL)
|
||||
data->target = xstrdup(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
if (data->sepstr != NULL)
|
||||
xfree(data->sepstr);
|
||||
data->sepstr = xstrdup("\n");
|
||||
break;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
return (0);
|
||||
|
||||
usage:
|
||||
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
|
||||
|
||||
error:
|
||||
self->entry->free(self);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int
|
||||
cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct cmd_buffer_data *data = self->data;
|
||||
struct winlink *wl;
|
||||
struct window_pane *wp;
|
||||
struct session *s;
|
||||
struct paste_buffer *pb;
|
||||
struct cmd_paste_buffer_data *data = self->data;
|
||||
struct window_pane *wp;
|
||||
struct session *s;
|
||||
struct paste_buffer *pb;
|
||||
|
||||
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
|
||||
if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL)
|
||||
return (-1);
|
||||
wp = wl->window->active;
|
||||
|
||||
if (data->buffer == -1)
|
||||
pb = paste_get_top(&s->buffers);
|
||||
@@ -62,16 +143,11 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
if (pb != NULL) {
|
||||
/* -r means raw data without LF->CR conversion. */
|
||||
if (cmd_check_flag(data->chflags, 'r'))
|
||||
bufferevent_write(wp->event, pb->data, pb->size);
|
||||
else
|
||||
cmd_paste_buffer_lf2cr(wp, pb->data, pb->size);
|
||||
}
|
||||
if (pb != NULL)
|
||||
cmd_paste_buffer_filter(wp, pb->data, pb->size, data->sepstr);
|
||||
|
||||
/* Delete the buffer if -d. */
|
||||
if (cmd_check_flag(data->chflags, 'd')) {
|
||||
if (data->flag_delete) {
|
||||
if (data->buffer == -1)
|
||||
paste_free_top(&s->buffers);
|
||||
else
|
||||
@@ -81,20 +157,66 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Add bytes to a buffer but change every '\n' to '\r'. */
|
||||
/* Add bytes to a buffer and filter '\n' according to separator. */
|
||||
void
|
||||
cmd_paste_buffer_lf2cr(struct window_pane *wp, const char *data, size_t size)
|
||||
cmd_paste_buffer_filter(
|
||||
struct window_pane *wp, const char *data, size_t size, char *sep)
|
||||
{
|
||||
const char *end = data + size;
|
||||
const char *lf;
|
||||
size_t seplen;
|
||||
|
||||
seplen = strlen(sep);
|
||||
while ((lf = memchr(data, '\n', end - data)) != NULL) {
|
||||
if (lf != data)
|
||||
bufferevent_write(wp->event, data, lf - data);
|
||||
bufferevent_write(wp->event, "\r", 1);
|
||||
bufferevent_write(wp->event, sep, seplen);
|
||||
data = lf + 1;
|
||||
}
|
||||
|
||||
if (end != data)
|
||||
bufferevent_write(wp->event, data, end - data);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_paste_buffer_free(struct cmd *self)
|
||||
{
|
||||
struct cmd_paste_buffer_data *data = self->data;
|
||||
|
||||
if (data->target != NULL)
|
||||
xfree(data->target);
|
||||
if (data->sepstr != NULL)
|
||||
xfree(data->sepstr);
|
||||
xfree(data);
|
||||
}
|
||||
|
||||
size_t
|
||||
cmd_paste_buffer_print(struct cmd *self, char *buf, size_t len)
|
||||
{
|
||||
struct cmd_paste_buffer_data *data = self->data;
|
||||
size_t off = 0;
|
||||
char tmp[BUFSIZ];
|
||||
int r_flag;
|
||||
|
||||
r_flag = 0;
|
||||
if (data->sepstr != NULL)
|
||||
r_flag = (data->sepstr[0] == '\n' && data->sepstr[1] == '\0');
|
||||
|
||||
off += xsnprintf(buf, len, "%s", self->entry->name);
|
||||
if (data == NULL)
|
||||
return (off);
|
||||
if (off < len && data->flag_delete)
|
||||
off += xsnprintf(buf + off, len - off, " -d");
|
||||
if (off < len && r_flag)
|
||||
off += xsnprintf(buf + off, len - off, " -r");
|
||||
if (off < len && data->buffer != -1)
|
||||
off += xsnprintf(buf + off, len - off, " -b %d", data->buffer);
|
||||
if (off < len && data->sepstr != NULL && !r_flag) {
|
||||
strnvis(
|
||||
tmp, data->sepstr, sizeof tmp, VIS_OCTAL|VIS_TAB|VIS_NL);
|
||||
off += cmd_prarg(buf + off, len - off, " -s ", tmp);
|
||||
}
|
||||
if (off < len && data->target != NULL)
|
||||
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
|
||||
return (off);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-pipe-pane.c,v 1.10 2009-12-04 22:14:47 tcunha Exp $ */
|
||||
/* $Id: cmd-pipe-pane.c,v 1.15 2010-10-24 00:45:57 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
@@ -49,9 +50,14 @@ int
|
||||
cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct cmd_target_data *data = self->data;
|
||||
struct client *c;
|
||||
struct window_pane *wp;
|
||||
char *command;
|
||||
int old_fd, pipe_fd[2], null_fd, mode;
|
||||
|
||||
if ((c = cmd_find_client(ctx, NULL)) == NULL)
|
||||
return (-1);
|
||||
|
||||
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
|
||||
return (-1);
|
||||
|
||||
@@ -90,7 +96,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
case 0:
|
||||
/* Child process. */
|
||||
close(pipe_fd[0]);
|
||||
server_signal_clear();
|
||||
clear_signals(1);
|
||||
|
||||
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
|
||||
_exit(1);
|
||||
@@ -105,7 +111,10 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO)
|
||||
close(null_fd);
|
||||
|
||||
execl(_PATH_BSHELL, "sh", "-c", data->arg, (char *) NULL);
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
|
||||
command = status_replace(c, NULL, data->arg, time(NULL), 0);
|
||||
execl(_PATH_BSHELL, "sh", "-c", command, (char *) NULL);
|
||||
_exit(1);
|
||||
default:
|
||||
/* Parent process. */
|
||||
@@ -122,8 +131,6 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
fatal("fcntl failed");
|
||||
if (fcntl(wp->pipe_fd, F_SETFL, mode|O_NONBLOCK) == -1)
|
||||
fatal("fcntl failed");
|
||||
if (fcntl(wp->pipe_fd, F_SETFD, FD_CLOEXEC) == -1)
|
||||
fatal("fcntl failed");
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-rename-session.c,v 1.19 2009-11-14 17:56:39 tcunha Exp $ */
|
||||
/* $Id: cmd-rename-session.c,v 1.21 2010-12-22 15:36:44 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -45,11 +45,18 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
struct cmd_target_data *data = self->data;
|
||||
struct session *s;
|
||||
|
||||
if (data->arg != NULL && session_find(data->arg) != NULL) {
|
||||
ctx->error(ctx, "duplicate session: %s", data->arg);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((s = cmd_find_session(ctx, data->target)) == NULL)
|
||||
return (-1);
|
||||
|
||||
RB_REMOVE(sessions, &sessions, s);
|
||||
xfree(s->name);
|
||||
s->name = xstrdup(data->arg);
|
||||
RB_INSERT(sessions, &sessions, s);
|
||||
|
||||
server_status_session(s);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-run-shell.c,v 1.6 2009-11-14 17:56:39 tcunha Exp $ */
|
||||
/* $Id: cmd-run-shell.c,v 1.9 2010-08-09 21:44:25 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
@@ -82,6 +82,11 @@ cmd_run_shell_callback(struct job *job)
|
||||
int retcode;
|
||||
u_int lines;
|
||||
|
||||
if (ctx->cmdclient != NULL && ctx->cmdclient->flags & CLIENT_DEAD)
|
||||
return;
|
||||
if (ctx->curclient != NULL && ctx->curclient->flags & CLIENT_DEAD)
|
||||
return;
|
||||
|
||||
lines = 0;
|
||||
do {
|
||||
if ((line = evbuffer_readline(job->event->input)) != NULL) {
|
||||
@@ -129,7 +134,7 @@ cmd_run_shell_free(void *data)
|
||||
|
||||
if (ctx->cmdclient != NULL) {
|
||||
ctx->cmdclient->references--;
|
||||
server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0);
|
||||
ctx->cmdclient->flags |= CLIENT_EXIT;
|
||||
}
|
||||
if (ctx->curclient != NULL)
|
||||
ctx->curclient->references--;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-save-buffer.c,v 1.10 2009-11-14 17:56:39 tcunha Exp $ */
|
||||
/* $Id: cmd-save-buffer.c,v 1.12 2010-08-09 21:44:25 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
@@ -47,7 +47,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
struct cmd_buffer_data *data = self->data;
|
||||
struct session *s;
|
||||
struct paste_buffer *pb;
|
||||
mode_t mask;
|
||||
mode_t mask;
|
||||
FILE *f;
|
||||
|
||||
if ((s = cmd_find_session(ctx, data->target)) == NULL)
|
||||
@@ -65,24 +65,31 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
mask = umask(S_IRWXG | S_IRWXO);
|
||||
if (cmd_check_flag(data->chflags, 'a'))
|
||||
f = fopen(data->arg, "ab");
|
||||
else
|
||||
f = fopen(data->arg, "wb");
|
||||
umask(mask);
|
||||
if (f == NULL) {
|
||||
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
|
||||
return (-1);
|
||||
if (strcmp(data->arg, "-") == 0) {
|
||||
if (ctx->cmdclient == NULL) {
|
||||
ctx->error(ctx, "%s: can't write to stdout", data->arg);
|
||||
return (-1);
|
||||
}
|
||||
bufferevent_write(
|
||||
ctx->cmdclient->stdout_event, pb->data, pb->size);
|
||||
} else {
|
||||
mask = umask(S_IRWXG | S_IRWXO);
|
||||
if (cmd_check_flag(data->chflags, 'a'))
|
||||
f = fopen(data->arg, "ab");
|
||||
else
|
||||
f = fopen(data->arg, "wb");
|
||||
umask(mask);
|
||||
if (f == NULL) {
|
||||
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
|
||||
ctx->error(ctx, "%s: fwrite error", data->arg);
|
||||
fclose(f);
|
||||
return (-1);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
|
||||
ctx->error(ctx, "%s: fwrite error", data->arg);
|
||||
fclose(f);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-select-layout.c,v 1.10 2009-12-04 22:14:47 tcunha Exp $ */
|
||||
/* $Id: cmd-select-layout.c,v 1.12 2010-07-02 02:54:52 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -59,6 +59,9 @@ cmd_select_layout_init(struct cmd *self, int key)
|
||||
case ('4' | KEYC_ESCAPE):
|
||||
data->arg = xstrdup("main-vertical");
|
||||
break;
|
||||
case ('5' | KEYC_ESCAPE):
|
||||
data->arg = xstrdup("tiled");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,13 +79,16 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
layout = wl->window->lastlayout;
|
||||
if (layout == -1)
|
||||
return (0);
|
||||
} else if ((layout = layout_set_lookup(data->arg)) == -1) {
|
||||
ctx->error(ctx, "unknown layout or ambiguous: %s", data->arg);
|
||||
return (-1);
|
||||
} else if ((layout = layout_set_lookup(data->arg)) != -1) {
|
||||
layout = layout_set_select(wl->window, layout);
|
||||
ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
|
||||
} else {
|
||||
if (layout_parse(wl->window, data->arg) == -1) {
|
||||
ctx->error(ctx, "can't set layout: %s", data->arg);
|
||||
return (-1);
|
||||
}
|
||||
ctx->info(ctx, "arranging in: %s", data->arg);
|
||||
}
|
||||
|
||||
layout = layout_set_select(wl->window, layout);
|
||||
ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-select-pane.c,v 1.12 2010-01-05 23:52:37 tcunha Exp $ */
|
||||
/* $Id: cmd-select-pane.c,v 1.13 2010-03-15 22:03:38 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -24,19 +24,40 @@
|
||||
* Select pane.
|
||||
*/
|
||||
|
||||
void cmd_select_pane_init(struct cmd *, int);
|
||||
int cmd_select_pane_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
const struct cmd_entry cmd_select_pane_entry = {
|
||||
"select-pane", "selectp",
|
||||
CMD_TARGET_PANE_USAGE,
|
||||
0, "",
|
||||
cmd_target_init,
|
||||
"[-DLRU] " CMD_TARGET_PANE_USAGE,
|
||||
0, "DLRU",
|
||||
cmd_select_pane_init,
|
||||
cmd_target_parse,
|
||||
cmd_select_pane_exec,
|
||||
cmd_target_free,
|
||||
cmd_target_print
|
||||
};
|
||||
|
||||
void
|
||||
cmd_select_pane_init(struct cmd *self, int key)
|
||||
{
|
||||
struct cmd_target_data *data;
|
||||
|
||||
cmd_target_init(self, key);
|
||||
data = self->data;
|
||||
|
||||
if (key == KEYC_UP)
|
||||
cmd_set_flag(&data->chflags, 'U');
|
||||
if (key == KEYC_DOWN)
|
||||
cmd_set_flag(&data->chflags, 'D');
|
||||
if (key == KEYC_LEFT)
|
||||
cmd_set_flag(&data->chflags, 'L');
|
||||
if (key == KEYC_RIGHT)
|
||||
cmd_set_flag(&data->chflags, 'R');
|
||||
if (key == 'o')
|
||||
data->target = xstrdup(":.+");
|
||||
}
|
||||
|
||||
int
|
||||
cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
@@ -51,6 +72,20 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
ctx->error(ctx, "pane not visible: %s", data->target);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (cmd_check_flag(data->chflags, 'L'))
|
||||
wp = window_pane_find_left(wp);
|
||||
else if (cmd_check_flag(data->chflags, 'R'))
|
||||
wp = window_pane_find_right(wp);
|
||||
else if (cmd_check_flag(data->chflags, 'U'))
|
||||
wp = window_pane_find_up(wp);
|
||||
else if (cmd_check_flag(data->chflags, 'D'))
|
||||
wp = window_pane_find_down(wp);
|
||||
if (wp == NULL) {
|
||||
ctx->error(ctx, "pane not found");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
window_set_active_pane(wl->window, wp);
|
||||
server_status_window(wl->window);
|
||||
server_redraw_window_borders(wl->window);
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
/* $Id: cmd-select-prompt.c,v 1.13 2009-11-14 17:56:39 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF 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 "tmux.h"
|
||||
|
||||
/*
|
||||
* Prompt for window index and select it.
|
||||
*/
|
||||
|
||||
int cmd_select_prompt_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
int cmd_select_prompt_callback(void *, const char *);
|
||||
|
||||
const struct cmd_entry cmd_select_prompt_entry = {
|
||||
"select-prompt", NULL,
|
||||
CMD_TARGET_CLIENT_USAGE,
|
||||
0, "",
|
||||
cmd_target_init,
|
||||
cmd_target_parse,
|
||||
cmd_select_prompt_exec,
|
||||
cmd_target_free,
|
||||
cmd_target_print
|
||||
};
|
||||
|
||||
int
|
||||
cmd_select_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct cmd_target_data *data = self->data;
|
||||
struct client *c;
|
||||
|
||||
if ((c = cmd_find_client(ctx, data->target)) == NULL)
|
||||
return (-1);
|
||||
|
||||
if (c->prompt_string != NULL)
|
||||
return (0);
|
||||
|
||||
status_prompt_set(c, "index ", cmd_select_prompt_callback, NULL, c, 0);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
cmd_select_prompt_callback(void *data, const char *s)
|
||||
{
|
||||
struct client *c = data;
|
||||
const char *errstr;
|
||||
char msg[128];
|
||||
u_int idx;
|
||||
|
||||
if (s == NULL || *s == '\0')
|
||||
return (0);
|
||||
|
||||
idx = strtonum(s, 0, UINT_MAX, &errstr);
|
||||
if (errstr != NULL) {
|
||||
xsnprintf(msg, sizeof msg, "Index %s: %s", errstr, s);
|
||||
status_message_set(c, "%s", msg);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (winlink_find_by_index(&c->session->windows, idx) == NULL) {
|
||||
xsnprintf(msg, sizeof msg,
|
||||
"Window not found: %s:%d", c->session->name, idx);
|
||||
status_message_set(c, "%s", msg);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (session_select(c->session, idx) == 0)
|
||||
server_redraw_session(c->session);
|
||||
recalculate_sizes();
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-send-keys.c,v 1.24 2009-12-04 22:14:47 tcunha Exp $ */
|
||||
/* $Id: cmd-send-keys.c,v 1.25 2010-05-22 21:56:04 micahcowan Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -105,16 +105,17 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct cmd_send_keys_data *data = self->data;
|
||||
struct window_pane *wp;
|
||||
struct session *s;
|
||||
u_int i;
|
||||
|
||||
if (data == NULL)
|
||||
return (-1);
|
||||
|
||||
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
|
||||
if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL)
|
||||
return (-1);
|
||||
|
||||
for (i = 0; i < data->nkeys; i++)
|
||||
window_pane_key(wp, ctx->curclient, data->keys[i]);
|
||||
window_pane_key(wp, s, data->keys[i]);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-send-prefix.c,v 1.28 2009-11-14 17:56:39 tcunha Exp $ */
|
||||
/* $Id: cmd-send-prefix.c,v 1.29 2010-05-22 21:56:04 micahcowan Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -49,7 +49,7 @@ cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
return (-1);
|
||||
|
||||
keylist = options_get_data(&s->options, "prefix");
|
||||
window_pane_key(wp, ctx->curclient, ARRAY_FIRST(keylist));
|
||||
window_pane_key(wp, s, ARRAY_FIRST(keylist));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-server-info.c,v 1.37 2009-12-10 16:59:02 tcunha Exp $ */
|
||||
/* $Id: cmd-server-info.c,v 1.38 2010-12-22 15:36:44 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -81,8 +81,6 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
|
||||
else
|
||||
ctx->print(ctx, "configuration file not specified");
|
||||
ctx->print(ctx, "protocol version is %d", PROTOCOL_VERSION);
|
||||
ctx->print(ctx, "%u clients, %u sessions",
|
||||
ARRAY_LENGTH(&clients), ARRAY_LENGTH(&sessions));
|
||||
ctx->print(ctx, "%s", "");
|
||||
|
||||
ctx->print(ctx, "Clients:");
|
||||
@@ -101,19 +99,14 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
|
||||
|
||||
ctx->print(ctx, "Sessions: [%zu/%zu]",
|
||||
sizeof (struct grid_cell), sizeof (struct grid_utf8));
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
s = ARRAY_ITEM(&sessions, i);
|
||||
if (s == NULL)
|
||||
continue;
|
||||
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
t = s->creation_time.tv_sec;
|
||||
tim = ctime(&t);
|
||||
*strchr(tim, '\n') = '\0';
|
||||
|
||||
ctx->print(ctx, "%2u: %s: %u windows (created %s) [%ux%u] "
|
||||
"[flags=0x%x, references=%u]", i, s->name,
|
||||
winlink_count(&s->windows), tim, s->sx, s->sy, s->flags,
|
||||
s->references);
|
||||
"[flags=0x%x]", s->idx, s->name,
|
||||
winlink_count(&s->windows), tim, s->sx, s->sy, s->flags);
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
w = wl->window;
|
||||
ctx->print(ctx, "%4u: %s [%ux%u] [flags=0x%x, "
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-set-option.c,v 1.96 2010-02-26 13:31:39 tcunha Exp $ */
|
||||
/* $Id: cmd-set-option.c,v 1.102 2010-12-22 15:23:59 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -75,6 +75,7 @@ const char *set_option_bell_action_list[] = {
|
||||
|
||||
const struct set_option_entry set_option_table[] = {
|
||||
{ "escape-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
|
||||
{ "exit-unattached", SET_OPTION_FLAG, 0, 0, NULL },
|
||||
{ "quiet", SET_OPTION_FLAG, 0, 0, NULL },
|
||||
{ NULL, 0, 0, 0, NULL }
|
||||
};
|
||||
@@ -87,6 +88,8 @@ const struct set_option_entry set_session_option_table[] = {
|
||||
{ "default-path", SET_OPTION_STRING, 0, 0, NULL },
|
||||
{ "default-shell", SET_OPTION_STRING, 0, 0, NULL },
|
||||
{ "default-terminal", SET_OPTION_STRING, 0, 0, NULL },
|
||||
{ "destroy-unattached", SET_OPTION_FLAG, 0, 0, NULL },
|
||||
{ "detach-on-destroy", SET_OPTION_FLAG, 0, 0, NULL },
|
||||
{ "display-panes-colour", SET_OPTION_COLOUR, 0, 0, NULL },
|
||||
{ "display-panes-active-colour", SET_OPTION_COLOUR, 0, 0, NULL },
|
||||
{ "display-panes-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL },
|
||||
@@ -133,6 +136,7 @@ const struct set_option_entry set_session_option_table[] = {
|
||||
{ "visual-activity", SET_OPTION_FLAG, 0, 0, NULL },
|
||||
{ "visual-bell", SET_OPTION_FLAG, 0, 0, NULL },
|
||||
{ "visual-content", SET_OPTION_FLAG, 0, 0, NULL },
|
||||
{ "visual-silence", SET_OPTION_FLAG, 0, 0, NULL },
|
||||
{ NULL, 0, 0, 0, NULL }
|
||||
};
|
||||
|
||||
@@ -154,9 +158,15 @@ const struct set_option_entry set_window_option_table[] = {
|
||||
{ "mode-mouse", SET_OPTION_FLAG, 0, 0, NULL },
|
||||
{ "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL },
|
||||
{ "monitor-content", SET_OPTION_STRING, 0, 0, NULL },
|
||||
{ "monitor-silence",SET_OPTION_NUMBER, 0, INT_MAX, NULL},
|
||||
{ "other-pane-height", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
|
||||
{ "other-pane-width", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
|
||||
{ "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL },
|
||||
{ "synchronize-panes", SET_OPTION_FLAG, 0, 0, NULL },
|
||||
{ "utf8", SET_OPTION_FLAG, 0, 0, NULL },
|
||||
{ "window-status-alert-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
|
||||
{ "window-status-alert-bg", SET_OPTION_COLOUR, 0, 0, NULL },
|
||||
{ "window-status-alert-fg", SET_OPTION_COLOUR, 0, 0, NULL },
|
||||
{ "window-status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
|
||||
{ "window-status-bg", SET_OPTION_COLOUR, 0, 0, NULL },
|
||||
{ "window-status-current-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
|
||||
@@ -289,6 +299,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
*/
|
||||
if (strcmp(entry->name, "status-left") == 0 ||
|
||||
strcmp(entry->name, "status-right") == 0 ||
|
||||
strcmp(entry->name, "status") == 0 ||
|
||||
strcmp(entry->name, "set-titles-string") == 0 ||
|
||||
strcmp(entry->name, "window-status-format") == 0) {
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-split-window.c,v 1.34 2010-01-08 16:31:35 tcunha Exp $ */
|
||||
/* $Id: cmd-split-window.c,v 1.35 2010-07-02 02:49:19 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -169,10 +169,13 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
cmd = data->cmd;
|
||||
if (cmd == NULL)
|
||||
cmd = options_get_string(&s->options, "default-command");
|
||||
if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL)
|
||||
cwd = options_get_string(&s->options, "default-path");
|
||||
else
|
||||
cwd = ctx->cmdclient->cwd;
|
||||
cwd = options_get_string(&s->options, "default-path");
|
||||
if (*cwd == '\0') {
|
||||
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
|
||||
cwd = ctx->cmdclient->cwd;
|
||||
else
|
||||
cwd = s->cwd;
|
||||
}
|
||||
|
||||
type = LAYOUT_TOPBOTTOM;
|
||||
if (data->flag_horizontal)
|
||||
|
||||
32
cmd-string.c
32
cmd-string.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-string.c,v 1.31 2010-02-26 13:27:38 tcunha Exp $ */
|
||||
/* $Id: cmd-string.c,v 1.32 2010-12-13 22:53:56 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -247,9 +247,10 @@ error:
|
||||
char *
|
||||
cmd_string_variable(const char *s, size_t *p)
|
||||
{
|
||||
int ch, fch;
|
||||
char *buf, *t;
|
||||
size_t len;
|
||||
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'))
|
||||
@@ -301,12 +302,11 @@ cmd_string_variable(const char *s, size_t *p)
|
||||
buf = xrealloc(buf, 1, len + 1);
|
||||
buf[len] = '\0';
|
||||
|
||||
if ((t = getenv(buf)) == NULL) {
|
||||
xfree(buf);
|
||||
return (xstrdup(""));
|
||||
}
|
||||
envent = environ_find(&global_environ, buf);
|
||||
xfree(buf);
|
||||
return (xstrdup(t));
|
||||
if (envent == NULL)
|
||||
return (xstrdup(""));
|
||||
return (xstrdup(envent->value));
|
||||
|
||||
error:
|
||||
if (buf != NULL)
|
||||
@@ -317,15 +317,17 @@ error:
|
||||
char *
|
||||
cmd_string_expand_tilde(const char *s, size_t *p)
|
||||
{
|
||||
struct passwd *pw;
|
||||
char *home, *path, *username;
|
||||
struct passwd *pw;
|
||||
struct environ_entry *envent;
|
||||
char *home, *path, *username;
|
||||
|
||||
home = NULL;
|
||||
if (cmd_string_getc(s, p) == '/') {
|
||||
if ((home = getenv("HOME")) == NULL || *home == '\0') {
|
||||
if ((pw = getpwuid(getuid())) != NULL)
|
||||
home = pw->pw_dir;
|
||||
}
|
||||
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);
|
||||
if ((username = cmd_string_string(s, p, '/', 0)) == NULL)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-switch-client.c,v 1.19 2010-01-25 17:12:44 tcunha Exp $ */
|
||||
/* $Id: cmd-switch-client.c,v 1.23 2010-12-22 15:31:00 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -27,6 +27,7 @@
|
||||
* Switch client to a different session.
|
||||
*/
|
||||
|
||||
void cmd_switch_client_init(struct cmd *, int);
|
||||
int cmd_switch_client_parse(struct cmd *, int, char **, char **);
|
||||
int cmd_switch_client_exec(struct cmd *, struct cmd_ctx *);
|
||||
void cmd_switch_client_free(struct cmd *);
|
||||
@@ -35,36 +36,83 @@ size_t cmd_switch_client_print(struct cmd *, char *, size_t);
|
||||
struct cmd_switch_client_data {
|
||||
char *name;
|
||||
char *target;
|
||||
int flag_last;
|
||||
int flag_next;
|
||||
int flag_previous;
|
||||
};
|
||||
|
||||
const struct cmd_entry cmd_switch_client_entry = {
|
||||
"switch-client", "switchc",
|
||||
"[-c target-client] [-t target-session]",
|
||||
"[-lnp] [-c target-client] [-t target-session]",
|
||||
0, "",
|
||||
NULL,
|
||||
cmd_switch_client_init,
|
||||
cmd_switch_client_parse,
|
||||
cmd_switch_client_exec,
|
||||
cmd_switch_client_free,
|
||||
cmd_switch_client_print
|
||||
};
|
||||
|
||||
void
|
||||
cmd_switch_client_init(struct cmd *self, int key)
|
||||
{
|
||||
struct cmd_switch_client_data *data;
|
||||
|
||||
self->data = data = xmalloc(sizeof *data);
|
||||
data->name = NULL;
|
||||
data->target = NULL;
|
||||
data->flag_last = 0;
|
||||
data->flag_next = 0;
|
||||
data->flag_previous = 0;
|
||||
|
||||
switch (key) {
|
||||
case '(':
|
||||
data->flag_previous = 1;
|
||||
break;
|
||||
case ')':
|
||||
data->flag_next = 1;
|
||||
break;
|
||||
case 'L':
|
||||
data->flag_last = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
cmd_switch_client_parse(struct cmd *self, int argc, char **argv, char **cause)
|
||||
{
|
||||
struct cmd_switch_client_data *data;
|
||||
int opt;
|
||||
|
||||
self->data = data = xmalloc(sizeof *data);
|
||||
data->name = NULL;
|
||||
data->target = NULL;
|
||||
self->entry->init(self, KEYC_NONE);
|
||||
data = self->data;
|
||||
|
||||
while ((opt = getopt(argc, argv, "c:t:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "c:lnpt:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
if (data->name == NULL)
|
||||
data->name = xstrdup(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
if (data->flag_next || data->flag_previous ||
|
||||
data->target != NULL)
|
||||
goto usage;
|
||||
data->flag_last = 1;
|
||||
break;
|
||||
case 'n':
|
||||
if (data->flag_previous || data->flag_last ||
|
||||
data->target != NULL)
|
||||
goto usage;
|
||||
data->flag_next = 1;
|
||||
break;
|
||||
case 'p':
|
||||
if (data->flag_next || data->flag_last ||
|
||||
data->target != NULL)
|
||||
goto usage;
|
||||
data->flag_next = 1;
|
||||
break;
|
||||
case 't':
|
||||
if (data->flag_next || data->flag_previous)
|
||||
goto usage;
|
||||
if (data->target == NULL)
|
||||
data->target = xstrdup(optarg);
|
||||
break;
|
||||
@@ -98,12 +146,36 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
|
||||
if ((c = cmd_find_client(ctx, data->name)) == NULL)
|
||||
return (-1);
|
||||
if ((s = cmd_find_session(ctx, data->target)) == NULL)
|
||||
|
||||
s = NULL;
|
||||
if (data->flag_next) {
|
||||
if ((s = session_next_session(c->session)) == NULL) {
|
||||
ctx->error(ctx, "can't find next session");
|
||||
return (-1);
|
||||
}
|
||||
} else if (data->flag_previous) {
|
||||
if ((s = session_previous_session(c->session)) == NULL) {
|
||||
ctx->error(ctx, "can't find previous session");
|
||||
return (-1);
|
||||
}
|
||||
} else if (data->flag_last) {
|
||||
if (c->last_session != NULL && session_alive(c->last_session))
|
||||
s = c->last_session;
|
||||
if (s == NULL) {
|
||||
ctx->error(ctx, "can't find last session");
|
||||
return (-1);
|
||||
}
|
||||
} else
|
||||
s = cmd_find_session(ctx, data->target);
|
||||
if (s == NULL)
|
||||
return (-1);
|
||||
|
||||
if (c->session != NULL)
|
||||
c->last_session = c->session;
|
||||
c->session = s;
|
||||
|
||||
recalculate_sizes();
|
||||
server_check_unattached();
|
||||
server_redraw_client(c);
|
||||
|
||||
return (0);
|
||||
@@ -130,6 +202,12 @@ cmd_switch_client_print(struct cmd *self, char *buf, size_t len)
|
||||
off += xsnprintf(buf, len, "%s", self->entry->name);
|
||||
if (data == NULL)
|
||||
return (off);
|
||||
if (off < len && data->flag_last)
|
||||
off += xsnprintf(buf + off, len - off, "%s", " -l");
|
||||
if (off < len && data->flag_next)
|
||||
off += xsnprintf(buf + off, len - off, "%s", " -n");
|
||||
if (off < len && data->flag_previous)
|
||||
off += xsnprintf(buf + off, len - off, "%s", " -p");
|
||||
if (off < len && data->name != NULL)
|
||||
off += cmd_prarg(buf + off, len - off, " -c ", data->name);
|
||||
if (off < len && data->target != NULL)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-unbind-key.c,v 1.22 2010-01-25 17:12:44 tcunha Exp $ */
|
||||
/* $Id: cmd-unbind-key.c,v 1.23 2010-12-06 21:51:02 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -33,13 +33,14 @@ int cmd_unbind_key_table(struct cmd *, struct cmd_ctx *);
|
||||
struct cmd_unbind_key_data {
|
||||
int key;
|
||||
|
||||
int flag_all;
|
||||
int command_key;
|
||||
char *tablename;
|
||||
};
|
||||
|
||||
const struct cmd_entry cmd_unbind_key_entry = {
|
||||
"unbind-key", "unbind",
|
||||
"[-cn] [-t key-table] key",
|
||||
"[-acn] [-t key-table] key",
|
||||
0, "",
|
||||
NULL,
|
||||
cmd_unbind_key_parse,
|
||||
@@ -55,11 +56,15 @@ cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause)
|
||||
int opt, no_prefix = 0;
|
||||
|
||||
self->data = data = xmalloc(sizeof *data);
|
||||
data->flag_all = 0;
|
||||
data->command_key = 0;
|
||||
data->tablename = NULL;
|
||||
|
||||
while ((opt = getopt(argc, argv, "cnt:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "acnt:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
data->flag_all = 1;
|
||||
break;
|
||||
case 'c':
|
||||
data->command_key = 1;
|
||||
break;
|
||||
@@ -76,15 +81,20 @@ cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause)
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if (argc != 1)
|
||||
if (data->flag_all && (argc != 0 || data->tablename))
|
||||
goto usage;
|
||||
if (!data->flag_all && argc != 1)
|
||||
goto usage;
|
||||
|
||||
if ((data->key = key_string_lookup_string(argv[0])) == KEYC_NONE) {
|
||||
xasprintf(cause, "unknown key: %s", argv[0]);
|
||||
goto error;
|
||||
if (!data->flag_all) {
|
||||
data->key = key_string_lookup_string(argv[0]);
|
||||
if (data->key == KEYC_NONE) {
|
||||
xasprintf(cause, "unknown key: %s", argv[0]);
|
||||
goto error;
|
||||
}
|
||||
if (!no_prefix)
|
||||
data->key |= KEYC_PREFIX;
|
||||
}
|
||||
if (!no_prefix)
|
||||
data->key |= KEYC_PREFIX;
|
||||
|
||||
return (0);
|
||||
|
||||
@@ -100,13 +110,23 @@ int
|
||||
cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
|
||||
{
|
||||
struct cmd_unbind_key_data *data = self->data;
|
||||
struct key_binding *bd;
|
||||
|
||||
if (data == NULL)
|
||||
return (0);
|
||||
if (data->tablename != NULL)
|
||||
return (cmd_unbind_key_table(self, ctx));
|
||||
if (data->flag_all) {
|
||||
while (!SPLAY_EMPTY(&key_bindings)) {
|
||||
bd = SPLAY_ROOT(&key_bindings);
|
||||
SPLAY_REMOVE(key_bindings, &key_bindings, bd);
|
||||
cmd_list_free(bd->cmdlist);
|
||||
xfree(bd);
|
||||
}
|
||||
} else {
|
||||
if (data->tablename != NULL)
|
||||
return (cmd_unbind_key_table(self, ctx));
|
||||
|
||||
key_bindings_remove(data->key);
|
||||
key_bindings_remove(data->key);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/* $Id: cmd-up-pane.c,v 1.14 2010-01-05 23:52:37 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF 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 "tmux.h"
|
||||
|
||||
/*
|
||||
* Move up a pane.
|
||||
*/
|
||||
|
||||
int cmd_up_pane_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
const struct cmd_entry cmd_up_pane_entry = {
|
||||
"up-pane", "upp",
|
||||
CMD_TARGET_WINDOW_USAGE,
|
||||
0, "",
|
||||
cmd_target_init,
|
||||
cmd_target_parse,
|
||||
cmd_up_pane_exec,
|
||||
cmd_target_free,
|
||||
cmd_target_print
|
||||
};
|
||||
|
||||
int
|
||||
cmd_up_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct cmd_target_data *data = self->data;
|
||||
struct winlink *wl;
|
||||
struct window *w;
|
||||
|
||||
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
|
||||
return (-1);
|
||||
w = wl->window;
|
||||
|
||||
do {
|
||||
w->active = TAILQ_PREV(w->active, window_panes, entry);
|
||||
if (w->active == NULL)
|
||||
w->active = TAILQ_LAST(&w->panes, window_panes);
|
||||
} while (!window_pane_visible(w->active));
|
||||
server_status_window(wl->window);
|
||||
server_redraw_window_borders(wl->window);
|
||||
|
||||
return (0);
|
||||
}
|
||||
252
cmd.c
252
cmd.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: cmd.c,v 1.137 2010-01-22 17:28:34 tcunha Exp $ */
|
||||
/* $Id: cmd.c,v 1.146 2010-12-22 15:36:44 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -31,6 +31,7 @@ const struct cmd_entry *cmd_table[] = {
|
||||
&cmd_bind_key_entry,
|
||||
&cmd_break_pane_entry,
|
||||
&cmd_capture_pane_entry,
|
||||
&cmd_choose_buffer_entry,
|
||||
&cmd_choose_client_entry,
|
||||
&cmd_choose_session_entry,
|
||||
&cmd_choose_window_entry,
|
||||
@@ -44,7 +45,6 @@ const struct cmd_entry *cmd_table[] = {
|
||||
&cmd_detach_client_entry,
|
||||
&cmd_display_message_entry,
|
||||
&cmd_display_panes_entry,
|
||||
&cmd_down_pane_entry,
|
||||
&cmd_find_window_entry,
|
||||
&cmd_has_session_entry,
|
||||
&cmd_if_shell_entry,
|
||||
@@ -53,6 +53,7 @@ const struct cmd_entry *cmd_table[] = {
|
||||
&cmd_kill_server_entry,
|
||||
&cmd_kill_session_entry,
|
||||
&cmd_kill_window_entry,
|
||||
&cmd_last_pane_entry,
|
||||
&cmd_last_window_entry,
|
||||
&cmd_link_window_entry,
|
||||
&cmd_list_buffers_entry,
|
||||
@@ -85,7 +86,6 @@ const struct cmd_entry *cmd_table[] = {
|
||||
&cmd_save_buffer_entry,
|
||||
&cmd_select_layout_entry,
|
||||
&cmd_select_pane_entry,
|
||||
&cmd_select_prompt_entry,
|
||||
&cmd_select_window_entry,
|
||||
&cmd_send_keys_entry,
|
||||
&cmd_send_prefix_entry,
|
||||
@@ -108,16 +108,19 @@ const struct cmd_entry *cmd_table[] = {
|
||||
&cmd_switch_client_entry,
|
||||
&cmd_unbind_key_entry,
|
||||
&cmd_unlink_window_entry,
|
||||
&cmd_up_pane_entry,
|
||||
NULL
|
||||
};
|
||||
|
||||
struct session *cmd_choose_session(struct sessions *);
|
||||
struct session *cmd_choose_session_list(struct sessionslist *);
|
||||
struct session *cmd_choose_session(void);
|
||||
struct client *cmd_choose_client(struct clients *);
|
||||
struct client *cmd_lookup_client(const char *);
|
||||
struct session *cmd_lookup_session(const char *, int *);
|
||||
struct winlink *cmd_lookup_window(struct session *, const char *, int *);
|
||||
int cmd_lookup_index(struct session *, const char *, int *);
|
||||
struct winlink *cmd_find_window_offset(const char *, struct session *, int *);
|
||||
int cmd_find_index_offset(const char *, struct session *, int *);
|
||||
struct window_pane *cmd_find_pane_offset(const char *, struct winlink *);
|
||||
|
||||
int
|
||||
cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
|
||||
@@ -163,6 +166,22 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
|
||||
return (0);
|
||||
}
|
||||
|
||||
char **
|
||||
cmd_copy_argv(int argc, char **argv)
|
||||
{
|
||||
char **new_argv;
|
||||
int i;
|
||||
|
||||
if (argc == 0)
|
||||
return (NULL);
|
||||
new_argv = xcalloc(argc, sizeof *new_argv);
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (argv[i] != NULL)
|
||||
new_argv[i] = xstrdup(argv[i]);
|
||||
}
|
||||
return (new_argv);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_free_argv(int argc, char **argv)
|
||||
{
|
||||
@@ -297,10 +316,9 @@ cmd_current_session(struct cmd_ctx *ctx)
|
||||
struct msg_command_data *data = ctx->msgdata;
|
||||
struct client *c = ctx->cmdclient;
|
||||
struct session *s;
|
||||
struct sessions ss;
|
||||
struct sessionslist ss;
|
||||
struct winlink *wl;
|
||||
struct window_pane *wp;
|
||||
u_int i;
|
||||
int found;
|
||||
|
||||
if (ctx->curclient != NULL && ctx->curclient->session != NULL)
|
||||
@@ -313,9 +331,7 @@ cmd_current_session(struct cmd_ctx *ctx)
|
||||
*/
|
||||
if (c != NULL && c->tty.path != NULL) {
|
||||
ARRAY_INIT(&ss);
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
|
||||
continue;
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
found = 0;
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
|
||||
@@ -331,29 +347,43 @@ cmd_current_session(struct cmd_ctx *ctx)
|
||||
ARRAY_ADD(&ss, s);
|
||||
}
|
||||
|
||||
s = cmd_choose_session(&ss);
|
||||
s = cmd_choose_session_list(&ss);
|
||||
ARRAY_FREE(&ss);
|
||||
if (s != NULL)
|
||||
return (s);
|
||||
}
|
||||
|
||||
/* Use the session from the TMUX environment variable. */
|
||||
if (data != NULL && data->pid != -1) {
|
||||
if (data->pid != getpid())
|
||||
return (NULL);
|
||||
if (data->idx > ARRAY_LENGTH(&sessions))
|
||||
return (NULL);
|
||||
if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL)
|
||||
return (NULL);
|
||||
return (s);
|
||||
if (data != NULL && data->pid == getpid()) {
|
||||
s = session_find_by_index(data->idx);
|
||||
if (s != NULL)
|
||||
return (s);
|
||||
}
|
||||
|
||||
return (cmd_choose_session(&sessions));
|
||||
return (cmd_choose_session());
|
||||
}
|
||||
|
||||
/* Find the most recently used session. */
|
||||
struct session *
|
||||
cmd_choose_session(void)
|
||||
{
|
||||
struct session *s, *sbest;
|
||||
struct timeval *tv = NULL;
|
||||
|
||||
sbest = NULL;
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
if (tv == NULL || timercmp(&s->activity_time, tv, >)) {
|
||||
sbest = s;
|
||||
tv = &s->activity_time;
|
||||
}
|
||||
}
|
||||
|
||||
return (sbest);
|
||||
}
|
||||
|
||||
/* Find the most recently used session from a list. */
|
||||
struct session *
|
||||
cmd_choose_session(struct sessions *ss)
|
||||
cmd_choose_session_list(struct sessionslist *ss)
|
||||
{
|
||||
struct session *s, *sbest;
|
||||
struct timeval *tv = NULL;
|
||||
@@ -501,7 +531,6 @@ struct session *
|
||||
cmd_lookup_session(const char *name, int *ambiguous)
|
||||
{
|
||||
struct session *s, *sfound;
|
||||
u_int i;
|
||||
|
||||
*ambiguous = 0;
|
||||
|
||||
@@ -510,21 +539,15 @@ cmd_lookup_session(const char *name, int *ambiguous)
|
||||
* be unique so an exact match can't be ambigious and can just be
|
||||
* returned.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
|
||||
continue;
|
||||
if (strcmp(name, s->name) == 0)
|
||||
return (s);
|
||||
}
|
||||
if ((s = session_find(name)) != NULL)
|
||||
return (s);
|
||||
|
||||
/*
|
||||
* Otherwise look for partial matches, returning early if it is found to
|
||||
* be ambiguous.
|
||||
*/
|
||||
sfound = NULL;
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
|
||||
continue;
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
if (strncmp(name, s->name, strlen(name)) == 0 ||
|
||||
fnmatch(name, s->name, 0) == 0) {
|
||||
if (sfound != NULL) {
|
||||
@@ -540,7 +563,7 @@ cmd_lookup_session(const char *name, int *ambiguous)
|
||||
/*
|
||||
* Lookup a window or return -1 if not found or ambigious. First try as an
|
||||
* index and if invalid, use fnmatch or leading prefix. Return NULL but fill in
|
||||
* idx if the window index is a valid number but there is now window with that
|
||||
* idx if the window index is a valid number but there is no window with that
|
||||
* index.
|
||||
*/
|
||||
struct winlink *
|
||||
@@ -707,10 +730,8 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp)
|
||||
wl = s->curw;
|
||||
else if (winptr[0] == '!' && winptr[1] == '\0')
|
||||
wl = TAILQ_FIRST(&s->lastw);
|
||||
else if (winptr[0] == '+' && winptr[1] == '\0')
|
||||
wl = winlink_next(s->curw);
|
||||
else if (winptr[0] == '-' && winptr[1] == '\0')
|
||||
wl = winlink_previous(s->curw);
|
||||
else if (winptr[0] == '+' || winptr[0] == '-')
|
||||
wl = cmd_find_window_offset(winptr, s, &ambiguous);
|
||||
else
|
||||
wl = cmd_lookup_window(s, winptr, &ambiguous);
|
||||
if (wl == NULL)
|
||||
@@ -728,25 +749,28 @@ no_colon:
|
||||
if (arg[0] == '!' && arg[1] == '\0') {
|
||||
if ((wl = TAILQ_FIRST(&s->lastw)) == NULL)
|
||||
goto not_found;
|
||||
} else if (arg[0] == '+' && arg[1] == '\0') {
|
||||
if ((wl = winlink_next(s->curw)) == NULL)
|
||||
goto not_found;
|
||||
} else if (arg[0] == '-' && arg[1] == '\0') {
|
||||
if ((wl = winlink_previous(s->curw)) == NULL)
|
||||
goto not_found;
|
||||
} else if ((wl = cmd_lookup_window(s, arg, &ambiguous)) == NULL) {
|
||||
if (ambiguous)
|
||||
goto not_found;
|
||||
if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL)
|
||||
goto no_session;
|
||||
wl = s->curw;
|
||||
}
|
||||
} else if (arg[0] == '+' || arg[0] == '-') {
|
||||
if ((wl = cmd_find_window_offset(arg, s, &ambiguous)) == NULL)
|
||||
goto lookup_session;
|
||||
} else if ((wl = cmd_lookup_window(s, arg, &ambiguous)) == NULL)
|
||||
goto lookup_session;
|
||||
|
||||
if (sp != NULL)
|
||||
*sp = s;
|
||||
|
||||
return (wl);
|
||||
|
||||
lookup_session:
|
||||
if (ambiguous)
|
||||
goto not_found;
|
||||
if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL)
|
||||
goto no_session;
|
||||
|
||||
if (sp != NULL)
|
||||
*sp = s;
|
||||
|
||||
return (s->curw);
|
||||
|
||||
no_session:
|
||||
if (ambiguous)
|
||||
ctx->error(ctx, "multiple sessions: %s", arg);
|
||||
@@ -766,6 +790,26 @@ not_found:
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct winlink *
|
||||
cmd_find_window_offset(const char *winptr, struct session *s, int *ambiguous)
|
||||
{
|
||||
struct winlink *wl;
|
||||
int offset = 1;
|
||||
|
||||
if (winptr[1] != '\0')
|
||||
offset = strtonum(winptr + 1, 1, INT_MAX, NULL);
|
||||
if (offset == 0)
|
||||
wl = cmd_lookup_window(s, winptr, ambiguous);
|
||||
else {
|
||||
if (winptr[0] == '+')
|
||||
wl = winlink_next_by_number(s->curw, s, offset);
|
||||
else
|
||||
wl = winlink_previous_by_number(s->curw, s, offset);
|
||||
}
|
||||
|
||||
return (wl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the target session and window index, whether or not it exists in the
|
||||
* session. Return -2 on error or -1 if no window index is specified. This is
|
||||
@@ -827,20 +871,11 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp)
|
||||
if ((wl = TAILQ_FIRST(&s->lastw)) == NULL)
|
||||
goto not_found;
|
||||
idx = wl->idx;
|
||||
} else if (winptr[0] == '+' && winptr[1] == '\0') {
|
||||
if (s->curw->idx == INT_MAX)
|
||||
goto not_found;
|
||||
idx = s->curw->idx + 1;
|
||||
} else if (winptr[0] == '-' && winptr[1] == '\0') {
|
||||
if (s->curw->idx == 0)
|
||||
goto not_found;
|
||||
idx = s->curw->idx - 1;
|
||||
} else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1) {
|
||||
if (ambiguous)
|
||||
goto not_found;
|
||||
ctx->error(ctx, "invalid index: %s", arg);
|
||||
idx = -2;
|
||||
}
|
||||
} else if (winptr[0] == '+' || winptr[0] == '-') {
|
||||
if ((idx = cmd_find_index_offset(winptr, s, &ambiguous)) < 0)
|
||||
goto invalid_index;
|
||||
} else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1)
|
||||
goto invalid_index;
|
||||
|
||||
if (sessptr != NULL)
|
||||
xfree(sessptr);
|
||||
@@ -855,27 +890,28 @@ no_colon:
|
||||
if ((wl = TAILQ_FIRST(&s->lastw)) == NULL)
|
||||
goto not_found;
|
||||
idx = wl->idx;
|
||||
} else if (arg[0] == '+' && arg[1] == '\0') {
|
||||
if (s->curw->idx == INT_MAX)
|
||||
goto not_found;
|
||||
idx = s->curw->idx + 1;
|
||||
} else if (arg[0] == '-' && arg[1] == '\0') {
|
||||
if (s->curw->idx == 0)
|
||||
goto not_found;
|
||||
idx = s->curw->idx - 1;
|
||||
} else if ((idx = cmd_lookup_index(s, arg, &ambiguous)) == -1) {
|
||||
if (ambiguous)
|
||||
goto not_found;
|
||||
if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL)
|
||||
goto no_session;
|
||||
idx = -1;
|
||||
}
|
||||
} else if (arg[0] == '+' || arg[0] == '-') {
|
||||
if ((idx = cmd_find_index_offset(arg, s, &ambiguous)) < 0)
|
||||
goto lookup_session;
|
||||
} else if ((idx = cmd_lookup_index(s, arg, &ambiguous)) == -1)
|
||||
goto lookup_session;
|
||||
|
||||
if (sp != NULL)
|
||||
*sp = s;
|
||||
|
||||
return (idx);
|
||||
|
||||
lookup_session:
|
||||
if (ambiguous)
|
||||
goto not_found;
|
||||
if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL)
|
||||
goto no_session;
|
||||
|
||||
if (sp != NULL)
|
||||
*sp = s;
|
||||
|
||||
return (-1);
|
||||
|
||||
no_session:
|
||||
if (ambiguous)
|
||||
ctx->error(ctx, "multiple sessions: %s", arg);
|
||||
@@ -885,6 +921,15 @@ no_session:
|
||||
xfree(sessptr);
|
||||
return (-2);
|
||||
|
||||
invalid_index:
|
||||
if (ambiguous)
|
||||
goto not_found;
|
||||
ctx->error(ctx, "invalid index: %s", arg);
|
||||
|
||||
if (sessptr != NULL)
|
||||
xfree(sessptr);
|
||||
return (-2);
|
||||
|
||||
not_found:
|
||||
if (ambiguous)
|
||||
ctx->error(ctx, "multiple windows: %s", arg);
|
||||
@@ -895,6 +940,32 @@ not_found:
|
||||
return (-2);
|
||||
}
|
||||
|
||||
int
|
||||
cmd_find_index_offset(const char *winptr, struct session *s, int *ambiguous)
|
||||
{
|
||||
int idx, offset = 1;
|
||||
|
||||
if (winptr[1] != '\0')
|
||||
offset = strtonum(winptr + 1, 1, INT_MAX, NULL);
|
||||
if (offset == 0)
|
||||
idx = cmd_lookup_index(s, winptr, ambiguous);
|
||||
else {
|
||||
if (winptr[0] == '+') {
|
||||
if (s->curw->idx == INT_MAX)
|
||||
idx = cmd_lookup_index(s, winptr, ambiguous);
|
||||
else
|
||||
idx = s->curw->idx + offset;
|
||||
} else {
|
||||
if (s->curw->idx == 0)
|
||||
idx = cmd_lookup_index(s, winptr, ambiguous);
|
||||
else
|
||||
idx = s->curw->idx - offset;
|
||||
}
|
||||
}
|
||||
|
||||
return (idx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the target session, window and pane number or report an error and
|
||||
* return NULL. The pane number is separated from the session:window by a .,
|
||||
@@ -941,6 +1012,8 @@ cmd_find_pane(struct cmd_ctx *ctx,
|
||||
paneptr = winptr + (period - arg) + 1;
|
||||
if (*paneptr == '\0')
|
||||
*wpp = wl->window->active;
|
||||
else if (paneptr[0] == '+' || paneptr[0] == '-')
|
||||
*wpp = cmd_find_pane_offset(paneptr, wl);
|
||||
else {
|
||||
idx = strtonum(paneptr, 0, INT_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
@@ -955,14 +1028,14 @@ cmd_find_pane(struct cmd_ctx *ctx,
|
||||
|
||||
lookup_string:
|
||||
/* Try pane string description. */
|
||||
if ((lc = layout_find_string(s->curw->window, paneptr)) == NULL) {
|
||||
if ((lc = layout_find_string(wl->window, paneptr)) == NULL) {
|
||||
ctx->error(ctx, "can't find pane: %s", paneptr);
|
||||
goto error;
|
||||
}
|
||||
*wpp = lc->wp;
|
||||
|
||||
xfree(winptr);
|
||||
return (s->curw);
|
||||
return (wl);
|
||||
|
||||
no_period:
|
||||
/* Try as a pane number alone. */
|
||||
@@ -993,6 +1066,25 @@ error:
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct window_pane *
|
||||
cmd_find_pane_offset(const char *paneptr, struct winlink *wl)
|
||||
{
|
||||
struct window *w = wl->window;
|
||||
struct window_pane *wp = w->active;
|
||||
u_int offset = 1;
|
||||
|
||||
if (paneptr[1] != '\0')
|
||||
offset = strtonum(paneptr + 1, 1, INT_MAX, NULL);
|
||||
if (offset > 0) {
|
||||
if (paneptr[0] == '+')
|
||||
wp = window_pane_next_by_number(w, wp, offset);
|
||||
else
|
||||
wp = window_pane_previous_by_number(w, wp, offset);
|
||||
}
|
||||
|
||||
return (wp);
|
||||
}
|
||||
|
||||
/* Replace the first %% or %idx in template by s. */
|
||||
char *
|
||||
cmd_template_replace(char *template, const char *s, int idx)
|
||||
|
||||
96
compat.h
96
compat.h
@@ -1,4 +1,4 @@
|
||||
/* $Id: compat.h,v 1.20 2009-11-08 22:51:34 tcunha Exp $ */
|
||||
/* $Id: compat.h,v 1.31 2010-11-11 20:45:49 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -16,6 +16,20 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef COMPAT_H
|
||||
#define COMPAT_H
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define __attribute__(a)
|
||||
#endif
|
||||
|
||||
#ifndef __dead
|
||||
#define __dead __attribute__ ((__noreturn__))
|
||||
#endif
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__ ((__packed__))
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_U_INT
|
||||
typedef uint8_t u_int8_t;
|
||||
typedef uint16_t u_int16_t;
|
||||
@@ -42,21 +56,13 @@ typedef uint64_t u_int64_t;
|
||||
#else
|
||||
#include "compat/tree.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_BITSTRING_H
|
||||
#include <bitstring.h>
|
||||
#else
|
||||
#include "compat/bitstring.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETOPT
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CRYPT_H
|
||||
#include <crypt.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PATHS_H
|
||||
#include <paths.h>
|
||||
#endif
|
||||
@@ -79,19 +85,44 @@ typedef uint64_t u_int64_t;
|
||||
#include "compat/vis.h"
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_IMSG
|
||||
#ifdef HAVE_IMSG
|
||||
#include <imsg.h>
|
||||
#else
|
||||
#include "compat/imsg.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_BROKEN_CMSG_FIRSTHDR
|
||||
/* Broken on OS X. */
|
||||
/* CMSG_FIRSTHDR broken on OS X. */
|
||||
#undef CMSG_FIRSTHDR
|
||||
#define CMSG_FIRSTHDR(mhdr) \
|
||||
((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \
|
||||
(struct cmsghdr *)(mhdr)->msg_control : \
|
||||
((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \
|
||||
(struct cmsghdr *)(mhdr)->msg_control : \
|
||||
(struct cmsghdr *)NULL)
|
||||
#endif
|
||||
|
||||
/* CMSG_ALIGN, CMSG_SPACE, CMSG_LEN missing from Solaris 9. */
|
||||
#ifndef CMSG_ALIGN
|
||||
#ifdef __sun
|
||||
#define CMSG_ALIGN _CMSG_DATA_ALIGN
|
||||
#else
|
||||
#define CMSG_ALIGN(len) (((len) + sizeof(long) - 1) & ~(sizeof(long) - 1))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CMSG_SPACE
|
||||
#define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
|
||||
#endif
|
||||
|
||||
#ifndef CMSG_LEN
|
||||
#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
|
||||
#endif
|
||||
|
||||
#ifndef INFTIM
|
||||
#define INFTIM -1
|
||||
#endif
|
||||
@@ -104,13 +135,6 @@ typedef uint64_t u_int64_t;
|
||||
#define SUN_LEN(sun) (sizeof (sun)->sun_path)
|
||||
#endif
|
||||
|
||||
#ifndef __dead
|
||||
#define __dead __attribute__ ((__noreturn__))
|
||||
#endif
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__ ((__packed__))
|
||||
#endif
|
||||
|
||||
#ifndef timercmp
|
||||
#define timercmp(tvp, uvp, cmp) \
|
||||
(((tvp)->tv_sec == (uvp)->tv_sec) ? \
|
||||
@@ -135,7 +159,16 @@ typedef uint64_t u_int64_t;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_BZERO
|
||||
#define bzero(buf, len) memset((buf), 0, (len));
|
||||
#undef bzero
|
||||
#define bzero(buf, len) memset(buf, 0, len);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_CLOSEFROM
|
||||
/* closefrom.c */
|
||||
#define HAVE_FCNTL_H
|
||||
#define HAVE_DIRENT_H
|
||||
#define HAVE_SYSCONF
|
||||
void closefrom(int);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRCASESTR
|
||||
@@ -170,21 +203,30 @@ int daemon(int, int);
|
||||
|
||||
#ifndef HAVE_FORKPTY
|
||||
/* forkpty.c */
|
||||
#include <sys/ioctl.h>
|
||||
pid_t forkpty(int *, char *, struct termios *, struct winsize *);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ASPRINTF
|
||||
/* asprintf.c */
|
||||
int asprintf(char **, const char *, ...);
|
||||
int vasprintf(char **, const char *, va_list);
|
||||
int asprintf(char **, const char *, ...);
|
||||
int vasprintf(char **, const char *, va_list);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FGETLN
|
||||
/* fgetln.c */
|
||||
char *fgetln(FILE *, size_t *);
|
||||
char *fgetln(FILE *, size_t *);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETOPT
|
||||
#ifndef HAVE_SETENV
|
||||
/* setenv.c */
|
||||
int setenv(const char *, const char *, int);
|
||||
int unsetenv(const char *);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETOPT
|
||||
#include <getopt.h>
|
||||
#else
|
||||
/* getopt.c */
|
||||
extern int BSDopterr;
|
||||
extern int BSDoptind;
|
||||
@@ -199,3 +241,5 @@ int BSDgetopt(int, char *const *, const char *);
|
||||
#define optreset BSDoptreset
|
||||
#define optarg BSDoptarg
|
||||
#endif
|
||||
|
||||
#endif /* COMPAT_H */
|
||||
|
||||
111
compat/closefrom.c
Normal file
111
compat/closefrom.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/* $Id: closefrom.c,v 1.1 2010-10-27 20:21:01 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
#ifndef HAVE_CLOSEFROM
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_FCNTL_H
|
||||
# include <fcntl.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_DIRENT_H
|
||||
# include <dirent.h>
|
||||
# define NAMLEN(dirent) strlen((dirent)->d_name)
|
||||
#else
|
||||
# define dirent direct
|
||||
# define NAMLEN(dirent) (dirent)->d_namlen
|
||||
# ifdef HAVE_SYS_NDIR_H
|
||||
# include <sys/ndir.h>
|
||||
# endif
|
||||
# ifdef HAVE_SYS_DIR_H
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# ifdef HAVE_NDIR_H
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef OPEN_MAX
|
||||
# define OPEN_MAX 256
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $";
|
||||
#endif /* lint */
|
||||
|
||||
/*
|
||||
* Close all file descriptors greater than or equal to lowfd.
|
||||
*/
|
||||
#ifdef HAVE_FCNTL_CLOSEM
|
||||
void
|
||||
closefrom(int lowfd)
|
||||
{
|
||||
(void) fcntl(lowfd, F_CLOSEM, 0);
|
||||
}
|
||||
#else
|
||||
void
|
||||
closefrom(int lowfd)
|
||||
{
|
||||
long fd, maxfd;
|
||||
#if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID)
|
||||
char fdpath[PATH_MAX], *endp;
|
||||
struct dirent *dent;
|
||||
DIR *dirp;
|
||||
int len;
|
||||
|
||||
/* Check for a /proc/$$/fd directory. */
|
||||
len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid());
|
||||
if (len > 0 && (size_t)len <= sizeof(fdpath) && (dirp = opendir(fdpath))) {
|
||||
while ((dent = readdir(dirp)) != NULL) {
|
||||
fd = strtol(dent->d_name, &endp, 10);
|
||||
if (dent->d_name != endp && *endp == '\0' &&
|
||||
fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
|
||||
(void) close((int) fd);
|
||||
}
|
||||
(void) closedir(dirp);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
* Fall back on sysconf() or getdtablesize(). We avoid checking
|
||||
* resource limits since it is possible to open a file descriptor
|
||||
* and then drop the rlimit such that it is below the open fd.
|
||||
*/
|
||||
#ifdef HAVE_SYSCONF
|
||||
maxfd = sysconf(_SC_OPEN_MAX);
|
||||
#else
|
||||
maxfd = getdtablesize();
|
||||
#endif /* HAVE_SYSCONF */
|
||||
if (maxfd < 0)
|
||||
maxfd = OPEN_MAX;
|
||||
|
||||
for (fd = lowfd; fd < maxfd; fd++)
|
||||
(void) close((int) fd);
|
||||
}
|
||||
}
|
||||
#endif /* !HAVE_FCNTL_CLOSEM */
|
||||
#endif /* HAVE_CLOSEFROM */
|
||||
@@ -32,10 +32,6 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_PATHS_H
|
||||
#include <paths.h>
|
||||
#endif
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
int
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* $Id: imsg-buffer.c,v 1.4 2009-09-15 23:59:40 tcunha Exp $ */
|
||||
/* $OpenBSD: imsg-buffer.c,v 1.2 2009/09/15 18:12:51 jacekm Exp $ */
|
||||
/* $Id: imsg-buffer.c,v 1.5 2010-06-06 00:08:28 tcunha Exp $ */
|
||||
/* $OpenBSD: imsg-buffer.c,v 1.3 2010/05/26 13:56:07 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
|
||||
@@ -28,16 +28,16 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
int buf_realloc(struct buf *, size_t);
|
||||
void buf_enqueue(struct msgbuf *, struct buf *);
|
||||
void buf_dequeue(struct msgbuf *, struct buf *);
|
||||
int ibuf_realloc(struct ibuf *, size_t);
|
||||
void ibuf_enqueue(struct msgbuf *, struct ibuf *);
|
||||
void ibuf_dequeue(struct msgbuf *, struct ibuf *);
|
||||
|
||||
struct buf *
|
||||
buf_open(size_t len)
|
||||
struct ibuf *
|
||||
ibuf_open(size_t len)
|
||||
{
|
||||
struct buf *buf;
|
||||
struct ibuf *buf;
|
||||
|
||||
if ((buf = calloc(1, sizeof(struct buf))) == NULL)
|
||||
if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
|
||||
return (NULL);
|
||||
if ((buf->buf = malloc(len)) == NULL) {
|
||||
free(buf);
|
||||
@@ -49,15 +49,15 @@ buf_open(size_t len)
|
||||
return (buf);
|
||||
}
|
||||
|
||||
struct buf *
|
||||
buf_dynamic(size_t len, size_t max)
|
||||
struct ibuf *
|
||||
ibuf_dynamic(size_t len, size_t max)
|
||||
{
|
||||
struct buf *buf;
|
||||
struct ibuf *buf;
|
||||
|
||||
if (max < len)
|
||||
return (NULL);
|
||||
|
||||
if ((buf = buf_open(len)) == NULL)
|
||||
if ((buf = ibuf_open(len)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (max > 0)
|
||||
@@ -67,7 +67,7 @@ buf_dynamic(size_t len, size_t max)
|
||||
}
|
||||
|
||||
int
|
||||
buf_realloc(struct buf *buf, size_t len)
|
||||
ibuf_realloc(struct ibuf *buf, size_t len)
|
||||
{
|
||||
u_char *b;
|
||||
|
||||
@@ -87,10 +87,10 @@ buf_realloc(struct buf *buf, size_t len)
|
||||
}
|
||||
|
||||
int
|
||||
buf_add(struct buf *buf, const void *data, size_t len)
|
||||
ibuf_add(struct ibuf *buf, const void *data, size_t len)
|
||||
{
|
||||
if (buf->wpos + len > buf->size)
|
||||
if (buf_realloc(buf, len) == -1)
|
||||
if (ibuf_realloc(buf, len) == -1)
|
||||
return (-1);
|
||||
|
||||
memcpy(buf->buf + buf->wpos, data, len);
|
||||
@@ -99,12 +99,12 @@ buf_add(struct buf *buf, const void *data, size_t len)
|
||||
}
|
||||
|
||||
void *
|
||||
buf_reserve(struct buf *buf, size_t len)
|
||||
ibuf_reserve(struct ibuf *buf, size_t len)
|
||||
{
|
||||
void *b;
|
||||
|
||||
if (buf->wpos + len > buf->size)
|
||||
if (buf_realloc(buf, len) == -1)
|
||||
if (ibuf_realloc(buf, len) == -1)
|
||||
return (NULL);
|
||||
|
||||
b = buf->buf + buf->wpos;
|
||||
@@ -113,7 +113,7 @@ buf_reserve(struct buf *buf, size_t len)
|
||||
}
|
||||
|
||||
void *
|
||||
buf_seek(struct buf *buf, size_t pos, size_t len)
|
||||
ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
|
||||
{
|
||||
/* only allowed to seek in already written parts */
|
||||
if (pos + len > buf->wpos)
|
||||
@@ -123,28 +123,28 @@ buf_seek(struct buf *buf, size_t pos, size_t len)
|
||||
}
|
||||
|
||||
size_t
|
||||
buf_size(struct buf *buf)
|
||||
ibuf_size(struct ibuf *buf)
|
||||
{
|
||||
return (buf->wpos);
|
||||
}
|
||||
|
||||
size_t
|
||||
buf_left(struct buf *buf)
|
||||
ibuf_left(struct ibuf *buf)
|
||||
{
|
||||
return (buf->max - buf->wpos);
|
||||
}
|
||||
|
||||
void
|
||||
buf_close(struct msgbuf *msgbuf, struct buf *buf)
|
||||
ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
|
||||
{
|
||||
buf_enqueue(msgbuf, buf);
|
||||
ibuf_enqueue(msgbuf, buf);
|
||||
}
|
||||
|
||||
int
|
||||
buf_write(struct msgbuf *msgbuf)
|
||||
ibuf_write(struct msgbuf *msgbuf)
|
||||
{
|
||||
struct iovec iov[IOV_MAX];
|
||||
struct buf *buf;
|
||||
struct ibuf *buf;
|
||||
unsigned int i = 0;
|
||||
ssize_t n;
|
||||
|
||||
@@ -176,7 +176,7 @@ buf_write(struct msgbuf *msgbuf)
|
||||
}
|
||||
|
||||
void
|
||||
buf_free(struct buf *buf)
|
||||
ibuf_free(struct ibuf *buf)
|
||||
{
|
||||
free(buf->buf);
|
||||
free(buf);
|
||||
@@ -193,14 +193,14 @@ msgbuf_init(struct msgbuf *msgbuf)
|
||||
void
|
||||
msgbuf_drain(struct msgbuf *msgbuf, size_t n)
|
||||
{
|
||||
struct buf *buf, *next;
|
||||
struct ibuf *buf, *next;
|
||||
|
||||
for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
|
||||
buf = next) {
|
||||
next = TAILQ_NEXT(buf, entry);
|
||||
if (buf->rpos + n >= buf->wpos) {
|
||||
n -= buf->wpos - buf->rpos;
|
||||
buf_dequeue(msgbuf, buf);
|
||||
ibuf_dequeue(msgbuf, buf);
|
||||
} else {
|
||||
buf->rpos += n;
|
||||
n = 0;
|
||||
@@ -211,17 +211,17 @@ msgbuf_drain(struct msgbuf *msgbuf, size_t n)
|
||||
void
|
||||
msgbuf_clear(struct msgbuf *msgbuf)
|
||||
{
|
||||
struct buf *buf;
|
||||
struct ibuf *buf;
|
||||
|
||||
while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
|
||||
buf_dequeue(msgbuf, buf);
|
||||
ibuf_dequeue(msgbuf, buf);
|
||||
}
|
||||
|
||||
int
|
||||
msgbuf_write(struct msgbuf *msgbuf)
|
||||
{
|
||||
struct iovec iov[IOV_MAX];
|
||||
struct buf *buf;
|
||||
struct ibuf *buf;
|
||||
unsigned int i = 0;
|
||||
ssize_t n;
|
||||
struct msghdr msg;
|
||||
@@ -284,14 +284,14 @@ msgbuf_write(struct msgbuf *msgbuf)
|
||||
}
|
||||
|
||||
void
|
||||
buf_enqueue(struct msgbuf *msgbuf, struct buf *buf)
|
||||
ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
|
||||
{
|
||||
TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
|
||||
msgbuf->queued++;
|
||||
}
|
||||
|
||||
void
|
||||
buf_dequeue(struct msgbuf *msgbuf, struct buf *buf)
|
||||
ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
|
||||
{
|
||||
TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
|
||||
|
||||
@@ -299,5 +299,5 @@ buf_dequeue(struct msgbuf *msgbuf, struct buf *buf)
|
||||
close(buf->fd);
|
||||
|
||||
msgbuf->queued--;
|
||||
buf_free(buf);
|
||||
ibuf_free(buf);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* $Id: imsg.c,v 1.3 2009-08-20 12:54:08 nicm Exp $ */
|
||||
/* $OpenBSD: imsg.c,v 1.1 2009/08/11 17:18:35 nicm Exp $ */
|
||||
/* $Id: imsg.c,v 1.7 2010-11-13 16:29:05 nicm Exp $ */
|
||||
/* $OpenBSD: imsg.c,v 1.3 2010/05/26 13:56:07 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
|
||||
@@ -79,7 +79,7 @@ imsg_read(struct imsgbuf *ibuf)
|
||||
cmsg->cmsg_type == SCM_RIGHTS) {
|
||||
fd = (*(int *)CMSG_DATA(cmsg));
|
||||
if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) {
|
||||
/* XXX: this return can leak */
|
||||
close(fd);
|
||||
return (-1);
|
||||
}
|
||||
ifd->fd = fd;
|
||||
@@ -111,7 +111,7 @@ imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
|
||||
return (0);
|
||||
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
|
||||
ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
|
||||
if ((imsg->data = malloc(datalen)) == NULL)
|
||||
if ((imsg->data = malloc(datalen)) == NULL && datalen != 0)
|
||||
return (-1);
|
||||
|
||||
if (imsg->hdr.flags & IMSGF_HASFD)
|
||||
@@ -135,7 +135,7 @@ int
|
||||
imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
|
||||
pid_t pid, int fd, void *data, u_int16_t datalen)
|
||||
{
|
||||
struct buf *wbuf;
|
||||
struct ibuf *wbuf;
|
||||
|
||||
if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
|
||||
return (-1);
|
||||
@@ -154,7 +154,7 @@ int
|
||||
imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
|
||||
pid_t pid, int fd, const struct iovec *iov, int iovcnt)
|
||||
{
|
||||
struct buf *wbuf;
|
||||
struct ibuf *wbuf;
|
||||
int i, datalen = 0;
|
||||
|
||||
for (i = 0; i < iovcnt; i++)
|
||||
@@ -175,11 +175,11 @@ imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
struct buf *
|
||||
struct ibuf *
|
||||
imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
|
||||
pid_t pid, u_int16_t datalen)
|
||||
{
|
||||
struct buf *wbuf;
|
||||
struct ibuf *wbuf;
|
||||
struct imsg_hdr hdr;
|
||||
|
||||
datalen += IMSG_HEADER_SIZE;
|
||||
@@ -193,7 +193,7 @@ imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
|
||||
hdr.peerid = peerid;
|
||||
if ((hdr.pid = pid) == 0)
|
||||
hdr.pid = ibuf->pid;
|
||||
if ((wbuf = buf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
|
||||
if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
|
||||
@@ -203,18 +203,18 @@ imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
|
||||
}
|
||||
|
||||
int
|
||||
imsg_add(struct buf *msg, void *data, u_int16_t datalen)
|
||||
imsg_add(struct ibuf *msg, void *data, u_int16_t datalen)
|
||||
{
|
||||
if (datalen)
|
||||
if (buf_add(msg, data, datalen) == -1) {
|
||||
buf_free(msg);
|
||||
if (ibuf_add(msg, data, datalen) == -1) {
|
||||
ibuf_free(msg);
|
||||
return (-1);
|
||||
}
|
||||
return (datalen);
|
||||
}
|
||||
|
||||
void
|
||||
imsg_close(struct imsgbuf *ibuf, struct buf *msg)
|
||||
imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
|
||||
{
|
||||
struct imsg_hdr *hdr;
|
||||
|
||||
@@ -226,7 +226,7 @@ imsg_close(struct imsgbuf *ibuf, struct buf *msg)
|
||||
|
||||
hdr->len = (u_int16_t)msg->wpos;
|
||||
|
||||
buf_close(&ibuf->w, msg);
|
||||
ibuf_close(&ibuf->w, msg);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* $Id: imsg.h,v 1.4 2009-09-15 23:59:40 tcunha Exp $ */
|
||||
/* $OpenBSD: imsg.h,v 1.2 2009/09/15 18:12:51 jacekm Exp $ */
|
||||
/* $Id: imsg.h,v 1.5 2010-06-06 00:08:28 tcunha Exp $ */
|
||||
/* $OpenBSD: imsg.h,v 1.4 2010/05/26 13:56:07 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
|
||||
@@ -21,12 +21,12 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
#define READ_BUF_SIZE 65535
|
||||
#define IBUF_READ_SIZE 65535
|
||||
#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
|
||||
#define MAX_IMSGSIZE 16384
|
||||
|
||||
struct buf {
|
||||
TAILQ_ENTRY(buf) entry;
|
||||
struct ibuf {
|
||||
TAILQ_ENTRY(ibuf) entry;
|
||||
u_char *buf;
|
||||
size_t size;
|
||||
size_t max;
|
||||
@@ -36,13 +36,13 @@ struct buf {
|
||||
};
|
||||
|
||||
struct msgbuf {
|
||||
TAILQ_HEAD(, buf) bufs;
|
||||
TAILQ_HEAD(, ibuf) bufs;
|
||||
u_int32_t queued;
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct buf_read {
|
||||
u_char buf[READ_BUF_SIZE];
|
||||
struct ibuf_read {
|
||||
u_char buf[IBUF_READ_SIZE];
|
||||
u_char *rptr;
|
||||
size_t wpos;
|
||||
};
|
||||
@@ -54,7 +54,7 @@ struct imsg_fd {
|
||||
|
||||
struct imsgbuf {
|
||||
TAILQ_HEAD(, imsg_fd) fds;
|
||||
struct buf_read r;
|
||||
struct ibuf_read r;
|
||||
struct msgbuf w;
|
||||
int fd;
|
||||
pid_t pid;
|
||||
@@ -78,16 +78,16 @@ struct imsg {
|
||||
|
||||
|
||||
/* buffer.c */
|
||||
struct buf *buf_open(size_t);
|
||||
struct buf *buf_dynamic(size_t, size_t);
|
||||
int buf_add(struct buf *, const void *, size_t);
|
||||
void *buf_reserve(struct buf *, size_t);
|
||||
void *buf_seek(struct buf *, size_t, size_t);
|
||||
size_t buf_size(struct buf *);
|
||||
size_t buf_left(struct buf *);
|
||||
void buf_close(struct msgbuf *, struct buf *);
|
||||
int buf_write(struct msgbuf *);
|
||||
void buf_free(struct buf *);
|
||||
struct ibuf *ibuf_open(size_t);
|
||||
struct ibuf *ibuf_dynamic(size_t, size_t);
|
||||
int ibuf_add(struct ibuf *, const void *, size_t);
|
||||
void *ibuf_reserve(struct ibuf *, size_t);
|
||||
void *ibuf_seek(struct ibuf *, size_t, size_t);
|
||||
size_t ibuf_size(struct ibuf *);
|
||||
size_t ibuf_left(struct ibuf *);
|
||||
void ibuf_close(struct msgbuf *, struct ibuf *);
|
||||
int ibuf_write(struct msgbuf *);
|
||||
void ibuf_free(struct ibuf *);
|
||||
void msgbuf_init(struct msgbuf *);
|
||||
void msgbuf_clear(struct msgbuf *);
|
||||
int msgbuf_write(struct msgbuf *);
|
||||
@@ -101,10 +101,10 @@ int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
|
||||
int, void *, u_int16_t);
|
||||
int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
|
||||
int, const struct iovec *, int);
|
||||
struct buf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
|
||||
struct ibuf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
|
||||
u_int16_t);
|
||||
int imsg_add(struct buf *, void *, u_int16_t);
|
||||
void imsg_close(struct imsgbuf *, struct buf *);
|
||||
int imsg_add(struct ibuf *, void *, u_int16_t);
|
||||
void imsg_close(struct imsgbuf *, struct ibuf *);
|
||||
void imsg_free(struct imsg *);
|
||||
int imsg_flush(struct imsgbuf *);
|
||||
void imsg_clear(struct imsgbuf *);
|
||||
|
||||
49
compat/setenv.c
Normal file
49
compat/setenv.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/* $Id: setenv.c,v 1.2 2010-06-05 18:20:48 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Dagobert Michelsen
|
||||
* Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
int
|
||||
setenv(const char *name, const char *value, unused int overwrite)
|
||||
{
|
||||
char *newval;
|
||||
|
||||
xasprintf(&newval, "%s=%s", name, value);
|
||||
return (putenv(newval));
|
||||
}
|
||||
|
||||
int
|
||||
unsetenv(const char *name)
|
||||
{
|
||||
char **envptr;
|
||||
int namelen;
|
||||
|
||||
namelen = strlen(name);
|
||||
for (envptr = environ; *envptr != NULL; envptr++) {
|
||||
if (strncmp(name, *envptr, namelen) == 0 &&
|
||||
((*envptr)[namelen] == '=' || (*envptr)[namelen] == '\0'))
|
||||
break;
|
||||
}
|
||||
for (; *envptr != NULL; envptr++)
|
||||
*envptr = *(envptr + 1);
|
||||
return (0);
|
||||
}
|
||||
67
configure
vendored
67
configure
vendored
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# $Id: configure,v 1.47 2009-12-11 20:08:18 nicm Exp $
|
||||
# $Id: configure,v 1.59 2010-12-08 19:55:31 nicm Exp $
|
||||
#
|
||||
# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
#
|
||||
@@ -33,18 +33,22 @@ cat <<EOF >>$CONFIG_H
|
||||
#undef HAVE_BROKEN_KQUEUE
|
||||
#undef HAVE_BROKEN_POLL
|
||||
#undef HAVE_BZERO
|
||||
#undef HAVE_CRYPT_H
|
||||
#undef HAVE_CLOSEFROM
|
||||
#undef HAVE_DAEMON
|
||||
#undef HAVE_DIRFD
|
||||
#undef HAVE_FCNTL_CLOSEM
|
||||
#undef HAVE_FGETLN
|
||||
#undef HAVE_FORKPTY
|
||||
#undef HAVE_GETOPT
|
||||
#undef HAVE_IMSG
|
||||
#undef HAVE_LIBUTIL_H
|
||||
#undef HAVE_PATHS_H
|
||||
#undef HAVE_PROC_PID
|
||||
#undef HAVE_PROGNAME
|
||||
#undef HAVE_PTY_H
|
||||
#undef HAVE_QUEUE_H
|
||||
#undef HAVE_SETPROCTITLE
|
||||
#undef HAVE_STDINT_H
|
||||
#undef HAVE_STRCASESTR
|
||||
#undef HAVE_STRLCAT
|
||||
#undef HAVE_STRLCPY
|
||||
@@ -63,14 +67,18 @@ case $TMUX_PLATFORM in
|
||||
#define HAVE_ASPRINTF
|
||||
#define HAVE_BITSTRING_H
|
||||
#define HAVE_BZERO
|
||||
#define HAVE_CLOSEFROM
|
||||
#define HAVE_DAEMON
|
||||
#define HAVE_FGETLN
|
||||
#define HAVE_FORKPTY
|
||||
#define HAVE_GETOPT
|
||||
#define HAVE_IMSG
|
||||
#define HAVE_PATHS_H
|
||||
#define HAVE_PROGNAME
|
||||
#define HAVE_QUEUE_H
|
||||
#define HAVE_SETENV
|
||||
#define HAVE_SETPROCTITLE
|
||||
#define HAVE_STDINT_H
|
||||
#define HAVE_STRCASESTR
|
||||
#define HAVE_STRLCAT
|
||||
#define HAVE_STRLCPY
|
||||
@@ -83,9 +91,7 @@ case $TMUX_PLATFORM in
|
||||
EOF
|
||||
cat <<EOF >>$CONFIG_MK
|
||||
LIBS+= -lcurses -lutil -levent
|
||||
SRCS+= osdep-openbsd.c \
|
||||
compat/imsg-buffer.c \
|
||||
compat/imsg.c
|
||||
SRCS+= osdep-openbsd.c
|
||||
EOF
|
||||
;;
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -94,23 +100,28 @@ EOF
|
||||
#define HAVE_ASPRINTF
|
||||
#define HAVE_BZERO
|
||||
#define HAVE_DAEMON
|
||||
#define HAVE_DIRFD
|
||||
#define HAVE_FORKPTY
|
||||
#define HAVE_PATHS_H
|
||||
#define HAVE_PROC_PID
|
||||
#define HAVE_PROGNAME
|
||||
#define HAVE_PTY_H
|
||||
#define HAVE_SETENV
|
||||
#define HAVE_STDINT_H
|
||||
#define HAVE_STRCASESTR
|
||||
#define HAVE_STRSEP
|
||||
#define HAVE_U_INT
|
||||
EOF
|
||||
cat <<EOF >>$CONFIG_MK
|
||||
CFLAGS+= -std=c99 -D_GNU_SOURCE -D_POSIX_SOURCE
|
||||
LIBS+= -lncurses -lcrypt -lutil -levent
|
||||
LIBS+= -lncurses -lutil -levent -lrt
|
||||
SRCS+= osdep-linux.c \
|
||||
compat/closefrom.c \
|
||||
compat/fgetln.c \
|
||||
compat/strlcat.c \
|
||||
compat/strlcpy.c \
|
||||
compat/strtonum.c \
|
||||
compat/getopt.c \
|
||||
compat/getopt.c \
|
||||
compat/vis.c \
|
||||
compat/unvis.c \
|
||||
compat/imsg-buffer.c \
|
||||
@@ -120,13 +131,14 @@ EOF
|
||||
# ------------------------------------------------------------------------------
|
||||
AIX)
|
||||
cat <<EOF >>$CONFIG_H
|
||||
#define HAVE_BZERO
|
||||
#define HAVE_DAEMON
|
||||
#define HAVE_SETENV
|
||||
#define HAVE_STDINT_H
|
||||
EOF
|
||||
cat <<EOF >>$CONFIG_MK
|
||||
LIBS+= -lcurses -levent
|
||||
SRCS+= osdep-unknown.c \
|
||||
compat/asprintf.c \
|
||||
compat/closefrom.c \
|
||||
compat/daemon.c \
|
||||
compat/forkpty-aix.c \
|
||||
compat/strcasestr.c \
|
||||
@@ -145,7 +157,7 @@ EOF
|
||||
# ------------------------------------------------------------------------------
|
||||
SunOS)
|
||||
cat <<EOF >>$CONFIG_H
|
||||
#define HAVE_CRYPT_H
|
||||
#define HAVE_CLOSEFROM
|
||||
#define HAVE_STRLCAT
|
||||
#define HAVE_STRLCPY
|
||||
EOF
|
||||
@@ -158,6 +170,7 @@ SRCS+= osdep-sunos.c \
|
||||
compat/fgetln.c \
|
||||
compat/forkpty-sunos.c \
|
||||
compat/getopt.c \
|
||||
compat/setenv.c \
|
||||
compat/strcasestr.c \
|
||||
compat/strsep.c \
|
||||
compat/strtonum.c \
|
||||
@@ -176,11 +189,15 @@ EOF
|
||||
#define HAVE_BROKEN_POLL
|
||||
#define HAVE_BZERO
|
||||
#define HAVE_DAEMON
|
||||
#define HAVE_DIRFD
|
||||
#define HAVE_FGETLN
|
||||
#define HAVE_FORKPTY
|
||||
#define HAVE_GETOPT
|
||||
#define HAVE_PATHS_H
|
||||
#define HAVE_PROC_PID
|
||||
#define HAVE_PROGNAME
|
||||
#define HAVE_SETENV
|
||||
#define HAVE_STDINT_H
|
||||
#define HAVE_STRCASESTR
|
||||
#define HAVE_STRLCAT
|
||||
#define HAVE_STRLCPY
|
||||
@@ -193,6 +210,7 @@ CPPFLAGS+= -I/opt/local/include
|
||||
LDFLAGS+= -L/opt/local/lib
|
||||
LIBS+= -lcurses -levent
|
||||
SRCS+= osdep-darwin.c \
|
||||
compat/closefrom.c \
|
||||
compat/strtonum.c \
|
||||
compat/vis.c \
|
||||
compat/unvis.c \
|
||||
@@ -204,7 +222,9 @@ EOF
|
||||
FreeBSD|DragonFly)
|
||||
cat <<EOF >>$CONFIG_H
|
||||
#define HAVE_ASPRINTF
|
||||
#define HAVE_BROKEN_KQUEUE
|
||||
#define HAVE_BZERO
|
||||
#define HAVE_CLOSEFROM
|
||||
#define HAVE_DAEMON
|
||||
#define HAVE_FGETLN
|
||||
#define HAVE_FORKPTY
|
||||
@@ -212,16 +232,18 @@ EOF
|
||||
#define HAVE_LIBUTIL_H
|
||||
#define HAVE_PATHS_H
|
||||
#define HAVE_PROGNAME
|
||||
#define HAVE_SETENV
|
||||
#define HAVE_SETPROCTITLE
|
||||
#define HAVE_STDINT_H
|
||||
#define HAVE_STRCASESTR
|
||||
#define HAVE_STRLCAT
|
||||
#define HAVE_STRLCPY
|
||||
#define HAVE_STRTONUM
|
||||
#define HAVE_STRSEP
|
||||
#define HAVE_STRTONUM
|
||||
#define HAVE_U_INT
|
||||
EOF
|
||||
cat <<EOF >>$CONFIG_MK
|
||||
LIBS+= -lcurses -lcrypt -lutil -levent
|
||||
LIBS+= -lcurses -lutil -levent
|
||||
SRCS+= osdep-freebsd.c \
|
||||
compat/vis.c \
|
||||
compat/unvis.c \
|
||||
@@ -233,15 +255,17 @@ EOF
|
||||
NetBSD)
|
||||
cat <<EOF >>$CONFIG_H
|
||||
#define HAVE_ASPRINTF
|
||||
#define HAVE_BROKEN_CURSES_H
|
||||
#define HAVE_BZERO
|
||||
#define HAVE_CLOSEFROM
|
||||
#define HAVE_DAEMON
|
||||
#define HAVE_FGETLN
|
||||
#define HAVE_FORKPTY
|
||||
#define HAVE_GETOPT
|
||||
#define HAVE_PATHS_H
|
||||
#define HAVE_PROGNAME
|
||||
#define HAVE_SETENV
|
||||
#define HAVE_SETPROCTITLE
|
||||
#define HAVE_STDINT_H
|
||||
#define HAVE_STRCASESTR
|
||||
#define HAVE_STRLCAT
|
||||
#define HAVE_STRLCPY
|
||||
@@ -249,10 +273,23 @@ EOF
|
||||
#define HAVE_UTIL_H
|
||||
#define HAVE_U_INT
|
||||
EOF
|
||||
cat <<EOF >>$CONFIG_MK
|
||||
# NetBSD-6 has its own terminfo implementation
|
||||
if test -f /lib/libterminfo.so; then
|
||||
cat <<EOF >>$CONFIG_MK
|
||||
LIBS+= -lterminfo
|
||||
EOF
|
||||
else
|
||||
cat <<EOF >>$CONFIG_MK
|
||||
CPPFLAGS+= -I/usr/pkg/include
|
||||
LDFLAGS+= -L/usr/pkg/lib
|
||||
LIBS+= -lncurses -lcrypt -lutil -levent
|
||||
LIBS+= -lncurses
|
||||
EOF
|
||||
cat <<EOF >>$CONFIG_H
|
||||
#define HAVE_BROKEN_CURSES_H
|
||||
EOF
|
||||
fi
|
||||
cat <<EOF >>$CONFIG_MK
|
||||
LIBS+= -lutil -levent
|
||||
SRCS+= osdep-netbsd.c \
|
||||
compat/strtonum.c \
|
||||
compat/vis.c \
|
||||
|
||||
40
environ.c
40
environ.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: environ.c,v 1.3 2009-08-09 17:57:39 tcunha Exp $ */
|
||||
/* $Id: environ.c,v 1.4 2010-04-06 21:59:19 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -35,12 +35,14 @@ environ_cmp(struct environ_entry *envent1, struct environ_entry *envent2)
|
||||
return (strcmp(envent1->name, envent2->name));
|
||||
}
|
||||
|
||||
/* Initialise the environment. */
|
||||
void
|
||||
environ_init(struct environ *env)
|
||||
{
|
||||
RB_INIT(env);
|
||||
}
|
||||
|
||||
/* Free an environment. */
|
||||
void
|
||||
environ_free(struct environ *env)
|
||||
{
|
||||
@@ -56,6 +58,7 @@ environ_free(struct environ *env)
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy one environment into another. */
|
||||
void
|
||||
environ_copy(struct environ *srcenv, struct environ *dstenv)
|
||||
{
|
||||
@@ -65,6 +68,7 @@ environ_copy(struct environ *srcenv, struct environ *dstenv)
|
||||
environ_set(dstenv, envent->name, envent->value);
|
||||
}
|
||||
|
||||
/* Find an environment variable. */
|
||||
struct environ_entry *
|
||||
environ_find(struct environ *env, const char *name)
|
||||
{
|
||||
@@ -74,6 +78,7 @@ environ_find(struct environ *env, const char *name)
|
||||
return (RB_FIND(environ, env, &envent));
|
||||
}
|
||||
|
||||
/* Set an environment variable. */
|
||||
void
|
||||
environ_set(struct environ *env, const char *name, const char *value)
|
||||
{
|
||||
@@ -97,10 +102,11 @@ environ_set(struct environ *env, const char *name, const char *value)
|
||||
}
|
||||
}
|
||||
|
||||
/* Set an environment variable from a NAME=VALUE string. */
|
||||
void
|
||||
environ_put(struct environ *env, const char *var)
|
||||
{
|
||||
char *name, *value;
|
||||
char *name, *value;
|
||||
|
||||
value = strchr(var, '=');
|
||||
if (value == NULL)
|
||||
@@ -114,6 +120,7 @@ environ_put(struct environ *env, const char *var)
|
||||
xfree(name);
|
||||
}
|
||||
|
||||
/* Unset an environment variable. */
|
||||
void
|
||||
environ_unset(struct environ *env, const char *name)
|
||||
{
|
||||
@@ -128,6 +135,10 @@ environ_unset(struct environ *env, const char *name)
|
||||
xfree(envent);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy a space-separated list of variables from a destination into a source
|
||||
* environment.
|
||||
*/
|
||||
void
|
||||
environ_update(const char *vars, struct environ *srcenv, struct environ *dstenv)
|
||||
{
|
||||
@@ -143,3 +154,28 @@ environ_update(const char *vars, struct environ *srcenv, struct environ *dstenv)
|
||||
}
|
||||
xfree(copyvars);
|
||||
}
|
||||
|
||||
/* Push environment into the real environment - use after fork(). */
|
||||
void
|
||||
environ_push(struct environ *env)
|
||||
{
|
||||
ARRAY_DECL(, char *) varlist;
|
||||
struct environ_entry *envent;
|
||||
char **varp, *var;
|
||||
u_int i;
|
||||
|
||||
ARRAY_INIT(&varlist);
|
||||
for (varp = environ; *varp != NULL; varp++) {
|
||||
var = xstrdup(*varp);
|
||||
var[strcspn(var, "=")] = '\0';
|
||||
ARRAY_ADD(&varlist, var);
|
||||
}
|
||||
for (i = 0; i < ARRAY_LENGTH(&varlist); i++)
|
||||
unsetenv(ARRAY_ITEM(&varlist, i));
|
||||
ARRAY_FREE(&varlist);
|
||||
|
||||
RB_FOREACH(envent, environ, env) {
|
||||
if (envent->value != NULL)
|
||||
setenv(envent->name, envent->value, 1);
|
||||
}
|
||||
}
|
||||
|
||||
105
examples/bash_completion_tmux.sh
Normal file
105
examples/bash_completion_tmux.sh
Normal file
@@ -0,0 +1,105 @@
|
||||
# START tmux completion
|
||||
# This file is in the public domain
|
||||
# See: http://www.debian-administration.org/articles/317 for how to write more.
|
||||
# Usage: Put "source bash_completion_tmux.sh" into your .bashrc
|
||||
_tmux()
|
||||
{
|
||||
local cur prev opts
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
|
||||
opts=" \
|
||||
attach-session \
|
||||
bind-key \
|
||||
break-pane \
|
||||
capture-pane \
|
||||
choose-client \
|
||||
choose-session \
|
||||
choose-window \
|
||||
clear-history \
|
||||
clock-mode \
|
||||
command-prompt \
|
||||
confirm-before \
|
||||
copy-buffer \
|
||||
copy-mode \
|
||||
delete-buffer \
|
||||
detach-client \
|
||||
display-message \
|
||||
display-panes \
|
||||
down-pane \
|
||||
find-window \
|
||||
has-session \
|
||||
if-shell \
|
||||
join-pane \
|
||||
kill-pane \
|
||||
kill-server \
|
||||
kill-session \
|
||||
kill-window \
|
||||
last-window \
|
||||
link-window \
|
||||
list-buffers \
|
||||
list-clients \
|
||||
list-commands \
|
||||
list-keys \
|
||||
list-panes \
|
||||
list-sessions \
|
||||
list-windows \
|
||||
load-buffer \
|
||||
lock-client \
|
||||
lock-server \
|
||||
lock-session \
|
||||
move-window \
|
||||
new-session \
|
||||
new-window \
|
||||
next-layout \
|
||||
next-window \
|
||||
paste-buffer \
|
||||
pipe-pane \
|
||||
previous-layout \
|
||||
previous-window \
|
||||
refresh-client \
|
||||
rename-session \
|
||||
rename-window \
|
||||
resize-pane \
|
||||
respawn-window \
|
||||
rotate-window \
|
||||
run-shell \
|
||||
save-buffer \
|
||||
select-layout \
|
||||
select-pane \
|
||||
select-prompt \
|
||||
select-window \
|
||||
send-keys \
|
||||
send-prefix \
|
||||
server-info \
|
||||
set-buffer \
|
||||
set-environment \
|
||||
set-option \
|
||||
set-window-option \
|
||||
show-buffer \
|
||||
show-environment \
|
||||
show-messages \
|
||||
show-options \
|
||||
show-window-options \
|
||||
source-file \
|
||||
split-window \
|
||||
start-server \
|
||||
suspend-client \
|
||||
swap-pane \
|
||||
swap-window \
|
||||
switch-client \
|
||||
unbind-key \
|
||||
unlink-window \
|
||||
up-pane"
|
||||
|
||||
COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
|
||||
return 0
|
||||
|
||||
}
|
||||
complete -F _tmux tmux
|
||||
|
||||
# END tmux completion
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# $Id: screen-keys.conf,v 1.6 2010-02-02 21:34:16 nicm Exp $
|
||||
# $Id: screen-keys.conf,v 1.7 2010-07-31 11:39:13 nicm Exp $
|
||||
#
|
||||
# By Nicholas Marriott. Public domain.
|
||||
#
|
||||
@@ -93,9 +93,9 @@ bind | split-window
|
||||
|
||||
# :kB: focus up
|
||||
unbind Tab
|
||||
bind Tab down-pane
|
||||
bind Tab select-pane -t:.+
|
||||
unbind BTab
|
||||
bind BTab up-pane
|
||||
bind BTab select-pane -t:.-
|
||||
|
||||
# " windowlist -b
|
||||
unbind '"'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
" Vim syntax file
|
||||
" Language: tmux(1) configuration file
|
||||
" Maintainer: Tiago Cunha <me@tiagocunha.org>
|
||||
" Last Change: $Date: 2010-02-26 13:33:22 $
|
||||
" Last Change: $Date: 2010-07-27 18:29:07 $
|
||||
" License: This file is placed in the public domain.
|
||||
|
||||
if version < 600
|
||||
@@ -29,11 +29,11 @@ syn keyword tmuxCmds new[-session] start[-server] kill-server setw
|
||||
syn keyword tmuxCmds set-window-option show[-options] showw show-window-options
|
||||
syn keyword tmuxCmds command-prompt setb set-buffer showb show-buffer lsb
|
||||
syn keyword tmuxCmds list-buffers deleteb delete-buffer lscm list-commands
|
||||
syn keyword tmuxCmds movew move-window select-prompt respawnw respawn-window
|
||||
syn keyword tmuxCmds movew move-window respawnw respawn-window
|
||||
syn keyword tmuxCmds source[-file] info server-info clock-mode lock[-server]
|
||||
syn keyword tmuxCmds saveb save-buffer downp down-pane killp
|
||||
syn keyword tmuxCmds saveb save-buffer killp
|
||||
syn keyword tmuxCmds kill-pane resizep resize-pane selectp select-pane swapp
|
||||
syn keyword tmuxCmds swap-pane splitw split-window upp up-pane choose-session
|
||||
syn keyword tmuxCmds swap-pane splitw split-window choose-session
|
||||
syn keyword tmuxCmds choose-window loadb load-buffer copyb copy-buffer suspendc
|
||||
syn keyword tmuxCmds suspend-client findw find-window breakp break-pane nextl
|
||||
syn keyword tmuxCmds next-layout rotatew rotate-window confirm[-before]
|
||||
@@ -42,7 +42,7 @@ syn keyword tmuxCmds display[-message] setenv set-environment showenv
|
||||
syn keyword tmuxCmds show-environment choose-client displayp display-panes
|
||||
syn keyword tmuxCmds run[-shell] lockc lock-client locks lock-session lsp
|
||||
syn keyword tmuxCmds list-panes pipep pipe-pane showmsgs show-messages capturep
|
||||
syn keyword tmuxCmds capture-pane joinp join-pane
|
||||
syn keyword tmuxCmds capture-pane joinp join-pane choose-buffer
|
||||
|
||||
syn keyword tmuxOptsSet prefix status status-fg status-bg bell-action
|
||||
syn keyword tmuxOptsSet default-command history-limit status-left status-right
|
||||
@@ -61,6 +61,7 @@ syn keyword tmuxOptsSet mouse-select-pane message-limit quiet escape-time
|
||||
syn keyword tmuxOptsSet pane-active-border-bg pane-active-border-fg
|
||||
syn keyword tmuxOptsSet pane-border-bg pane-border-fg
|
||||
syn keyword tmuxOptsSet display-panes-active-colour alternate-screen
|
||||
syn keyword tmuxOptsSet detach-on-destroy
|
||||
|
||||
syn keyword tmuxOptsSetw monitor-activity aggressive-resize force-width
|
||||
syn keyword tmuxOptsSetw force-height remain-on-exit uft8 mode-fg mode-bg
|
||||
@@ -71,7 +72,8 @@ syn keyword tmuxOptsSetw main-pane-width main-pane-height monitor-content
|
||||
syn keyword tmuxOptsSetw window-status-current-attr window-status-current-bg
|
||||
syn keyword tmuxOptsSetw window-status-current-fg mode-mouse synchronize-panes
|
||||
syn keyword tmuxOptsSetw window-status-format window-status-current-format
|
||||
syn keyword tmuxOptsSetw word-separators
|
||||
syn keyword tmuxOptsSetw word-separators window-status-alert-alert
|
||||
syn keyword tmuxOptsSetw window-status-alert-bg window-status-alert-fg
|
||||
|
||||
syn keyword tmuxTodo FIXME NOTE TODO XXX contained
|
||||
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
# $Id: vim-keys.conf,v 1.1 2010-01-17 16:24:09 nicm Exp $
|
||||
# $Id: vim-keys.conf,v 1.2 2010-09-18 09:36:15 nicm Exp $
|
||||
#
|
||||
# vim-keys.conf, v1.0 2010/01/15
|
||||
# vim-keys.conf, v1.2 2010/09/12
|
||||
#
|
||||
# By Daniel Thau. Public domain.
|
||||
#
|
||||
# This configuration file binds many vi- and vim-like bindings to the
|
||||
# appropriate tmux key bindings. Note that for many key bindings there is no
|
||||
# tmux analogue.
|
||||
# tmux analogue. This is intended for tmux 1.3, which handles pane selection
|
||||
# differently from the previous versions
|
||||
|
||||
# split windows like vim
|
||||
# vim's definition of a horizontal/vertical split is reversed from tmux's
|
||||
bind s split-window -v
|
||||
bind v split-window -h
|
||||
|
||||
# move around panes with j and k, a bit like vim
|
||||
# as of tmux 1.1, there is no way to move based on pane position (ie, no way to
|
||||
# move the pane to the right)
|
||||
bind j down-pane
|
||||
bind k up-pane
|
||||
# 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
|
||||
|
||||
# resize panes like vim
|
||||
# feel free to change the "1" to however many lines you want to resize by, only
|
||||
|
||||
43
grid.c
43
grid.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: grid.c,v 1.36 2009-12-04 22:14:47 tcunha Exp $ */
|
||||
/* $Id: grid.c,v 1.37 2010-04-05 05:11:43 micahcowan Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -46,18 +46,9 @@ const struct grid_cell grid_default_cell = { 0, 0, 8, 8, ' ' };
|
||||
gc, sizeof gd->linedata[py].utf8data[px]); \
|
||||
} while (0)
|
||||
|
||||
int grid_check_x(struct grid *, u_int);
|
||||
int grid_check_y(struct grid *, u_int);
|
||||
|
||||
#ifdef DEBUG
|
||||
int
|
||||
grid_check_x(struct grid *gd, u_int px)
|
||||
{
|
||||
if ((px) >= (gd)->sx)
|
||||
log_fatalx("x out of range: %u", px);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
grid_check_y(struct grid *gd, u_int py)
|
||||
{
|
||||
@@ -66,16 +57,6 @@ grid_check_y(struct grid *gd, u_int py)
|
||||
return (0);
|
||||
}
|
||||
#else
|
||||
int
|
||||
grid_check_x(struct grid *gd, u_int px)
|
||||
{
|
||||
if ((px) >= (gd)->sx) {
|
||||
log_debug("x out of range: %u", px);
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
grid_check_y(struct grid *gd, u_int py)
|
||||
{
|
||||
@@ -270,8 +251,6 @@ grid_expand_line_utf8(struct grid *gd, u_int py, u_int sx)
|
||||
const struct grid_cell *
|
||||
grid_peek_cell(struct grid *gd, u_int px, u_int py)
|
||||
{
|
||||
if (grid_check_x(gd, px) != 0)
|
||||
return (&grid_default_cell);
|
||||
if (grid_check_y(gd, py) != 0)
|
||||
return (&grid_default_cell);
|
||||
|
||||
@@ -284,8 +263,6 @@ grid_peek_cell(struct grid *gd, u_int px, u_int py)
|
||||
struct grid_cell *
|
||||
grid_get_cell(struct grid *gd, u_int px, u_int py)
|
||||
{
|
||||
if (grid_check_x(gd, px) != 0)
|
||||
return (NULL);
|
||||
if (grid_check_y(gd, py) != 0)
|
||||
return (NULL);
|
||||
|
||||
@@ -298,8 +275,6 @@ void
|
||||
grid_set_cell(
|
||||
struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
|
||||
{
|
||||
if (grid_check_x(gd, px) != 0)
|
||||
return;
|
||||
if (grid_check_y(gd, py) != 0)
|
||||
return;
|
||||
|
||||
@@ -311,8 +286,6 @@ grid_set_cell(
|
||||
const struct grid_utf8 *
|
||||
grid_peek_utf8(struct grid *gd, u_int px, u_int py)
|
||||
{
|
||||
if (grid_check_x(gd, px) != 0)
|
||||
return (NULL);
|
||||
if (grid_check_y(gd, py) != 0)
|
||||
return (NULL);
|
||||
|
||||
@@ -325,8 +298,6 @@ grid_peek_utf8(struct grid *gd, u_int px, u_int py)
|
||||
struct grid_utf8 *
|
||||
grid_get_utf8(struct grid *gd, u_int px, u_int py)
|
||||
{
|
||||
if (grid_check_x(gd, px) != 0)
|
||||
return (NULL);
|
||||
if (grid_check_y(gd, py) != 0)
|
||||
return (NULL);
|
||||
|
||||
@@ -339,8 +310,6 @@ void
|
||||
grid_set_utf8(
|
||||
struct grid *gd, u_int px, u_int py, const struct grid_utf8 *gc)
|
||||
{
|
||||
if (grid_check_x(gd, px) != 0)
|
||||
return;
|
||||
if (grid_check_y(gd, py) != 0)
|
||||
return;
|
||||
|
||||
@@ -364,10 +333,6 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny)
|
||||
return;
|
||||
}
|
||||
|
||||
if (grid_check_x(gd, px) != 0)
|
||||
return;
|
||||
if (grid_check_x(gd, px + nx - 1) != 0)
|
||||
return;
|
||||
if (grid_check_y(gd, py) != 0)
|
||||
return;
|
||||
if (grid_check_y(gd, py + ny - 1) != 0)
|
||||
@@ -465,12 +430,6 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx)
|
||||
if (nx == 0 || px == dx)
|
||||
return;
|
||||
|
||||
if (grid_check_x(gd, px) != 0)
|
||||
return;
|
||||
if (grid_check_x(gd, px + nx - 1) != 0)
|
||||
return;
|
||||
if (grid_check_x(gd, dx + nx - 1) != 0)
|
||||
return;
|
||||
if (grid_check_y(gd, py) != 0)
|
||||
return;
|
||||
gl = &gd->linedata[py];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: input-keys.c,v 1.44 2009-12-04 22:14:47 tcunha Exp $ */
|
||||
/* $Id: input-keys.c,v 1.45 2010-09-07 19:32:58 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
11
job.c
11
job.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: job.c,v 1.15 2010-02-26 13:35:04 tcunha Exp $ */
|
||||
/* $Id: job.c,v 1.19 2010-10-24 00:45:57 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -148,8 +148,9 @@ job_run(struct job *job)
|
||||
case -1:
|
||||
return (-1);
|
||||
case 0: /* child */
|
||||
server_signal_clear();
|
||||
/* XXX environ? */
|
||||
clear_signals(1);
|
||||
|
||||
environ_push(&global_environ);
|
||||
|
||||
if (dup2(out[1], STDOUT_FILENO) == -1)
|
||||
fatal("dup2 failed");
|
||||
@@ -167,6 +168,8 @@ job_run(struct job *job)
|
||||
if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO)
|
||||
close(nullfd);
|
||||
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
|
||||
execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL);
|
||||
fatal("execl failed");
|
||||
default: /* parent */
|
||||
@@ -177,8 +180,6 @@ job_run(struct job *job)
|
||||
fatal("fcntl failed");
|
||||
if (fcntl(job->fd, F_SETFL, mode|O_NONBLOCK) == -1)
|
||||
fatal("fcntl failed");
|
||||
if (fcntl(job->fd, F_SETFD, FD_CLOEXEC) == -1)
|
||||
fatal("fcntl failed");
|
||||
|
||||
if (job->event != NULL)
|
||||
bufferevent_free(job->event);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: key-bindings.c,v 1.88 2010-02-08 18:27:34 tcunha Exp $ */
|
||||
/* $Id: key-bindings.c,v 1.97 2010-12-11 18:42:20 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -108,6 +108,8 @@ key_bindings_init(void)
|
||||
{ '#', 0, &cmd_list_buffers_entry },
|
||||
{ '%', 0, &cmd_split_window_entry },
|
||||
{ '&', 0, &cmd_confirm_before_entry },
|
||||
{ '(', 0, &cmd_switch_client_entry },
|
||||
{ ')', 0, &cmd_switch_client_entry },
|
||||
{ ',', 0, &cmd_command_prompt_entry },
|
||||
{ '-', 0, &cmd_delete_buffer_entry },
|
||||
{ '.', 0, &cmd_command_prompt_entry },
|
||||
@@ -122,10 +124,13 @@ key_bindings_init(void)
|
||||
{ '8', 0, &cmd_select_window_entry },
|
||||
{ '9', 0, &cmd_select_window_entry },
|
||||
{ ':', 0, &cmd_command_prompt_entry },
|
||||
{ ';', 0, &cmd_last_pane_entry },
|
||||
{ '=', 0, &cmd_choose_buffer_entry },
|
||||
{ '?', 0, &cmd_list_keys_entry },
|
||||
{ 'D', 0, &cmd_choose_client_entry },
|
||||
{ 'L', 0, &cmd_switch_client_entry },
|
||||
{ '[', 0, &cmd_copy_mode_entry },
|
||||
{ '\'', 0, &cmd_select_prompt_entry },
|
||||
{ '\'', 0, &cmd_command_prompt_entry },
|
||||
{ '\002', /* C-b */ 0, &cmd_send_prefix_entry },
|
||||
{ '\017', /* C-o */ 0, &cmd_rotate_window_entry },
|
||||
{ '\032', /* C-z */ 0, &cmd_suspend_client_entry },
|
||||
@@ -136,7 +141,7 @@ key_bindings_init(void)
|
||||
{ 'i', 0, &cmd_display_message_entry },
|
||||
{ 'l', 0, &cmd_last_window_entry },
|
||||
{ 'n', 0, &cmd_next_window_entry },
|
||||
{ 'o', 0, &cmd_down_pane_entry },
|
||||
{ 'o', 0, &cmd_select_pane_entry },
|
||||
{ 'p', 0, &cmd_previous_window_entry },
|
||||
{ 'q', 0, &cmd_display_panes_entry },
|
||||
{ 'r', 0, &cmd_refresh_client_entry },
|
||||
@@ -151,12 +156,15 @@ key_bindings_init(void)
|
||||
{ '2' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
|
||||
{ '3' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
|
||||
{ '4' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
|
||||
{ '5' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
|
||||
{ KEYC_PPAGE, 0, &cmd_copy_mode_entry },
|
||||
{ 'n' | KEYC_ESCAPE, 0, &cmd_next_window_entry },
|
||||
{ 'o' | KEYC_ESCAPE, 0, &cmd_rotate_window_entry },
|
||||
{ 'p' | KEYC_ESCAPE, 0, &cmd_previous_window_entry },
|
||||
{ KEYC_UP, 0, &cmd_up_pane_entry },
|
||||
{ KEYC_DOWN, 0, &cmd_down_pane_entry },
|
||||
{ KEYC_UP, 1, &cmd_select_pane_entry },
|
||||
{ KEYC_DOWN, 1, &cmd_select_pane_entry },
|
||||
{ KEYC_LEFT, 1, &cmd_select_pane_entry },
|
||||
{ KEYC_RIGHT, 1, &cmd_select_pane_entry },
|
||||
{ KEYC_UP | KEYC_ESCAPE, 1, &cmd_resize_pane_entry },
|
||||
{ KEYC_DOWN | KEYC_ESCAPE, 1, &cmd_resize_pane_entry },
|
||||
{ KEYC_LEFT | KEYC_ESCAPE, 1, &cmd_resize_pane_entry },
|
||||
@@ -174,14 +182,15 @@ key_bindings_init(void)
|
||||
|
||||
for (i = 0; i < nitems(table); i++) {
|
||||
cmdlist = xmalloc(sizeof *cmdlist);
|
||||
TAILQ_INIT(cmdlist);
|
||||
TAILQ_INIT(&cmdlist->list);
|
||||
cmdlist->references = 1;
|
||||
|
||||
cmd = xmalloc(sizeof *cmd);
|
||||
cmd->entry = table[i].entry;
|
||||
cmd->data = NULL;
|
||||
if (cmd->entry->init != NULL)
|
||||
cmd->entry->init(cmd, table[i].key);
|
||||
TAILQ_INSERT_HEAD(cmdlist, cmd, qentry);
|
||||
TAILQ_INSERT_HEAD(&cmdlist->list, cmd, qentry);
|
||||
|
||||
key_bindings_add(
|
||||
table[i].key | KEYC_PREFIX, table[i].can_repeat, cmdlist);
|
||||
@@ -209,12 +218,14 @@ key_bindings_print(struct cmd_ctx *ctx, const char *fmt, ...)
|
||||
struct winlink *wl = ctx->curclient->session->curw;
|
||||
va_list ap;
|
||||
|
||||
if (wl->window->active->mode != &window_more_mode)
|
||||
if (wl->window->active->mode != &window_copy_mode) {
|
||||
window_pane_reset_mode(wl->window->active);
|
||||
window_pane_set_mode(wl->window->active, &window_more_mode);
|
||||
window_pane_set_mode(wl->window->active, &window_copy_mode);
|
||||
window_copy_init_for_output(wl->window->active);
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
window_more_vadd(wl->window->active, fmt, ap);
|
||||
window_copy_vadd(wl->window->active, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
@@ -253,7 +264,7 @@ key_bindings_dispatch(struct key_binding *bd, struct client *c)
|
||||
ctx.cmdclient = NULL;
|
||||
|
||||
readonly = 1;
|
||||
TAILQ_FOREACH(cmd, bd->cmdlist, qentry) {
|
||||
TAILQ_FOREACH(cmd, &bd->cmdlist->list, qentry) {
|
||||
if (!(cmd->entry->flags & CMD_READONLY))
|
||||
readonly = 0;
|
||||
}
|
||||
|
||||
210
key-string.c
210
key-string.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: key-string.c,v 1.29 2010-01-17 19:01:27 tcunha Exp $ */
|
||||
/* $Id: key-string.c,v 1.34 2010-06-05 20:29:11 micahcowan Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -23,10 +23,11 @@
|
||||
#include "tmux.h"
|
||||
|
||||
int key_string_search_table(const char *);
|
||||
int key_string_get_modifiers(const char **);
|
||||
|
||||
struct {
|
||||
const char *string;
|
||||
int key;
|
||||
const char *string;
|
||||
int key;
|
||||
} key_string_table[] = {
|
||||
/* Function keys. */
|
||||
{ "F1", KEYC_F1 },
|
||||
@@ -100,146 +101,131 @@ key_string_search_table(const char *string)
|
||||
return (KEYC_NONE);
|
||||
}
|
||||
|
||||
/* Lookup a string and convert to a key value, handling C-/M-/S- prefix. */
|
||||
/* Find modifiers. */
|
||||
int
|
||||
key_string_get_modifiers(const char **string)
|
||||
{
|
||||
int modifiers;
|
||||
|
||||
modifiers = 0;
|
||||
while (((*string)[0] != '\0') && (*string)[1] == '-') {
|
||||
switch ((*string)[0]) {
|
||||
case 'C':
|
||||
case 'c':
|
||||
modifiers |= KEYC_CTRL;
|
||||
break;
|
||||
case 'M':
|
||||
case 'm':
|
||||
modifiers |= KEYC_ESCAPE;
|
||||
break;
|
||||
case 'S':
|
||||
case 's':
|
||||
modifiers |= KEYC_SHIFT;
|
||||
break;
|
||||
}
|
||||
*string += 2;
|
||||
}
|
||||
return (modifiers);
|
||||
}
|
||||
|
||||
/* Lookup a string and convert to a key value. */
|
||||
int
|
||||
key_string_lookup_string(const char *string)
|
||||
{
|
||||
int key;
|
||||
const char *ptr;
|
||||
int key, modifiers;
|
||||
|
||||
/* Check for modifiers. */
|
||||
modifiers = 0;
|
||||
if (string[0] == '^' && string[1] != '\0') {
|
||||
modifiers |= KEYC_CTRL;
|
||||
string++;
|
||||
}
|
||||
modifiers |= key_string_get_modifiers(&string);
|
||||
if (string[0] == '\0')
|
||||
return (KEYC_NONE);
|
||||
if (string[1] == '\0')
|
||||
return ((u_char) string[0]);
|
||||
|
||||
ptr = NULL;
|
||||
if ((string[0] == 'C' || string[0] == 'c') && string[1] == '-')
|
||||
ptr = string + 2;
|
||||
else if (string[0] == '^')
|
||||
ptr = string + 1;
|
||||
if (ptr != NULL) {
|
||||
if (ptr[0] == '\0')
|
||||
/* Is this a standard ASCII key? */
|
||||
if (string[1] == '\0') {
|
||||
key = (u_char) string[0];
|
||||
if (key < 32 || key > 126)
|
||||
return (KEYC_NONE);
|
||||
/*
|
||||
* Lookup as a named key. If a function key (>= KEYC_BASE),
|
||||
* return it with the ctrl modifier, otherwise fallthrough with
|
||||
* the key value from the table (eg for C-Space). If not a
|
||||
* named key, check for single character keys and try that.
|
||||
*/
|
||||
key = key_string_search_table(ptr);
|
||||
if (key != KEYC_NONE) {
|
||||
if (key >= KEYC_BASE)
|
||||
return (key | KEYC_CTRL);
|
||||
} else {
|
||||
if (ptr[1] != '\0')
|
||||
return (KEYC_NONE);
|
||||
key = (u_char) ptr[0];
|
||||
}
|
||||
} else {
|
||||
/* Otherwise look the key up in the table. */
|
||||
key = key_string_search_table(string);
|
||||
if (key == KEYC_NONE)
|
||||
return (KEYC_NONE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out if the single character in key is a valid ctrl
|
||||
* key.
|
||||
*/
|
||||
if (key == 32)
|
||||
return (0);
|
||||
if (key == 63)
|
||||
return (KEYC_BSPACE);
|
||||
if (key >= 64 && key <= 95)
|
||||
return (key - 64);
|
||||
/* Convert the standard control keys. */
|
||||
if (key < KEYC_BASE && (modifiers & KEYC_CTRL)) {
|
||||
if (key >= 97 && key <= 122)
|
||||
return (key - 96);
|
||||
return (KEYC_NONE);
|
||||
}
|
||||
|
||||
if ((string[0] == 'M' || string[0] == 'm') && string[1] == '-') {
|
||||
ptr = string + 2;
|
||||
if (ptr[0] == '\0')
|
||||
key -= 96;
|
||||
else if (key >= 64 && key <= 95)
|
||||
key -= 64;
|
||||
else if (key == 32)
|
||||
key = 0;
|
||||
else if (key == 63)
|
||||
key = KEYC_BSPACE;
|
||||
else
|
||||
return (KEYC_NONE);
|
||||
key = key_string_lookup_string(ptr);
|
||||
if (key != KEYC_NONE) {
|
||||
if (key >= KEYC_BASE)
|
||||
return (key | KEYC_ESCAPE);
|
||||
} else {
|
||||
if (ptr[1] == '\0')
|
||||
return (KEYC_NONE);
|
||||
key = (u_char) ptr[0];
|
||||
}
|
||||
|
||||
if (key >= 32 && key <= 127)
|
||||
return (key | KEYC_ESCAPE);
|
||||
return (KEYC_NONE);
|
||||
modifiers &= ~KEYC_CTRL;
|
||||
}
|
||||
|
||||
if ((string[0] == 'S' || string[0] == 's') && string[1] == '-') {
|
||||
ptr = string + 2;
|
||||
if (ptr[0] == '\0')
|
||||
return (KEYC_NONE);
|
||||
key = key_string_lookup_string(ptr);
|
||||
if (key != KEYC_NONE) {
|
||||
if (key >= KEYC_BASE)
|
||||
return (key | KEYC_SHIFT);
|
||||
} else {
|
||||
if (ptr[1] == '\0')
|
||||
return (KEYC_NONE);
|
||||
key = (u_char) ptr[0];
|
||||
}
|
||||
|
||||
if (key >= 32 && key <= 127)
|
||||
return (key | KEYC_SHIFT);
|
||||
return (KEYC_NONE);
|
||||
}
|
||||
|
||||
return (key_string_search_table(string));
|
||||
return (key | modifiers);
|
||||
}
|
||||
|
||||
/* Convert a key code into string format, with prefix if necessary. */
|
||||
const char *
|
||||
key_string_lookup_key(int key)
|
||||
{
|
||||
static char tmp[24], tmp2[24];
|
||||
const char *s;
|
||||
u_int i;
|
||||
static char out[24];
|
||||
char tmp[8];
|
||||
u_int i;
|
||||
|
||||
if (key == 127)
|
||||
return (NULL);
|
||||
*out = '\0';
|
||||
|
||||
if (key & KEYC_ESCAPE) {
|
||||
if ((s = key_string_lookup_key(key & ~KEYC_ESCAPE)) == NULL)
|
||||
return (NULL);
|
||||
xsnprintf(tmp2, sizeof tmp2, "M-%s", s);
|
||||
return (tmp2);
|
||||
}
|
||||
if (key & KEYC_CTRL) {
|
||||
if ((s = key_string_lookup_key(key & ~KEYC_CTRL)) == NULL)
|
||||
return (NULL);
|
||||
xsnprintf(tmp2, sizeof tmp2, "C-%s", s);
|
||||
return (tmp2);
|
||||
}
|
||||
if (key & KEYC_SHIFT) {
|
||||
if ((s = key_string_lookup_key(key & ~KEYC_SHIFT)) == NULL)
|
||||
return (NULL);
|
||||
xsnprintf(tmp2, sizeof tmp2, "S-%s", s);
|
||||
return (tmp2);
|
||||
}
|
||||
/*
|
||||
* Special case: display C-@ as C-Space. Could do this below in
|
||||
* the (key >= 0 && key <= 32), but this way we let it be found
|
||||
* in key_string_table, for the unlikely chance that we might
|
||||
* change its name.
|
||||
*/
|
||||
if ((key & KEYC_MASK_KEY) == 0)
|
||||
key = ' ' | KEYC_CTRL | (key & KEYC_MASK_MOD);
|
||||
|
||||
/* Fill in the modifiers. */
|
||||
if (key & KEYC_CTRL)
|
||||
strlcat(out, "C-", sizeof out);
|
||||
if (key & KEYC_ESCAPE)
|
||||
strlcat(out, "M-", sizeof out);
|
||||
if (key & KEYC_SHIFT)
|
||||
strlcat(out, "S-", sizeof out);
|
||||
key &= KEYC_MASK_KEY;
|
||||
|
||||
/* Try the key against the string table. */
|
||||
for (i = 0; i < nitems(key_string_table); i++) {
|
||||
if (key == key_string_table[i].key)
|
||||
return (key_string_table[i].string);
|
||||
break;
|
||||
}
|
||||
if (i != nitems(key_string_table)) {
|
||||
strlcat(out, key_string_table[i].string, sizeof out);
|
||||
return (out);
|
||||
}
|
||||
|
||||
if (key >= 32 && key <= 255) {
|
||||
tmp[0] = (char) key;
|
||||
tmp[1] = '\0';
|
||||
return (tmp);
|
||||
}
|
||||
/* Invalid keys are errors. */
|
||||
if (key >= 127)
|
||||
return (NULL);
|
||||
|
||||
/* Check for standard or control key. */
|
||||
if (key >= 0 && key <= 32) {
|
||||
if (key == 0 || key > 26)
|
||||
xsnprintf(tmp, sizeof tmp, "C-%c", 64 + key);
|
||||
else
|
||||
xsnprintf(tmp, sizeof tmp, "C-%c", 96 + key);
|
||||
return (tmp);
|
||||
} else if (key >= 32 && key <= 126) {
|
||||
tmp[0] = key;
|
||||
tmp[1] = '\0';
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
strlcat(out, tmp, sizeof out);
|
||||
return (out);
|
||||
}
|
||||
|
||||
264
layout-custom.c
Normal file
264
layout-custom.c
Normal file
@@ -0,0 +1,264 @@
|
||||
/* $Id: layout-custom.c,v 1.1 2010-07-02 02:54:52 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF 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 <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
u_short layout_checksum(const char *);
|
||||
int layout_append(struct layout_cell *, char *, size_t);
|
||||
struct layout_cell *layout_construct(struct layout_cell *, const char **);
|
||||
void layout_assign(struct window_pane **, struct layout_cell *);
|
||||
|
||||
/* Calculate layout checksum. */
|
||||
u_short
|
||||
layout_checksum(const char *layout)
|
||||
{
|
||||
u_short csum;
|
||||
|
||||
csum = 0;
|
||||
for (; *layout != '\0'; layout++) {
|
||||
csum = (csum >> 1) + ((csum & 1) << 15);
|
||||
csum += *layout;
|
||||
}
|
||||
return (csum);
|
||||
}
|
||||
|
||||
/* Dump layout as a string. */
|
||||
char *
|
||||
layout_dump(struct window *w)
|
||||
{
|
||||
char layout[BUFSIZ], *out;
|
||||
|
||||
*layout = '\0';
|
||||
if (layout_append(w->layout_root, layout, sizeof layout) != 0)
|
||||
return (NULL);
|
||||
|
||||
xasprintf(&out, "%4x,%s", layout_checksum(layout), layout);
|
||||
return (out);
|
||||
}
|
||||
|
||||
/* Append information for a single cell. */
|
||||
int
|
||||
layout_append(struct layout_cell *lc, char *buf, size_t len)
|
||||
{
|
||||
struct layout_cell *lcchild;
|
||||
char tmp[64];
|
||||
size_t tmplen;
|
||||
const char *brackets = "][";
|
||||
|
||||
if (len == 0)
|
||||
return (-1);
|
||||
|
||||
tmplen = xsnprintf(tmp, sizeof tmp,
|
||||
"%ux%u,%u,%u", lc->sx, lc->sy, lc->xoff, lc->yoff);
|
||||
if (tmplen > (sizeof tmp) - 1)
|
||||
return (-1);
|
||||
if (strlcat(buf, tmp, len) >= len)
|
||||
return (-1);
|
||||
|
||||
switch (lc->type) {
|
||||
case LAYOUT_LEFTRIGHT:
|
||||
brackets = "}{";
|
||||
/* FALLTHROUGH */
|
||||
case LAYOUT_TOPBOTTOM:
|
||||
if (strlcat(buf, &brackets[1], len) >= len)
|
||||
return (-1);
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (layout_append(lcchild, buf, len) != 0)
|
||||
return (-1);
|
||||
if (strlcat(buf, ",", len) >= len)
|
||||
return (-1);
|
||||
}
|
||||
buf[strlen(buf) - 1] = brackets[0];
|
||||
break;
|
||||
case LAYOUT_WINDOWPANE:
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Parse a layout string and arrange window as layout. */
|
||||
int
|
||||
layout_parse(struct window *w, const char *layout)
|
||||
{
|
||||
struct layout_cell *lc, *lcchild;
|
||||
struct window_pane *wp;
|
||||
u_int npanes, ncells, sx, sy;
|
||||
u_short csum;
|
||||
|
||||
/* Check validity. */
|
||||
if (sscanf(layout, "%hx,", &csum) != 1)
|
||||
return (-1);
|
||||
layout += 5;
|
||||
if (csum != layout_checksum(layout))
|
||||
return (-1);
|
||||
|
||||
/* Build the layout. */
|
||||
lc = layout_construct(NULL, &layout);
|
||||
if (lc == NULL)
|
||||
return (-1);
|
||||
if (*layout != '\0')
|
||||
goto fail;
|
||||
|
||||
/* Check this window will fit into the layout. */
|
||||
for (;;) {
|
||||
npanes = window_count_panes(w);
|
||||
ncells = layout_count_cells(lc);
|
||||
if (npanes > ncells)
|
||||
goto fail;
|
||||
if (npanes == ncells)
|
||||
break;
|
||||
|
||||
/* Fewer panes than cells - close the bottom right. */
|
||||
lcchild = layout_find_bottomright(lc);
|
||||
layout_destroy_cell(lcchild, &lc);
|
||||
}
|
||||
|
||||
/* Save the old window size and resize to the layout size. */
|
||||
sx = w->sx; sy = w->sy;
|
||||
window_resize(w, lc->sx, lc->sy);
|
||||
|
||||
/* Destroy the old layout and swap to the new. */
|
||||
layout_free_cell(w->layout_root);
|
||||
w->layout_root = lc;
|
||||
|
||||
/* Assign the panes into the cells. */
|
||||
wp = TAILQ_FIRST(&w->panes);
|
||||
layout_assign(&wp, lc);
|
||||
|
||||
/* Update pane offsets and sizes. */
|
||||
layout_fix_offsets(lc);
|
||||
layout_fix_panes(w, lc->sx, lc->sy);
|
||||
|
||||
/* Then resize the layout back to the original window size. */
|
||||
layout_resize(w, sx, sy);
|
||||
window_resize(w, sx, sy);
|
||||
|
||||
layout_print_cell(lc, __func__, 0);
|
||||
|
||||
return (0);
|
||||
|
||||
fail:
|
||||
layout_free_cell(lc);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Assign panes into cells. */
|
||||
void
|
||||
layout_assign(struct window_pane **wp, struct layout_cell *lc)
|
||||
{
|
||||
struct layout_cell *lcchild;
|
||||
|
||||
switch (lc->type) {
|
||||
case LAYOUT_WINDOWPANE:
|
||||
layout_make_leaf(lc, *wp);
|
||||
*wp = TAILQ_NEXT(*wp, entry);
|
||||
return;
|
||||
case LAYOUT_LEFTRIGHT:
|
||||
case LAYOUT_TOPBOTTOM:
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry)
|
||||
layout_assign(wp, lcchild);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Construct a cell from all or part of a layout tree. */
|
||||
struct layout_cell *
|
||||
layout_construct(struct layout_cell *lcparent, const char **layout)
|
||||
{
|
||||
struct layout_cell *lc, *lcchild;
|
||||
u_int sx, sy, xoff, yoff;
|
||||
|
||||
if (!isdigit((u_char) **layout))
|
||||
return (NULL);
|
||||
if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4)
|
||||
return (NULL);
|
||||
|
||||
while (isdigit((u_char) **layout))
|
||||
(*layout)++;
|
||||
if (**layout != 'x')
|
||||
return (NULL);
|
||||
(*layout)++;
|
||||
while (isdigit((u_char) **layout))
|
||||
(*layout)++;
|
||||
if (**layout != ',')
|
||||
return (NULL);
|
||||
(*layout)++;
|
||||
while (isdigit((u_char) **layout))
|
||||
(*layout)++;
|
||||
if (**layout != ',')
|
||||
return (NULL);
|
||||
(*layout)++;
|
||||
while (isdigit((u_char) **layout))
|
||||
(*layout)++;
|
||||
|
||||
lc = layout_create_cell(lcparent);
|
||||
lc->sx = sx;
|
||||
lc->sy = sy;
|
||||
lc->xoff = xoff;
|
||||
lc->yoff = yoff;
|
||||
|
||||
switch (**layout) {
|
||||
case ',':
|
||||
case '}':
|
||||
case ']':
|
||||
case '\0':
|
||||
return (lc);
|
||||
case '{':
|
||||
lc->type = LAYOUT_LEFTRIGHT;
|
||||
break;
|
||||
case '[':
|
||||
lc->type = LAYOUT_TOPBOTTOM;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
do {
|
||||
(*layout)++;
|
||||
lcchild = layout_construct(lc, layout);
|
||||
if (lcchild == NULL)
|
||||
goto fail;
|
||||
TAILQ_INSERT_TAIL(&lc->cells, lcchild, entry);
|
||||
} while (**layout == ',');
|
||||
|
||||
switch (lc->type) {
|
||||
case LAYOUT_LEFTRIGHT:
|
||||
if (**layout != '}')
|
||||
goto fail;
|
||||
break;
|
||||
case LAYOUT_TOPBOTTOM:
|
||||
if (**layout != ']')
|
||||
goto fail;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
(*layout)++;
|
||||
|
||||
return (lc);
|
||||
|
||||
fail:
|
||||
layout_free_cell(lc);
|
||||
return (NULL);
|
||||
}
|
||||
194
layout-set.c
194
layout-set.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: layout-set.c,v 1.5 2010-02-05 01:29:04 tcunha Exp $ */
|
||||
/* $Id: layout-set.c,v 1.8 2010-12-22 15:23:59 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -31,6 +31,7 @@ void layout_set_even_h(struct window *);
|
||||
void layout_set_even_v(struct window *);
|
||||
void layout_set_main_h(struct window *);
|
||||
void layout_set_main_v(struct window *);
|
||||
void layout_set_tiled(struct window *);
|
||||
|
||||
const struct {
|
||||
const char *name;
|
||||
@@ -40,6 +41,7 @@ const struct {
|
||||
{ "even-vertical", layout_set_even_v },
|
||||
{ "main-horizontal", layout_set_main_h },
|
||||
{ "main-vertical", layout_set_main_v },
|
||||
{ "tiled", layout_set_tiled },
|
||||
};
|
||||
|
||||
const char *
|
||||
@@ -133,10 +135,9 @@ layout_set_even_h(struct window *w)
|
||||
return;
|
||||
|
||||
/* How many can we fit? */
|
||||
if (w->sx / n < PANE_MINIMUM + 1)
|
||||
width = PANE_MINIMUM + 1;
|
||||
else
|
||||
width = w->sx / n;
|
||||
width = (w->sx - (n - 1)) / n;
|
||||
if (width < PANE_MINIMUM)
|
||||
width = PANE_MINIMUM;
|
||||
|
||||
/* Free the old root and construct a new. */
|
||||
layout_free(w);
|
||||
@@ -149,12 +150,12 @@ layout_set_even_h(struct window *w)
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
/* Create child cell. */
|
||||
lcnew = layout_create_cell(lc);
|
||||
layout_set_size(lcnew, width - 1, w->sy, xoff, 0);
|
||||
layout_set_size(lcnew, width, w->sy, xoff, 0);
|
||||
layout_make_leaf(lcnew, wp);
|
||||
TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
|
||||
|
||||
i++;
|
||||
xoff += width;
|
||||
xoff += width + 1;
|
||||
}
|
||||
|
||||
/* Allocate any remaining space. */
|
||||
@@ -187,10 +188,9 @@ layout_set_even_v(struct window *w)
|
||||
return;
|
||||
|
||||
/* How many can we fit? */
|
||||
if (w->sy / n < PANE_MINIMUM + 1)
|
||||
height = PANE_MINIMUM + 1;
|
||||
else
|
||||
height = w->sy / n;
|
||||
height = (w->sy - (n - 1)) / n;
|
||||
if (height < PANE_MINIMUM)
|
||||
height = PANE_MINIMUM;
|
||||
|
||||
/* Free the old root and construct a new. */
|
||||
layout_free(w);
|
||||
@@ -203,12 +203,12 @@ layout_set_even_v(struct window *w)
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
/* Create child cell. */
|
||||
lcnew = layout_create_cell(lc);
|
||||
layout_set_size(lcnew, w->sx, height - 1, 0, yoff);
|
||||
layout_set_size(lcnew, w->sx, height, 0, yoff);
|
||||
layout_make_leaf(lcnew, wp);
|
||||
TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
|
||||
|
||||
i++;
|
||||
yoff += height;
|
||||
yoff += height + 1;
|
||||
}
|
||||
|
||||
/* Allocate any remaining space. */
|
||||
@@ -231,8 +231,8 @@ layout_set_main_h(struct window *w)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
struct layout_cell *lc, *lcmain, *lcrow, *lcchild;
|
||||
u_int n, mainheight, width, height, used;
|
||||
u_int i, j, columns, rows, totalrows;
|
||||
u_int n, mainheight, otherheight, width, height;
|
||||
u_int used, i, j, columns, rows, totalrows;
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
@@ -242,16 +242,26 @@ layout_set_main_h(struct window *w)
|
||||
return;
|
||||
n--; /* take off main pane */
|
||||
|
||||
/* How many rows and columns will be needed? */
|
||||
columns = w->sx / (PANE_MINIMUM + 1); /* maximum columns */
|
||||
/* How many rows and columns will be needed, not counting main? */
|
||||
columns = (w->sx + 1) / (PANE_MINIMUM + 1); /* maximum columns */
|
||||
if (columns == 0)
|
||||
columns = 1;
|
||||
rows = 1 + (n - 1) / columns;
|
||||
columns = 1 + (n - 1) / rows;
|
||||
width = w->sx / columns;
|
||||
width = (w->sx - (n - 1)) / columns;
|
||||
|
||||
/* Get the main pane height and add one for separator line. */
|
||||
mainheight = options_get_number(&w->options, "main-pane-height") + 1;
|
||||
|
||||
/* Get the optional other pane height and add one for separator line. */
|
||||
otherheight = options_get_number(&w->options, "other-pane-height") + 1;
|
||||
|
||||
/*
|
||||
* If an other pane height was specified, honour it so long as it
|
||||
* doesn't shrink the main height to less than the main-pane-height
|
||||
*/
|
||||
if (otherheight > 1 && w->sx - otherheight > mainheight)
|
||||
mainheight = w->sx - otherheight;
|
||||
if (mainheight < PANE_MINIMUM + 1)
|
||||
mainheight = PANE_MINIMUM + 1;
|
||||
|
||||
@@ -262,14 +272,14 @@ layout_set_main_h(struct window *w)
|
||||
mainheight = PANE_MINIMUM + 2;
|
||||
else
|
||||
mainheight = w->sy - totalrows;
|
||||
height = PANE_MINIMUM + 1;
|
||||
height = PANE_MINIMUM;
|
||||
} else
|
||||
height = (w->sy - mainheight) / rows;
|
||||
height = (w->sy - mainheight - (rows - 1)) / rows;
|
||||
|
||||
/* Free old tree and create a new root. */
|
||||
layout_free(w);
|
||||
lc = w->layout_root = layout_create_cell(NULL);
|
||||
layout_set_size(lc, w->sx, mainheight + rows * height, 0, 0);
|
||||
layout_set_size(lc, w->sx, mainheight + rows * (height + 1) - 1, 0, 0);
|
||||
layout_make_node(lc, LAYOUT_TOPBOTTOM);
|
||||
|
||||
/* Create the main pane. */
|
||||
@@ -287,7 +297,7 @@ layout_set_main_h(struct window *w)
|
||||
|
||||
/* Create the new row. */
|
||||
lcrow = layout_create_cell(lc);
|
||||
layout_set_size(lcrow, w->sx, height - 1, 0, 0);
|
||||
layout_set_size(lcrow, w->sx, height, 0, 0);
|
||||
TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
|
||||
|
||||
/* If only one column, just use the row directly. */
|
||||
@@ -302,7 +312,7 @@ layout_set_main_h(struct window *w)
|
||||
for (i = 0; i < columns; i++) {
|
||||
/* Create and add a pane cell. */
|
||||
lcchild = layout_create_cell(lcrow);
|
||||
layout_set_size(lcchild, width - 1, height - 1, 0, 0);
|
||||
layout_set_size(lcchild, width, height, 0, 0);
|
||||
layout_make_leaf(lcchild, wp);
|
||||
TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
|
||||
|
||||
@@ -314,7 +324,7 @@ layout_set_main_h(struct window *w)
|
||||
/* Adjust the row to fit the full width if necessary. */
|
||||
if (i == columns)
|
||||
i--;
|
||||
used = ((i + 1) * width) - 1;
|
||||
used = ((i + 1) * (width + 1)) - 1;
|
||||
if (w->sx <= used)
|
||||
continue;
|
||||
lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
|
||||
@@ -322,7 +332,7 @@ layout_set_main_h(struct window *w)
|
||||
}
|
||||
|
||||
/* Adjust the last row height to fit if necessary. */
|
||||
used = mainheight + (rows * height) - 1;
|
||||
used = mainheight + (rows * height) + rows - 1;
|
||||
if (w->sy > used) {
|
||||
lcrow = TAILQ_LAST(&lc->cells, layout_cells);
|
||||
layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used);
|
||||
@@ -342,8 +352,8 @@ layout_set_main_v(struct window *w)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
struct layout_cell *lc, *lcmain, *lccolumn, *lcchild;
|
||||
u_int n, mainwidth, width, height, used;
|
||||
u_int i, j, columns, rows, totalcolumns;
|
||||
u_int n, mainwidth, otherwidth, width, height;
|
||||
u_int used, i, j, columns, rows, totalcolumns;
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
@@ -353,16 +363,26 @@ layout_set_main_v(struct window *w)
|
||||
return;
|
||||
n--; /* take off main pane */
|
||||
|
||||
/* How many rows and columns will be needed? */
|
||||
rows = w->sy / (PANE_MINIMUM + 1); /* maximum rows */
|
||||
/* How many rows and columns will be needed, not counting main? */
|
||||
rows = (w->sy + 1) / (PANE_MINIMUM + 1); /* maximum rows */
|
||||
if (rows == 0)
|
||||
rows = 1;
|
||||
columns = 1 + (n - 1) / rows;
|
||||
rows = 1 + (n - 1) / columns;
|
||||
height = w->sy / rows;
|
||||
height = (w->sy - (n - 1)) / rows;
|
||||
|
||||
/* Get the main pane width and add one for separator line. */
|
||||
mainwidth = options_get_number(&w->options, "main-pane-width") + 1;
|
||||
|
||||
/* Get the optional other pane width and add one for separator line. */
|
||||
otherwidth = options_get_number(&w->options, "other-pane-width") + 1;
|
||||
|
||||
/*
|
||||
* If an other pane width was specified, honour it so long as it
|
||||
* doesn't shrink the main width to less than the main-pane-width
|
||||
*/
|
||||
if (otherwidth > 1 && w->sx - otherwidth > mainwidth)
|
||||
mainwidth = w->sx - otherwidth;
|
||||
if (mainwidth < PANE_MINIMUM + 1)
|
||||
mainwidth = PANE_MINIMUM + 1;
|
||||
|
||||
@@ -373,14 +393,14 @@ layout_set_main_v(struct window *w)
|
||||
mainwidth = PANE_MINIMUM + 2;
|
||||
else
|
||||
mainwidth = w->sx - totalcolumns;
|
||||
width = PANE_MINIMUM + 1;
|
||||
width = PANE_MINIMUM;
|
||||
} else
|
||||
width = (w->sx - mainwidth) / columns;
|
||||
width = (w->sx - mainwidth - (columns - 1)) / columns;
|
||||
|
||||
/* Free old tree and create a new root. */
|
||||
layout_free(w);
|
||||
lc = w->layout_root = layout_create_cell(NULL);
|
||||
layout_set_size(lc, mainwidth + columns * width, w->sy, 0, 0);
|
||||
layout_set_size(lc, mainwidth + columns * (width + 1) - 1, w->sy, 0, 0);
|
||||
layout_make_node(lc, LAYOUT_LEFTRIGHT);
|
||||
|
||||
/* Create the main pane. */
|
||||
@@ -398,7 +418,7 @@ layout_set_main_v(struct window *w)
|
||||
|
||||
/* Create the new column. */
|
||||
lccolumn = layout_create_cell(lc);
|
||||
layout_set_size(lccolumn, width - 1, w->sy, 0, 0);
|
||||
layout_set_size(lccolumn, width, w->sy, 0, 0);
|
||||
TAILQ_INSERT_TAIL(&lc->cells, lccolumn, entry);
|
||||
|
||||
/* If only one row, just use the row directly. */
|
||||
@@ -413,7 +433,7 @@ layout_set_main_v(struct window *w)
|
||||
for (i = 0; i < rows; i++) {
|
||||
/* Create and add a pane cell. */
|
||||
lcchild = layout_create_cell(lccolumn);
|
||||
layout_set_size(lcchild, width - 1, height - 1, 0, 0);
|
||||
layout_set_size(lcchild, width, height, 0, 0);
|
||||
layout_make_leaf(lcchild, wp);
|
||||
TAILQ_INSERT_TAIL(&lccolumn->cells, lcchild, entry);
|
||||
|
||||
@@ -425,7 +445,7 @@ layout_set_main_v(struct window *w)
|
||||
/* Adjust the column to fit the full height if necessary. */
|
||||
if (i == rows)
|
||||
i--;
|
||||
used = ((i + 1) * height) - 1;
|
||||
used = ((i + 1) * (height + 1)) - 1;
|
||||
if (w->sy <= used)
|
||||
continue;
|
||||
lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells);
|
||||
@@ -433,7 +453,7 @@ layout_set_main_v(struct window *w)
|
||||
}
|
||||
|
||||
/* Adjust the last column width to fit if necessary. */
|
||||
used = mainwidth + (columns * width) - 1;
|
||||
used = mainwidth + (columns * width) + columns - 1;
|
||||
if (w->sx > used) {
|
||||
lccolumn = TAILQ_LAST(&lc->cells, layout_cells);
|
||||
layout_resize_adjust(lccolumn, LAYOUT_LEFTRIGHT, w->sx - used);
|
||||
@@ -447,3 +467,103 @@ layout_set_main_v(struct window *w)
|
||||
|
||||
server_redraw_window(w);
|
||||
}
|
||||
|
||||
void
|
||||
layout_set_tiled(struct window *w)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
struct layout_cell *lc, *lcrow, *lcchild;
|
||||
u_int n, width, height, used;
|
||||
u_int i, j, columns, rows;
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
/* Get number of panes. */
|
||||
n = window_count_panes(w);
|
||||
if (n <= 1)
|
||||
return;
|
||||
|
||||
/* How many rows and columns are wanted? */
|
||||
rows = columns = 1;
|
||||
while (rows * columns < n) {
|
||||
rows++;
|
||||
if (rows * columns < n)
|
||||
columns++;
|
||||
}
|
||||
|
||||
/* What width and height should they be? */
|
||||
width = (w->sx - (columns - 1)) / columns;
|
||||
if (width < PANE_MINIMUM)
|
||||
width = PANE_MINIMUM;
|
||||
height = (w->sy - (rows - 1)) / rows;
|
||||
if (height < PANE_MINIMUM)
|
||||
height = PANE_MINIMUM;
|
||||
|
||||
/* Free old tree and create a new root. */
|
||||
layout_free(w);
|
||||
lc = w->layout_root = layout_create_cell(NULL);
|
||||
layout_set_size(lc, (width + 1) * columns - 1,
|
||||
(height + 1) * rows - 1, 0, 0);
|
||||
layout_make_node(lc, LAYOUT_TOPBOTTOM);
|
||||
|
||||
/* Create a grid of the cells. */
|
||||
wp = TAILQ_FIRST(&w->panes);
|
||||
for (j = 0; j < rows; j++) {
|
||||
/* If this is the last cell, all done. */
|
||||
if (wp == NULL)
|
||||
break;
|
||||
|
||||
/* Create the new row. */
|
||||
lcrow = layout_create_cell(lc);
|
||||
layout_set_size(lcrow, w->sx, height, 0, 0);
|
||||
TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
|
||||
|
||||
/* If only one column, just use the row directly. */
|
||||
if (n - (j * columns) == 1) {
|
||||
layout_make_leaf(lcrow, wp);
|
||||
wp = TAILQ_NEXT(wp, entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Add in the columns. */
|
||||
layout_make_node(lcrow, LAYOUT_LEFTRIGHT);
|
||||
for (i = 0; i < columns; i++) {
|
||||
/* Create and add a pane cell. */
|
||||
lcchild = layout_create_cell(lcrow);
|
||||
layout_set_size(lcchild, width, height, 0, 0);
|
||||
layout_make_leaf(lcchild, wp);
|
||||
TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
|
||||
|
||||
/* Move to the next cell. */
|
||||
if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust the row and columns to fit the full width if
|
||||
* necessary.
|
||||
*/
|
||||
if (i == columns)
|
||||
i--;
|
||||
used = ((i + 1) * (width + 1)) - 1;
|
||||
if (w->sx <= used)
|
||||
continue;
|
||||
lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
|
||||
layout_resize_adjust(lcchild, LAYOUT_LEFTRIGHT, w->sx - used);
|
||||
}
|
||||
|
||||
/* Adjust the last row height to fit if necessary. */
|
||||
used = (rows * height) + rows - 1;
|
||||
if (w->sy > used) {
|
||||
lcrow = TAILQ_LAST(&lc->cells, layout_cells);
|
||||
layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used);
|
||||
}
|
||||
|
||||
/* Fix cell offsets. */
|
||||
layout_fix_offsets(lc);
|
||||
layout_fix_panes(w, w->sx, w->sy);
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
server_redraw_window(w);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: layout-string.c,v 1.3 2010-01-08 16:28:04 tcunha Exp $ */
|
||||
/* $Id: layout-string.c,v 1.4 2010-07-02 02:54:52 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -36,7 +36,6 @@ struct layout_cell *layout_find_right(struct layout_cell *);
|
||||
struct layout_cell *layout_find_topleft(struct layout_cell *);
|
||||
struct layout_cell *layout_find_topright(struct layout_cell *);
|
||||
struct layout_cell *layout_find_bottomleft(struct layout_cell *);
|
||||
struct layout_cell *layout_find_bottomright(struct layout_cell *);
|
||||
|
||||
/* Find the cell; returns NULL if string not understood. */
|
||||
struct layout_cell *
|
||||
|
||||
130
layout.c
130
layout.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: layout.c,v 1.18 2010-01-08 16:31:35 tcunha Exp $ */
|
||||
/* $Id: layout.c,v 1.19 2010-07-02 02:54:52 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -218,6 +218,27 @@ layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
|
||||
}
|
||||
}
|
||||
|
||||
/* Count the number of available cells in a layout. */
|
||||
u_int
|
||||
layout_count_cells(struct layout_cell *lc)
|
||||
{
|
||||
struct layout_cell *lcchild;
|
||||
u_int n;
|
||||
|
||||
switch (lc->type) {
|
||||
case LAYOUT_WINDOWPANE:
|
||||
return (1);
|
||||
case LAYOUT_LEFTRIGHT:
|
||||
case LAYOUT_TOPBOTTOM:
|
||||
n = 0;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry)
|
||||
n += layout_count_cells(lcchild);
|
||||
return (n);
|
||||
default:
|
||||
fatalx("bad layout type");
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate how much size is available to be removed from a cell. */
|
||||
u_int
|
||||
layout_resize_check(struct layout_cell *lc, enum layout_type type)
|
||||
@@ -302,6 +323,56 @@ layout_resize_adjust(struct layout_cell *lc, enum layout_type type, int change)
|
||||
}
|
||||
}
|
||||
|
||||
/* Destroy a cell and redistribute the space. */
|
||||
void
|
||||
layout_destroy_cell(struct layout_cell *lc, struct layout_cell **lcroot)
|
||||
{
|
||||
struct layout_cell *lcother, *lcparent;
|
||||
|
||||
/*
|
||||
* If no parent, this is the last pane so window close is imminent and
|
||||
* there is no need to resize anything.
|
||||
*/
|
||||
lcparent = lc->parent;
|
||||
if (lcparent == NULL) {
|
||||
layout_free_cell(lc);
|
||||
*lcroot = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Merge the space into the previous or next cell. */
|
||||
if (lc == TAILQ_FIRST(&lcparent->cells))
|
||||
lcother = TAILQ_NEXT(lc, entry);
|
||||
else
|
||||
lcother = TAILQ_PREV(lc, layout_cells, entry);
|
||||
if (lcparent->type == LAYOUT_LEFTRIGHT)
|
||||
layout_resize_adjust(lcother, lcparent->type, lc->sx + 1);
|
||||
else
|
||||
layout_resize_adjust(lcother, lcparent->type, lc->sy + 1);
|
||||
|
||||
/* Remove this from the parent's list. */
|
||||
TAILQ_REMOVE(&lcparent->cells, lc, entry);
|
||||
layout_free_cell(lc);
|
||||
|
||||
/*
|
||||
* If the parent now has one cell, remove the parent from the tree and
|
||||
* replace it by that cell.
|
||||
*/
|
||||
lc = TAILQ_FIRST(&lcparent->cells);
|
||||
if (TAILQ_NEXT(lc, entry) == NULL) {
|
||||
TAILQ_REMOVE(&lcparent->cells, lc, entry);
|
||||
|
||||
lc->parent = lcparent->parent;
|
||||
if (lc->parent == NULL) {
|
||||
lc->xoff = 0; lc->yoff = 0;
|
||||
*lcroot = lc;
|
||||
} else
|
||||
TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry);
|
||||
|
||||
layout_free_cell(lcparent);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
layout_init(struct window *w)
|
||||
{
|
||||
@@ -597,59 +668,16 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size)
|
||||
return (lcnew);
|
||||
}
|
||||
|
||||
/* Destroy the layout associated with a pane and redistribute the space. */
|
||||
/* Destroy the cell associated with a pane. */
|
||||
void
|
||||
layout_close_pane(struct window_pane *wp)
|
||||
{
|
||||
struct layout_cell *lc, *lcother, *lcparent;
|
||||
|
||||
lc = wp->layout_cell;
|
||||
lcparent = lc->parent;
|
||||
|
||||
/*
|
||||
* If no parent, this is the last pane so window close is imminent and
|
||||
* there is no need to resize anything.
|
||||
*/
|
||||
if (lcparent == NULL) {
|
||||
layout_free_cell(lc);
|
||||
wp->window->layout_root = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Merge the space into the previous or next cell. */
|
||||
if (lc == TAILQ_FIRST(&lcparent->cells))
|
||||
lcother = TAILQ_NEXT(lc, entry);
|
||||
else
|
||||
lcother = TAILQ_PREV(lc, layout_cells, entry);
|
||||
if (lcparent->type == LAYOUT_LEFTRIGHT)
|
||||
layout_resize_adjust(lcother, lcparent->type, lc->sx + 1);
|
||||
else
|
||||
layout_resize_adjust(lcother, lcparent->type, lc->sy + 1);
|
||||
|
||||
/* Remove this from the parent's list. */
|
||||
TAILQ_REMOVE(&lcparent->cells, lc, entry);
|
||||
layout_free_cell(lc);
|
||||
|
||||
/*
|
||||
* If the parent now has one cell, remove the parent from the tree and
|
||||
* replace it by that cell.
|
||||
*/
|
||||
lc = TAILQ_FIRST(&lcparent->cells);
|
||||
if (TAILQ_NEXT(lc, entry) == NULL) {
|
||||
TAILQ_REMOVE(&lcparent->cells, lc, entry);
|
||||
|
||||
lc->parent = lcparent->parent;
|
||||
if (lc->parent == NULL) {
|
||||
lc->xoff = 0; lc->yoff = 0;
|
||||
wp->window->layout_root = lc;
|
||||
} else
|
||||
TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry);
|
||||
|
||||
layout_free_cell(lcparent);
|
||||
}
|
||||
/* Remove the cell. */
|
||||
layout_destroy_cell(wp->layout_cell, &wp->window->layout_root);
|
||||
|
||||
/* Fix pane offsets and sizes. */
|
||||
layout_fix_offsets(wp->window->layout_root);
|
||||
layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
|
||||
if (wp->window->layout_root != NULL) {
|
||||
layout_fix_offsets(wp->window->layout_root);
|
||||
layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
15
mode-key.c
15
mode-key.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: mode-key.c,v 1.45 2010-03-08 15:02:07 tcunha Exp $ */
|
||||
/* $Id: mode-key.c,v 1.46 2010-03-16 17:30:58 micahcowan Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -88,6 +88,10 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
|
||||
{ MODEKEYCOPY_GOTOLINE, "goto-line" },
|
||||
{ MODEKEYCOPY_HISTORYBOTTOM, "history-bottom" },
|
||||
{ MODEKEYCOPY_HISTORYTOP, "history-top" },
|
||||
{ MODEKEYCOPY_JUMP, "jump-forward" },
|
||||
{ MODEKEYCOPY_JUMPAGAIN, "jump-again" },
|
||||
{ MODEKEYCOPY_JUMPREVERSE, "jump-reverse" },
|
||||
{ MODEKEYCOPY_JUMPBACK, "jump-backward" },
|
||||
{ MODEKEYCOPY_LEFT, "cursor-left" },
|
||||
{ MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" },
|
||||
{ MODEKEYCOPY_MIDDLELINE, "middle-line" },
|
||||
@@ -177,6 +181,8 @@ struct mode_key_tree mode_key_tree_vi_choice;
|
||||
const struct mode_key_entry mode_key_vi_copy[] = {
|
||||
{ ' ', 0, MODEKEYCOPY_STARTSELECTION },
|
||||
{ '$', 0, MODEKEYCOPY_ENDOFLINE },
|
||||
{ ',', 0, MODEKEYCOPY_JUMPREVERSE },
|
||||
{ ';', 0, MODEKEYCOPY_JUMPAGAIN },
|
||||
{ '/', 0, MODEKEYCOPY_SEARCHDOWN },
|
||||
{ '0', 0, MODEKEYCOPY_STARTOFLINE },
|
||||
{ '1', 0, MODEKEYCOPY_STARTNUMBERPREFIX },
|
||||
@@ -192,6 +198,7 @@ const struct mode_key_entry mode_key_vi_copy[] = {
|
||||
{ '?', 0, MODEKEYCOPY_SEARCHUP },
|
||||
{ 'B', 0, MODEKEYCOPY_PREVIOUSSPACE },
|
||||
{ 'E', 0, MODEKEYCOPY_NEXTSPACEEND },
|
||||
{ 'F', 0, MODEKEYCOPY_JUMPBACK },
|
||||
{ 'G', 0, MODEKEYCOPY_HISTORYBOTTOM },
|
||||
{ 'H', 0, MODEKEYCOPY_TOPLINE },
|
||||
{ 'J', 0, MODEKEYCOPY_SCROLLDOWN },
|
||||
@@ -213,6 +220,7 @@ const struct mode_key_entry mode_key_vi_copy[] = {
|
||||
{ '^', 0, MODEKEYCOPY_BACKTOINDENTATION },
|
||||
{ 'b', 0, MODEKEYCOPY_PREVIOUSWORD },
|
||||
{ 'e', 0, MODEKEYCOPY_NEXTWORDEND },
|
||||
{ 'f', 0, MODEKEYCOPY_JUMP },
|
||||
{ 'g', 0, MODEKEYCOPY_HISTORYTOP },
|
||||
{ 'h', 0, MODEKEYCOPY_LEFT },
|
||||
{ 'j', 0, MODEKEYCOPY_DOWN },
|
||||
@@ -290,6 +298,8 @@ struct mode_key_tree mode_key_tree_emacs_choice;
|
||||
/* emacs copy mode keys. */
|
||||
const struct mode_key_entry mode_key_emacs_copy[] = {
|
||||
{ ' ', 0, MODEKEYCOPY_NEXTPAGE },
|
||||
{ ',', 0, MODEKEYCOPY_JUMPREVERSE },
|
||||
{ ';', 0, MODEKEYCOPY_JUMPAGAIN },
|
||||
{ '1' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
|
||||
{ '2' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
|
||||
{ '3' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
|
||||
@@ -301,6 +311,8 @@ const struct mode_key_entry mode_key_emacs_copy[] = {
|
||||
{ '9' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
|
||||
{ '<' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYTOP },
|
||||
{ '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM },
|
||||
{ 'F', 0, MODEKEYCOPY_JUMPBACK },
|
||||
{ 'N', 0, MODEKEYCOPY_SEARCHREVERSE },
|
||||
{ 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE },
|
||||
{ 'R', 0, MODEKEYCOPY_RECTANGLETOGGLE },
|
||||
{ '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION },
|
||||
@@ -319,6 +331,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = {
|
||||
{ '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL },
|
||||
{ 'N', 0, MODEKEYCOPY_SEARCHREVERSE },
|
||||
{ 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD },
|
||||
{ 'f', 0, MODEKEYCOPY_JUMP },
|
||||
{ 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORDEND },
|
||||
{ 'g', 0, MODEKEYCOPY_GOTOLINE },
|
||||
{ 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION },
|
||||
|
||||
26
paste.c
26
paste.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: paste.c,v 1.13 2009-12-04 22:14:47 tcunha Exp $ */
|
||||
/* $Id: paste.c,v 1.15 2010-06-22 23:36:54 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -156,3 +156,27 @@ paste_replace(struct paste_stack *ps, u_int idx, char *data, size_t size)
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Convert a buffer into a visible string. */
|
||||
char *
|
||||
paste_print(struct paste_buffer *pb, size_t width)
|
||||
{
|
||||
char *buf;
|
||||
size_t len, used;
|
||||
|
||||
if (width < 3)
|
||||
width = 3;
|
||||
buf = xmalloc(width * 4 + 1);
|
||||
|
||||
len = pb->size;
|
||||
if (len > width)
|
||||
len = width;
|
||||
|
||||
used = strvisx(buf, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL);
|
||||
if (pb->size > width || used > width) {
|
||||
buf[width - 3] = '\0';
|
||||
strlcat(buf, "...", width);
|
||||
}
|
||||
|
||||
return (buf);
|
||||
}
|
||||
|
||||
20
resize.c
20
resize.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: resize.c,v 1.24 2009-09-25 17:47:42 tcunha Exp $ */
|
||||
/* $Id: resize.c,v 1.27 2010-12-22 15:36:44 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -52,11 +52,7 @@ recalculate_sizes(void)
|
||||
u_int i, j, ssx, ssy, has, limit;
|
||||
int flag;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
s = ARRAY_ITEM(&sessions, i);
|
||||
if (s == NULL)
|
||||
continue;
|
||||
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
ssx = ssy = UINT_MAX;
|
||||
for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
|
||||
c = ARRAY_ITEM(&clients, j);
|
||||
@@ -98,14 +94,13 @@ recalculate_sizes(void)
|
||||
flag = options_get_number(&w->options, "aggressive-resize");
|
||||
|
||||
ssx = ssy = UINT_MAX;
|
||||
for (j = 0; j < ARRAY_LENGTH(&sessions); j++) {
|
||||
s = ARRAY_ITEM(&sessions, j);
|
||||
if (s == NULL || s->flags & SESSION_UNATTACHED)
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
if (s->flags & SESSION_UNATTACHED)
|
||||
continue;
|
||||
if (flag)
|
||||
has = s->curw->window == w;
|
||||
else
|
||||
has = session_has(s, w);
|
||||
has = session_has(s, w) != NULL;
|
||||
if (has) {
|
||||
if (s->sx < ssx)
|
||||
ssx = s->sx;
|
||||
@@ -113,11 +108,8 @@ recalculate_sizes(void)
|
||||
ssy = s->sy;
|
||||
}
|
||||
}
|
||||
if (ssx == UINT_MAX || ssy == UINT_MAX) {
|
||||
w->flags |= WINDOW_HIDDEN;
|
||||
if (ssx == UINT_MAX || ssy == UINT_MAX)
|
||||
continue;
|
||||
}
|
||||
w->flags &= ~WINDOW_HIDDEN;
|
||||
|
||||
limit = options_get_number(&w->options, "force-width");
|
||||
if (limit != 0 && ssx > limit)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: screen-redraw.c,v 1.52 2010-02-05 01:31:06 tcunha Exp $ */
|
||||
/* $Id: screen-redraw.c,v 1.53 2010-09-18 15:43:53 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -41,6 +41,8 @@ void screen_redraw_draw_number(struct client *, struct window_pane *);
|
||||
#define CELL_JOIN 11
|
||||
#define CELL_OUTSIDE 12
|
||||
|
||||
#define CELL_BORDERS " xqlkmjwvtun~"
|
||||
|
||||
/* Check if cell is on the border of a particular pane. */
|
||||
int
|
||||
screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py)
|
||||
@@ -173,8 +175,6 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only)
|
||||
struct grid_cell active_gc, other_gc;
|
||||
u_int i, j, type;
|
||||
int status, fg, bg;
|
||||
const u_char *base, *ptr;
|
||||
u_char ch, border[20];
|
||||
|
||||
/* Get status line, er, status. */
|
||||
if (c->message_string != NULL || c->prompt_string != NULL)
|
||||
@@ -193,6 +193,7 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only)
|
||||
memcpy(&other_gc, &grid_default_cell, sizeof other_gc);
|
||||
memcpy(&active_gc, &grid_default_cell, sizeof active_gc);
|
||||
active_gc.data = other_gc.data = 'x'; /* not space */
|
||||
active_gc.attr = other_gc.attr = GRID_ATTR_CHARSET;
|
||||
fg = options_get_number(&c->session->options, "pane-border-fg");
|
||||
colour_set_fg(&other_gc, fg);
|
||||
bg = options_get_number(&c->session->options, "pane-border-bg");
|
||||
@@ -203,16 +204,6 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only)
|
||||
colour_set_bg(&active_gc, bg);
|
||||
|
||||
/* Draw background and borders. */
|
||||
strlcpy(border, " |-....--||+.", sizeof border);
|
||||
if (tty_term_has(tty->term, TTYC_ACSC)) {
|
||||
base = " xqlkmjwvtun~";
|
||||
for (ptr = base; *ptr != '\0'; ptr++) {
|
||||
if ((ch = tty_get_acs(tty, *ptr)) != '\0')
|
||||
border[ptr - base] = ch;
|
||||
}
|
||||
other_gc.attr |= GRID_ATTR_CHARSET;
|
||||
active_gc.attr |= GRID_ATTR_CHARSET;
|
||||
}
|
||||
for (j = 0; j < tty->sy - status; j++) {
|
||||
if (status_only && j != tty->sy - 1)
|
||||
continue;
|
||||
@@ -225,7 +216,7 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only)
|
||||
else
|
||||
tty_attributes(tty, &other_gc);
|
||||
tty_cursor(tty, i, j);
|
||||
tty_putc(tty, border[type]);
|
||||
tty_putc(tty, CELL_BORDERS[type]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: screen-write.c,v 1.88 2009-12-04 22:14:47 tcunha Exp $ */
|
||||
/* $Id: screen-write.c,v 1.90 2010-06-16 18:09:23 micahcowan Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "tmux.h"
|
||||
|
||||
void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *, int);
|
||||
void screen_write_overwrite(struct screen_write_ctx *);
|
||||
void screen_write_overwrite(struct screen_write_ctx *, u_int);
|
||||
int screen_write_combine(
|
||||
struct screen_write_ctx *, const struct utf8_data *);
|
||||
|
||||
@@ -1009,17 +1009,18 @@ screen_write_cell(struct screen_write_ctx *ctx,
|
||||
}
|
||||
|
||||
/* Check this will fit on the current line and wrap if not. */
|
||||
if (s->cx > screen_size_x(s) - width) {
|
||||
if ((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) {
|
||||
screen_write_linefeed(ctx, 1);
|
||||
s->cx = 0; /* carriage return */
|
||||
}
|
||||
|
||||
/* Sanity checks. */
|
||||
if (s->cx > screen_size_x(s) - 1 || s->cy > screen_size_y(s) - 1)
|
||||
if (((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - 1)
|
||||
|| s->cy > screen_size_y(s) - 1)
|
||||
return;
|
||||
|
||||
/* Handle overwriting of UTF-8 characters. */
|
||||
screen_write_overwrite(ctx);
|
||||
screen_write_overwrite(ctx, width);
|
||||
|
||||
/*
|
||||
* If the new character is UTF-8 wide, fill in padding cells. Have
|
||||
@@ -1122,12 +1123,11 @@ screen_write_combine(
|
||||
* by the same character.
|
||||
*/
|
||||
void
|
||||
screen_write_overwrite(struct screen_write_ctx *ctx)
|
||||
screen_write_overwrite(struct screen_write_ctx *ctx, u_int width)
|
||||
{
|
||||
struct screen *s = ctx->s;
|
||||
struct grid *gd = s->grid;
|
||||
const struct grid_cell *gc;
|
||||
const struct grid_utf8 *gu;
|
||||
u_int xx;
|
||||
|
||||
gc = grid_view_peek_cell(gd, s->cx, s->cy);
|
||||
@@ -1147,30 +1147,17 @@ screen_write_overwrite(struct screen_write_ctx *ctx)
|
||||
|
||||
/* Overwrite the character at the start of this padding. */
|
||||
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
|
||||
}
|
||||
|
||||
/* Overwrite following padding cells. */
|
||||
xx = s->cx;
|
||||
while (++xx < screen_size_x(s)) {
|
||||
gc = grid_view_peek_cell(gd, xx, s->cy);
|
||||
if (!(gc->flags & GRID_FLAG_PADDING))
|
||||
break;
|
||||
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
|
||||
}
|
||||
} else if (gc->flags & GRID_FLAG_UTF8) {
|
||||
gu = grid_view_peek_utf8(gd, s->cx, s->cy);
|
||||
if (gu->width > 1) {
|
||||
/*
|
||||
* An UTF-8 wide cell; overwrite following padding
|
||||
* cells only.
|
||||
*/
|
||||
xx = s->cx;
|
||||
while (++xx < screen_size_x(s)) {
|
||||
gc = grid_view_peek_cell(gd, xx, s->cy);
|
||||
if (!(gc->flags & GRID_FLAG_PADDING))
|
||||
break;
|
||||
grid_view_set_cell(
|
||||
gd, xx, s->cy, &grid_default_cell);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Overwrite any padding cells that belong to a UTF-8 character
|
||||
* we'll be overwriting with the current character.
|
||||
*/
|
||||
xx = s->cx + width - 1;
|
||||
while (++xx < screen_size_x(s)) {
|
||||
gc = grid_view_peek_cell(gd, xx, s->cy);
|
||||
if (!(gc->flags & GRID_FLAG_PADDING))
|
||||
break;
|
||||
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
|
||||
}
|
||||
}
|
||||
|
||||
17
screen.c
17
screen.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: screen.c,v 1.99 2010-02-08 18:13:17 tcunha Exp $ */
|
||||
/* $Id: screen.c,v 1.103 2010-12-11 17:57:28 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -18,8 +18,10 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
@@ -30,9 +32,14 @@ void screen_resize_y(struct screen *, u_int);
|
||||
void
|
||||
screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
|
||||
{
|
||||
char hn[MAXHOSTNAMELEN];
|
||||
|
||||
s->grid = grid_create(sx, sy, hlimit);
|
||||
|
||||
s->title = xstrdup("");
|
||||
if (gethostname(hn, MAXHOSTNAMELEN) == 0)
|
||||
s->title = xstrdup(hn);
|
||||
else
|
||||
s->title = xstrdup("");
|
||||
|
||||
s->tabs = NULL;
|
||||
|
||||
@@ -49,7 +56,7 @@ screen_reinit(struct screen *s)
|
||||
s->rupper = 0;
|
||||
s->rlower = screen_size_y(s) - 1;
|
||||
|
||||
s->mode = MODE_CURSOR;
|
||||
s->mode = MODE_CURSOR | MODE_WRAP;
|
||||
|
||||
screen_reset_tabs(s);
|
||||
|
||||
@@ -280,7 +287,7 @@ screen_check_selection(struct screen *s, u_int px, u_int py)
|
||||
*/
|
||||
if (sel->ex < sel->sx) {
|
||||
/* Cursor (ex) is on the left. */
|
||||
if (px <= sel->ex)
|
||||
if (px < sel->ex)
|
||||
return (0);
|
||||
|
||||
if (px > sel->sx)
|
||||
@@ -290,7 +297,7 @@ screen_check_selection(struct screen *s, u_int px, u_int py)
|
||||
if (px < sel->sx)
|
||||
return (0);
|
||||
|
||||
if (px >= sel->ex)
|
||||
if (px > sel->ex)
|
||||
return (0);
|
||||
}
|
||||
} else {
|
||||
|
||||
245
server-client.c
245
server-client.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: server-client.c,v 1.31 2010-02-08 18:27:34 tcunha Exp $ */
|
||||
/* $Id: server-client.c,v 1.48 2010-12-22 15:31:00 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -28,9 +28,14 @@
|
||||
|
||||
void server_client_handle_key(int, struct mouse_event *, void *);
|
||||
void server_client_repeat_timer(int, short, void *);
|
||||
void server_client_check_exit(struct client *);
|
||||
void server_client_check_backoff(struct client *);
|
||||
void server_client_check_redraw(struct client *);
|
||||
void server_client_set_title(struct client *);
|
||||
void server_client_reset_state(struct client *);
|
||||
void server_client_in_callback(struct bufferevent *, short, void *);
|
||||
void server_client_out_callback(struct bufferevent *, short, void *);
|
||||
void server_client_err_callback(struct bufferevent *, short, void *);
|
||||
|
||||
int server_client_msg_dispatch(struct client *);
|
||||
void server_client_msg_command(struct client *, struct msg_command_data *);
|
||||
@@ -54,8 +59,6 @@ server_client_create(int fd)
|
||||
fatal("fcntl failed");
|
||||
if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
|
||||
fatal("fcntl failed");
|
||||
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
|
||||
fatal("fcntl failed");
|
||||
|
||||
c = xcalloc(1, sizeof *c);
|
||||
c->references = 0;
|
||||
@@ -66,12 +69,15 @@ server_client_create(int fd)
|
||||
fatal("gettimeofday failed");
|
||||
memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time);
|
||||
|
||||
ARRAY_INIT(&c->prompt_hdata);
|
||||
c->stdin_event = NULL;
|
||||
c->stdout_event = NULL;
|
||||
c->stderr_event = NULL;
|
||||
|
||||
c->tty.fd = -1;
|
||||
c->title = NULL;
|
||||
|
||||
c->session = NULL;
|
||||
c->last_session = NULL;
|
||||
c->tty.sx = 80;
|
||||
c->tty.sy = 24;
|
||||
|
||||
@@ -117,6 +123,19 @@ server_client_lost(struct client *c)
|
||||
if (c->flags & CLIENT_TERMINAL)
|
||||
tty_free(&c->tty);
|
||||
|
||||
if (c->stdin_fd != -1)
|
||||
close(c->stdin_fd);
|
||||
if (c->stdin_event != NULL)
|
||||
bufferevent_free(c->stdin_event);
|
||||
if (c->stdout_fd != -1)
|
||||
close(c->stdout_fd);
|
||||
if (c->stdout_event != NULL)
|
||||
bufferevent_free(c->stdout_event);
|
||||
if (c->stderr_fd != -1)
|
||||
close(c->stderr_fd);
|
||||
if (c->stderr_event != NULL)
|
||||
bufferevent_free(c->stderr_event);
|
||||
|
||||
screen_free(&c->status);
|
||||
job_tree_free(&c->status_jobs);
|
||||
|
||||
@@ -140,9 +159,6 @@ server_client_lost(struct client *c)
|
||||
xfree(c->prompt_string);
|
||||
if (c->prompt_buffer != NULL)
|
||||
xfree(c->prompt_buffer);
|
||||
for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++)
|
||||
xfree(ARRAY_ITEM(&c->prompt_hdata, i));
|
||||
ARRAY_FREE(&c->prompt_hdata);
|
||||
|
||||
if (c->cwd != NULL)
|
||||
xfree(c->cwd);
|
||||
@@ -162,6 +178,7 @@ server_client_lost(struct client *c)
|
||||
c->flags |= CLIENT_DEAD;
|
||||
|
||||
recalculate_sizes();
|
||||
server_check_unattached();
|
||||
server_update_socket();
|
||||
}
|
||||
|
||||
@@ -299,7 +316,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data)
|
||||
server_redraw_window_borders(w);
|
||||
wp = w->active;
|
||||
}
|
||||
window_pane_mouse(wp, c, mouse);
|
||||
window_pane_mouse(wp, c->session, mouse);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -321,7 +338,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data)
|
||||
/* Try as a non-prefix key binding. */
|
||||
if ((bd = key_bindings_lookup(key)) == NULL) {
|
||||
if (!(c->flags & CLIENT_READONLY))
|
||||
window_pane_key(wp, c, key);
|
||||
window_pane_key(wp, c->session, key);
|
||||
} else
|
||||
key_bindings_dispatch(bd, c);
|
||||
}
|
||||
@@ -337,7 +354,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data)
|
||||
if (isprefix)
|
||||
c->flags |= CLIENT_PREFIX;
|
||||
else if (!(c->flags & CLIENT_READONLY))
|
||||
window_pane_key(wp, c, key);
|
||||
window_pane_key(wp, c->session, key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -348,7 +365,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data)
|
||||
if (isprefix)
|
||||
c->flags |= CLIENT_PREFIX;
|
||||
else if (!(c->flags & CLIENT_READONLY))
|
||||
window_pane_key(wp, c, key);
|
||||
window_pane_key(wp, c->session, key);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -378,11 +395,14 @@ server_client_loop(void)
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
c = ARRAY_ITEM(&clients, i);
|
||||
if (c == NULL || c->session == NULL)
|
||||
if (c == NULL)
|
||||
continue;
|
||||
|
||||
server_client_check_redraw(c);
|
||||
server_client_reset_state(c);
|
||||
server_client_check_exit(c);
|
||||
if (c->session != NULL) {
|
||||
server_client_check_redraw(c);
|
||||
server_client_reset_state(c);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -445,6 +465,72 @@ server_client_repeat_timer(unused int fd, unused short events, void *data)
|
||||
c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
|
||||
}
|
||||
|
||||
/* Check if client should be exited. */
|
||||
void
|
||||
server_client_check_exit(struct client *c)
|
||||
{
|
||||
struct msg_exit_data exitdata;
|
||||
|
||||
if (!(c->flags & CLIENT_EXIT))
|
||||
return;
|
||||
|
||||
if (c->stdout_fd != -1 && c->stdout_event != NULL &&
|
||||
EVBUFFER_LENGTH(c->stdout_event->output) != 0)
|
||||
return;
|
||||
if (c->stderr_fd != -1 && c->stderr_event != NULL &&
|
||||
EVBUFFER_LENGTH(c->stderr_event->output) != 0)
|
||||
return;
|
||||
|
||||
exitdata.retcode = c->retcode;
|
||||
server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata);
|
||||
|
||||
c->flags &= ~CLIENT_EXIT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the client should backoff. During backoff, data from external
|
||||
* programs is not written to the terminal. When the existing data drains, the
|
||||
* client is redrawn.
|
||||
*
|
||||
* There are two backoff phases - both the tty and client have backoff flags -
|
||||
* the first to allow existing data to drain and the latter to ensure backoff
|
||||
* is disabled until the redraw has finished and prevent the redraw triggering
|
||||
* another backoff.
|
||||
*/
|
||||
void
|
||||
server_client_check_backoff(struct client *c)
|
||||
{
|
||||
struct tty *tty = &c->tty;
|
||||
size_t used;
|
||||
|
||||
used = EVBUFFER_LENGTH(tty->event->output);
|
||||
|
||||
/*
|
||||
* If in the second backoff phase (redrawing), don't check backoff
|
||||
* until the redraw has completed (or enough of it to drop below the
|
||||
* backoff threshold).
|
||||
*/
|
||||
if (c->flags & CLIENT_BACKOFF) {
|
||||
if (used > BACKOFF_THRESHOLD)
|
||||
return;
|
||||
c->flags &= ~CLIENT_BACKOFF;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Once drained, allow data through again and schedule redraw. */
|
||||
if (tty->flags & TTY_BACKOFF) {
|
||||
if (used != 0)
|
||||
return;
|
||||
tty->flags &= ~TTY_BACKOFF;
|
||||
c->flags |= (CLIENT_BACKOFF|CLIENT_REDRAWWINDOW|CLIENT_STATUS);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If too much data, start backoff. */
|
||||
if (used > BACKOFF_THRESHOLD)
|
||||
tty->flags |= TTY_BACKOFF;
|
||||
}
|
||||
|
||||
/* Check for client redraws. */
|
||||
void
|
||||
server_client_check_redraw(struct client *c)
|
||||
@@ -473,6 +559,10 @@ server_client_check_redraw(struct client *c)
|
||||
if (c->flags & CLIENT_REDRAW) {
|
||||
screen_redraw_screen(c, 0, 0);
|
||||
c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS);
|
||||
} else if (c->flags & CLIENT_REDRAWWINDOW) {
|
||||
TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry)
|
||||
screen_redraw_pane(c, wp);
|
||||
c->flags &= ~CLIENT_REDRAWWINDOW;
|
||||
} else {
|
||||
TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
|
||||
if (wp->flags & PANE_REDRAW)
|
||||
@@ -511,6 +601,52 @@ server_client_set_title(struct client *c)
|
||||
xfree(title);
|
||||
}
|
||||
|
||||
/*
|
||||
* Error callback for client stdin. Caller must increase reference count when
|
||||
* enabling event!
|
||||
*/
|
||||
void
|
||||
server_client_in_callback(
|
||||
unused struct bufferevent *bufev, unused short what, void *data)
|
||||
{
|
||||
struct client *c = data;
|
||||
|
||||
c->references--;
|
||||
if (c->flags & CLIENT_DEAD)
|
||||
return;
|
||||
|
||||
bufferevent_disable(c->stdin_event, EV_READ|EV_WRITE);
|
||||
close(c->stdin_fd);
|
||||
c->stdin_fd = -1;
|
||||
|
||||
if (c->stdin_callback != NULL)
|
||||
c->stdin_callback(c, c->stdin_data);
|
||||
}
|
||||
|
||||
/* Error callback for client stdout. */
|
||||
void
|
||||
server_client_out_callback(
|
||||
unused struct bufferevent *bufev, unused short what, unused void *data)
|
||||
{
|
||||
struct client *c = data;
|
||||
|
||||
bufferevent_disable(c->stdout_event, EV_READ|EV_WRITE);
|
||||
close(c->stdout_fd);
|
||||
c->stdout_fd = -1;
|
||||
}
|
||||
|
||||
/* Error callback for client stderr. */
|
||||
void
|
||||
server_client_err_callback(
|
||||
unused struct bufferevent *bufev, unused short what, unused void *data)
|
||||
{
|
||||
struct client *c = data;
|
||||
|
||||
bufferevent_disable(c->stderr_event, EV_READ|EV_WRITE);
|
||||
close(c->stderr_fd);
|
||||
c->stderr_fd = -1;
|
||||
}
|
||||
|
||||
/* Dispatch message from client. */
|
||||
int
|
||||
server_client_msg_dispatch(struct client *c)
|
||||
@@ -520,6 +656,7 @@ server_client_msg_dispatch(struct client *c)
|
||||
struct msg_identify_data identifydata;
|
||||
struct msg_environ_data environdata;
|
||||
ssize_t n, datalen;
|
||||
int mode;
|
||||
|
||||
if ((n = imsg_read(&c->ibuf)) == -1 || n == 0)
|
||||
return (-1);
|
||||
@@ -554,15 +691,55 @@ server_client_msg_dispatch(struct client *c)
|
||||
fatalx("MSG_IDENTIFY missing fd");
|
||||
memcpy(&identifydata, imsg.data, sizeof identifydata);
|
||||
|
||||
c->stdin_fd = imsg.fd;
|
||||
c->stdin_event = bufferevent_new(c->stdin_fd,
|
||||
NULL, NULL, server_client_in_callback, c);
|
||||
if (c->stdin_event == NULL)
|
||||
fatalx("failed to create stdin event");
|
||||
|
||||
if ((mode = fcntl(c->stdin_fd, F_GETFL)) != -1)
|
||||
fcntl(c->stdin_fd, F_SETFL, mode|O_NONBLOCK);
|
||||
|
||||
server_client_msg_identify(c, &identifydata, imsg.fd);
|
||||
break;
|
||||
case MSG_STDOUT:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_STDOUT size");
|
||||
if (imsg.fd == -1)
|
||||
fatalx("MSG_STDOUT missing fd");
|
||||
|
||||
c->stdout_fd = imsg.fd;
|
||||
c->stdout_event = bufferevent_new(c->stdout_fd,
|
||||
NULL, NULL, server_client_out_callback, c);
|
||||
if (c->stdout_event == NULL)
|
||||
fatalx("failed to create stdout event");
|
||||
|
||||
if ((mode = fcntl(c->stdout_fd, F_GETFL)) != -1)
|
||||
fcntl(c->stdout_fd, F_SETFL, mode|O_NONBLOCK);
|
||||
break;
|
||||
case MSG_STDERR:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_STDERR size");
|
||||
if (imsg.fd == -1)
|
||||
fatalx("MSG_STDERR missing fd");
|
||||
|
||||
c->stderr_fd = imsg.fd;
|
||||
c->stderr_event = bufferevent_new(c->stderr_fd,
|
||||
NULL, NULL, server_client_err_callback, c);
|
||||
if (c->stderr_event == NULL)
|
||||
fatalx("failed to create stderr event");
|
||||
|
||||
if ((mode = fcntl(c->stderr_fd, F_GETFL)) != -1)
|
||||
fcntl(c->stderr_fd, F_SETFL, mode|O_NONBLOCK);
|
||||
break;
|
||||
case MSG_RESIZE:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_RESIZE size");
|
||||
|
||||
tty_resize(&c->tty);
|
||||
recalculate_sizes();
|
||||
server_redraw_client(c);
|
||||
if (tty_resize(&c->tty)) {
|
||||
recalculate_sizes();
|
||||
server_redraw_client(c);
|
||||
}
|
||||
break;
|
||||
case MSG_EXITING:
|
||||
if (datalen != 0)
|
||||
@@ -620,45 +797,43 @@ server_client_msg_dispatch(struct client *c)
|
||||
void printflike2
|
||||
server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
|
||||
{
|
||||
struct msg_print_data data;
|
||||
va_list ap;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
|
||||
evbuffer_add_vprintf(ctx->cmdclient->stderr_event->output, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
server_write_client(ctx->cmdclient, MSG_ERROR, &data, sizeof data);
|
||||
bufferevent_write(ctx->cmdclient->stderr_event, "\n", 1);
|
||||
ctx->cmdclient->retcode = 1;
|
||||
}
|
||||
|
||||
/* Callback to send print message to client. */
|
||||
void printflike2
|
||||
server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...)
|
||||
{
|
||||
struct msg_print_data data;
|
||||
va_list ap;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
|
||||
evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
|
||||
bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1);
|
||||
}
|
||||
|
||||
/* Callback to send print message to client, if not quiet. */
|
||||
void printflike2
|
||||
server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...)
|
||||
{
|
||||
struct msg_print_data data;
|
||||
va_list ap;
|
||||
va_list ap;
|
||||
|
||||
if (options_get_number(&global_options, "quiet"))
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
|
||||
evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
|
||||
bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1);
|
||||
}
|
||||
|
||||
/* Handle command message. */
|
||||
@@ -700,14 +875,14 @@ server_client_msg_command(struct client *c, struct msg_command_data *data)
|
||||
cmd_free_argv(argc, argv);
|
||||
|
||||
if (cmd_list_exec(cmdlist, &ctx) != 1)
|
||||
server_write_client(c, MSG_EXIT, NULL, 0);
|
||||
c->flags |= CLIENT_EXIT;
|
||||
cmd_list_free(cmdlist);
|
||||
return;
|
||||
|
||||
error:
|
||||
if (cmdlist != NULL)
|
||||
cmd_list_free(cmdlist);
|
||||
server_write_client(c, MSG_EXIT, NULL, 0);
|
||||
c->flags |= CLIENT_EXIT;
|
||||
}
|
||||
|
||||
/* Handle identify message. */
|
||||
@@ -715,13 +890,19 @@ void
|
||||
server_client_msg_identify(
|
||||
struct client *c, struct msg_identify_data *data, int fd)
|
||||
{
|
||||
int tty_fd;
|
||||
|
||||
c->cwd = NULL;
|
||||
data->cwd[(sizeof data->cwd) - 1] = '\0';
|
||||
if (*data->cwd != '\0')
|
||||
c->cwd = xstrdup(data->cwd);
|
||||
|
||||
if (!isatty(fd))
|
||||
return;
|
||||
if ((tty_fd = dup(fd)) == -1)
|
||||
fatal("dup failed");
|
||||
data->term[(sizeof data->term) - 1] = '\0';
|
||||
tty_init(&c->tty, fd, data->term);
|
||||
tty_init(&c->tty, tty_fd, data->term);
|
||||
if (data->flags & IDENTIFY_UTF8)
|
||||
c->tty.flags |= TTY_UTF8;
|
||||
if (data->flags & IDENTIFY_256COLOURS)
|
||||
|
||||
105
server-fn.c
105
server-fn.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: server-fn.c,v 1.102 2010-01-25 17:13:43 tcunha Exp $ */
|
||||
/* $Id: server-fn.c,v 1.117 2010-12-25 23:44:37 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -24,33 +24,22 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
void server_callback_identify(int, short, void *);
|
||||
struct session *server_next_session(struct session *);
|
||||
void server_callback_identify(int, short, void *);
|
||||
|
||||
void
|
||||
server_fill_environ(struct session *s, struct environ *env)
|
||||
{
|
||||
char tmuxvar[MAXPATHLEN], *term;
|
||||
u_int idx;
|
||||
char tmuxvar[MAXPATHLEN], *term;
|
||||
|
||||
if (session_index(s, &idx) != 0)
|
||||
fatalx("session not found");
|
||||
xsnprintf(tmuxvar, sizeof tmuxvar,
|
||||
"%s,%ld,%u", socket_path, (long) getpid(), idx);
|
||||
"%s,%ld,%u", socket_path, (long) getpid(), s->idx);
|
||||
environ_set(env, "TMUX", tmuxvar);
|
||||
|
||||
term = options_get_string(&s->options, "default-terminal");
|
||||
environ_set(env, "TERM", term);
|
||||
}
|
||||
|
||||
void
|
||||
server_write_error(struct client *c, const char *msg)
|
||||
{
|
||||
struct msg_print_data printdata;
|
||||
|
||||
strlcpy(printdata.msg, msg, sizeof printdata.msg);
|
||||
server_write_client(c, MSG_ERROR, &printdata, sizeof printdata);
|
||||
}
|
||||
|
||||
void
|
||||
server_write_client(
|
||||
struct client *c, enum msgtype type, const void *buf, size_t len)
|
||||
@@ -183,7 +172,6 @@ void
|
||||
server_status_window(struct window *w)
|
||||
{
|
||||
struct session *s;
|
||||
u_int i;
|
||||
|
||||
/*
|
||||
* This is slightly different. We want to redraw the status line of any
|
||||
@@ -191,9 +179,8 @@ server_status_window(struct window *w)
|
||||
* current window.
|
||||
*/
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
s = ARRAY_ITEM(&sessions, i);
|
||||
if (s != NULL && session_has(s, w))
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
if (session_has(s, w) != NULL)
|
||||
server_status_session(s);
|
||||
}
|
||||
}
|
||||
@@ -252,13 +239,15 @@ server_lock_client(struct client *c)
|
||||
void
|
||||
server_kill_window(struct window *w)
|
||||
{
|
||||
struct session *s;
|
||||
struct session *s, *next_s;
|
||||
struct winlink *wl;
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
s = ARRAY_ITEM(&sessions, i);
|
||||
if (s == NULL || !session_has(s, w))
|
||||
next_s = RB_MIN(sessions, &sessions);
|
||||
while (next_s != NULL) {
|
||||
s = next_s;
|
||||
next_s = RB_NEXT(sessions, &sessions, s);
|
||||
|
||||
if (session_has(s, w) == NULL)
|
||||
continue;
|
||||
while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) {
|
||||
if (session_detach(s, wl)) {
|
||||
@@ -288,14 +277,16 @@ server_link_window(struct session *src, struct winlink *srcwl,
|
||||
if (dstidx != -1)
|
||||
dstwl = winlink_find_by_index(&dst->windows, dstidx);
|
||||
if (dstwl != NULL) {
|
||||
if (dstwl->window == srcwl->window)
|
||||
return (0);
|
||||
if (dstwl->window == srcwl->window) {
|
||||
xasprintf(cause, "same index: %d", dstidx);
|
||||
return (-1);
|
||||
}
|
||||
if (killflag) {
|
||||
/*
|
||||
* Can't use session_detach as it will destroy session
|
||||
* if this makes it empty.
|
||||
*/
|
||||
session_alert_cancel(dst, dstwl);
|
||||
dstwl->flags &= ~WINLINK_ALERTFLAGS;
|
||||
winlink_stack_remove(&dst->lastw, dstwl);
|
||||
winlink_remove(&dst->windows, dstwl);
|
||||
|
||||
@@ -334,9 +325,11 @@ server_destroy_pane(struct window_pane *wp)
|
||||
{
|
||||
struct window *w = wp->window;
|
||||
|
||||
close(wp->fd);
|
||||
bufferevent_free(wp->event);
|
||||
wp->fd = -1;
|
||||
if (wp->fd != -1) {
|
||||
close(wp->fd);
|
||||
bufferevent_free(wp->event);
|
||||
wp->fd = -1;
|
||||
}
|
||||
|
||||
if (options_get_number(&w->options, "remain-on-exit"))
|
||||
return;
|
||||
@@ -365,18 +358,64 @@ server_destroy_session_group(struct session *s)
|
||||
}
|
||||
}
|
||||
|
||||
struct session *
|
||||
server_next_session(struct session *s)
|
||||
{
|
||||
struct session *s_loop, *s_out;
|
||||
|
||||
s_out = NULL;
|
||||
RB_FOREACH(s_loop, sessions, &sessions) {
|
||||
if (s_loop == s)
|
||||
continue;
|
||||
if (s_out == NULL ||
|
||||
timercmp(&s_loop->activity_time, &s_out->activity_time, <))
|
||||
s_out = s_loop;
|
||||
}
|
||||
return (s_out);
|
||||
}
|
||||
|
||||
void
|
||||
server_destroy_session(struct session *s)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *s_new;
|
||||
u_int i;
|
||||
|
||||
if (!options_get_number(&s->options, "detach-on-destroy"))
|
||||
s_new = server_next_session(s);
|
||||
else
|
||||
s_new = NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
c = ARRAY_ITEM(&clients, i);
|
||||
if (c == NULL || c->session != s)
|
||||
continue;
|
||||
c->session = NULL;
|
||||
server_write_client(c, MSG_EXIT, NULL, 0);
|
||||
if (s_new == NULL) {
|
||||
c->session = NULL;
|
||||
c->flags |= CLIENT_EXIT;
|
||||
} else {
|
||||
c->last_session = NULL;
|
||||
c->session = s_new;
|
||||
server_redraw_client(c);
|
||||
}
|
||||
}
|
||||
recalculate_sizes();
|
||||
}
|
||||
|
||||
void
|
||||
server_check_unattached (void)
|
||||
{
|
||||
struct session *s;
|
||||
|
||||
/*
|
||||
* If any sessions are no longer attached and have destroy-unattached
|
||||
* set, collect them.
|
||||
*/
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
if (!(s->flags & SESSION_UNATTACHED))
|
||||
continue;
|
||||
if (options_get_number (&s->options, "destroy-unattached"))
|
||||
session_destroy(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
153
server-window.c
153
server-window.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: server-window.c,v 1.14 2010-02-26 13:26:44 tcunha Exp $ */
|
||||
/* $Id: server-window.c,v 1.19 2010-12-22 15:36:44 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -24,90 +24,56 @@
|
||||
#include "tmux.h"
|
||||
|
||||
int server_window_backoff(struct window_pane *);
|
||||
int server_window_check_bell(struct session *, struct window *);
|
||||
int server_window_check_activity(struct session *, struct window *);
|
||||
int server_window_check_bell(struct session *, struct winlink *);
|
||||
int server_window_check_activity(struct session *, struct winlink *);
|
||||
int server_window_check_silence(struct session *, struct winlink *);
|
||||
int server_window_check_content(
|
||||
struct session *, struct window *, struct window_pane *);
|
||||
|
||||
/* Check if this window should suspend reading. */
|
||||
int
|
||||
server_window_backoff(struct window_pane *wp)
|
||||
{
|
||||
struct client *c;
|
||||
u_int i;
|
||||
|
||||
if (!window_pane_visible(wp))
|
||||
return (0);
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
c = ARRAY_ITEM(&clients, i);
|
||||
if (c == NULL || c->session == NULL)
|
||||
continue;
|
||||
if ((c->flags & (CLIENT_SUSPENDED|CLIENT_DEAD)) != 0)
|
||||
continue;
|
||||
if (c->session->curw->window != wp->window)
|
||||
continue;
|
||||
|
||||
if (EVBUFFER_LENGTH(c->tty.event->output) > BACKOFF_THRESHOLD)
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
struct session *, struct winlink *, struct window_pane *);
|
||||
|
||||
/* Window functions that need to happen every loop. */
|
||||
void
|
||||
server_window_loop(void)
|
||||
{
|
||||
struct window *w;
|
||||
struct winlink *wl;
|
||||
struct window_pane *wp;
|
||||
struct session *s;
|
||||
u_int i, j;
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
|
||||
w = ARRAY_ITEM(&windows, i);
|
||||
if (w == NULL)
|
||||
continue;
|
||||
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (wp->fd == -1)
|
||||
continue;
|
||||
if (!(wp->flags & PANE_FREEZE)) {
|
||||
if (server_window_backoff(wp))
|
||||
bufferevent_disable(wp->event, EV_READ);
|
||||
else
|
||||
bufferevent_enable(wp->event, EV_READ);
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < ARRAY_LENGTH(&sessions); j++) {
|
||||
s = ARRAY_ITEM(&sessions, j);
|
||||
if (s == NULL || !session_has(s, w))
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
wl = session_has(s, w);
|
||||
if (wl == NULL)
|
||||
continue;
|
||||
|
||||
if (server_window_check_bell(s, w) ||
|
||||
server_window_check_activity(s, w))
|
||||
if (server_window_check_bell(s, wl) ||
|
||||
server_window_check_activity(s, wl) ||
|
||||
server_window_check_silence(s, wl))
|
||||
server_status_session(s);
|
||||
TAILQ_FOREACH(wp, &w->panes, entry)
|
||||
server_window_check_content(s, w, wp);
|
||||
server_window_check_content(s, wl, wp);
|
||||
}
|
||||
w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT);
|
||||
w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for bell in window. */
|
||||
int
|
||||
server_window_check_bell(struct session *s, struct window *w)
|
||||
server_window_check_bell(struct session *s, struct winlink *wl)
|
||||
{
|
||||
struct client *c;
|
||||
struct window *w = wl->window;
|
||||
u_int i;
|
||||
int action, visual;
|
||||
|
||||
if (!(w->flags & WINDOW_BELL))
|
||||
if (!(w->flags & WINDOW_BELL) || wl->flags & WINLINK_BELL)
|
||||
return (0);
|
||||
|
||||
if (session_alert_has_window(s, w, WINDOW_BELL))
|
||||
return (0);
|
||||
session_alert_add(s, w, WINDOW_BELL);
|
||||
if (s->curw != wl)
|
||||
wl->flags |= WINLINK_BELL;
|
||||
|
||||
action = options_get_number(&s->options, "bell-action");
|
||||
switch (action) {
|
||||
@@ -155,25 +121,22 @@ server_window_check_bell(struct session *s, struct window *w)
|
||||
|
||||
/* Check for activity in window. */
|
||||
int
|
||||
server_window_check_activity(struct session *s, struct window *w)
|
||||
server_window_check_activity(struct session *s, struct winlink *wl)
|
||||
{
|
||||
struct client *c;
|
||||
struct window *w = wl->window;
|
||||
u_int i;
|
||||
|
||||
if (!(w->flags & WINDOW_ACTIVITY))
|
||||
if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY)
|
||||
return (0);
|
||||
if (s->curw->window == w)
|
||||
if (s->curw == wl)
|
||||
return (0);
|
||||
|
||||
if (!options_get_number(&w->options, "monitor-activity"))
|
||||
return (0);
|
||||
|
||||
if (session_alert_has_window(s, w, WINDOW_ACTIVITY))
|
||||
return (0);
|
||||
session_alert_add(s, w, WINDOW_ACTIVITY);
|
||||
wl->flags |= WINLINK_ACTIVITY;
|
||||
|
||||
if (s->flags & SESSION_UNATTACHED)
|
||||
return (0);
|
||||
if (options_get_number(&s->options, "visual-activity")) {
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
c = ARRAY_ITEM(&clients, i);
|
||||
@@ -187,34 +150,80 @@ server_window_check_activity(struct session *s, struct window *w)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Check for silence in window. */
|
||||
int
|
||||
server_window_check_silence(struct session *s, struct winlink *wl)
|
||||
{
|
||||
struct client *c;
|
||||
struct window *w = wl->window;
|
||||
struct timeval timer;
|
||||
u_int i;
|
||||
int silence_interval, timer_difference;
|
||||
|
||||
if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE)
|
||||
return (0);
|
||||
|
||||
if (s->curw == wl) {
|
||||
/*
|
||||
* Reset the timer for this window if we've focused it. We
|
||||
* don't want the timer tripping as soon as we've switched away
|
||||
* from this window.
|
||||
*/
|
||||
if (gettimeofday(&w->silence_timer, NULL) != 0)
|
||||
fatal("gettimeofday failed.");
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
silence_interval = options_get_number(&w->options, "monitor-silence");
|
||||
if (silence_interval == 0)
|
||||
return (0);
|
||||
|
||||
if (gettimeofday(&timer, NULL) != 0)
|
||||
fatal("gettimeofday");
|
||||
timer_difference = timer.tv_sec - w->silence_timer.tv_sec;
|
||||
if (timer_difference <= silence_interval)
|
||||
return (0);
|
||||
wl->flags |= WINLINK_SILENCE;
|
||||
|
||||
if (options_get_number(&s->options, "visual-silence")) {
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
c = ARRAY_ITEM(&clients, i);
|
||||
if (c == NULL || c->session != s)
|
||||
continue;
|
||||
status_message_set(c, "Silence in window %u",
|
||||
winlink_find_by_window(&s->windows, w)->idx);
|
||||
}
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Check for content change in window. */
|
||||
int
|
||||
server_window_check_content(
|
||||
struct session *s, struct window *w, struct window_pane *wp)
|
||||
struct session *s, struct winlink *wl, struct window_pane *wp)
|
||||
{
|
||||
struct client *c;
|
||||
struct window *w = wl->window;
|
||||
u_int i;
|
||||
char *found, *ptr;
|
||||
|
||||
if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */
|
||||
/* Activity flag must be set for new content. */
|
||||
if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_CONTENT)
|
||||
return (0);
|
||||
if (s->curw->window == w)
|
||||
if (s->curw == wl)
|
||||
return (0);
|
||||
|
||||
ptr = options_get_string(&w->options, "monitor-content");
|
||||
if (ptr == NULL || *ptr == '\0')
|
||||
return (0);
|
||||
|
||||
if (session_alert_has_window(s, w, WINDOW_CONTENT))
|
||||
return (0);
|
||||
|
||||
if ((found = window_pane_search(wp, ptr, NULL)) == NULL)
|
||||
return (0);
|
||||
xfree(found);
|
||||
|
||||
session_alert_add(s, w, WINDOW_CONTENT);
|
||||
if (s->flags & SESSION_UNATTACHED)
|
||||
return (0);
|
||||
wl->flags |= WINLINK_CONTENT;
|
||||
|
||||
if (options_get_number(&s->options, "visual-content")) {
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
c = ARRAY_ITEM(&clients, i);
|
||||
|
||||
188
server.c
188
server.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: server.c,v 1.235 2010-02-08 18:29:32 tcunha Exp $ */
|
||||
/* $Id: server.c,v 1.249 2010-12-22 15:36:44 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -48,9 +48,6 @@ struct clients dead_clients;
|
||||
int server_fd;
|
||||
int server_shutdown;
|
||||
struct event server_ev_accept;
|
||||
struct event server_ev_sigterm;
|
||||
struct event server_ev_sigusr1;
|
||||
struct event server_ev_sigchld;
|
||||
struct event server_ev_second;
|
||||
|
||||
int server_create_socket(void);
|
||||
@@ -88,7 +85,7 @@ server_create_socket(void)
|
||||
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||
fatal("socket failed");
|
||||
|
||||
mask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
|
||||
mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
|
||||
if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1)
|
||||
fatal("bind failed");
|
||||
umask(mask);
|
||||
@@ -100,8 +97,6 @@ server_create_socket(void)
|
||||
fatal("fcntl failed");
|
||||
if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
|
||||
fatal("fcntl failed");
|
||||
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
|
||||
fatal("fcntl failed");
|
||||
|
||||
server_update_socket();
|
||||
|
||||
@@ -110,16 +105,13 @@ server_create_socket(void)
|
||||
|
||||
/* Fork new server. */
|
||||
int
|
||||
server_start(char *path)
|
||||
server_start(void)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
int pair[2], retval;
|
||||
int pair[2];
|
||||
char *cause;
|
||||
struct timeval tv;
|
||||
u_int i;
|
||||
#ifdef HAVE_SETPROCTITLE
|
||||
char rpathbuf[MAXPATHLEN];
|
||||
#endif
|
||||
|
||||
/* The first client is special and gets a socketpair; create it. */
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
|
||||
@@ -143,49 +135,33 @@ server_start(char *path)
|
||||
if (daemon(1, 0) != 0)
|
||||
fatal("daemon failed");
|
||||
|
||||
/* event_init() was called in our parent, need to reinit. */
|
||||
if (event_reinit(ev_base) != 0)
|
||||
fatal("event_reinit failed");
|
||||
clear_signals(0);
|
||||
|
||||
logfile("server");
|
||||
log_debug("server started, pid %ld", (long) getpid());
|
||||
|
||||
ARRAY_INIT(&windows);
|
||||
ARRAY_INIT(&clients);
|
||||
ARRAY_INIT(&dead_clients);
|
||||
ARRAY_INIT(&sessions);
|
||||
ARRAY_INIT(&dead_sessions);
|
||||
RB_INIT(&sessions);
|
||||
RB_INIT(&dead_sessions);
|
||||
TAILQ_INIT(&session_groups);
|
||||
mode_key_init_trees();
|
||||
key_bindings_init();
|
||||
utf8_build();
|
||||
|
||||
start_time = time(NULL);
|
||||
socket_path = path;
|
||||
|
||||
#ifdef HAVE_SETPROCTITLE
|
||||
if (realpath(socket_path, rpathbuf) == NULL)
|
||||
strlcpy(rpathbuf, socket_path, sizeof rpathbuf);
|
||||
log_debug("socket path %s", socket_path);
|
||||
setproctitle("server (%s)", rpathbuf);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_BROKEN_KQUEUE
|
||||
if (setenv("EVENT_NOKQUEUE", "1", 1) != 0)
|
||||
fatal("setenv failed");
|
||||
#endif
|
||||
#ifdef HAVE_BROKEN_POLL
|
||||
if (setenv("EVENT_NOPOLL", "1", 1) != 0)
|
||||
fatal("setenv failed");
|
||||
#endif
|
||||
event_init();
|
||||
#ifdef HAVE_BROKEN_KQUEUE
|
||||
unsetenv("EVENT_NOKQUEUE");
|
||||
#endif
|
||||
#ifdef HAVE_BROKEN_POLL
|
||||
unsetenv("EVENT_NOPOLL");
|
||||
#ifdef HAVE_SETPROCTITLE
|
||||
setproctitle("server (%s)", socket_path);
|
||||
#endif
|
||||
|
||||
server_fd = server_create_socket();
|
||||
server_client_create(pair[1]);
|
||||
|
||||
retval = 0;
|
||||
if (access(SYSTEM_CFG, R_OK) == 0)
|
||||
load_cfg(SYSTEM_CFG, NULL, &cfg_causes);
|
||||
else if (errno != ENOENT) {
|
||||
@@ -199,12 +175,13 @@ server_start(char *path)
|
||||
* If there is a session already, put the current window and pane into
|
||||
* more mode.
|
||||
*/
|
||||
if (!ARRAY_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) {
|
||||
wp = ARRAY_FIRST(&sessions)->curw->window->active;
|
||||
window_pane_set_mode(wp, &window_more_mode);
|
||||
if (!RB_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) {
|
||||
wp = RB_MIN(sessions, &sessions)->curw->window->active;
|
||||
window_pane_set_mode(wp, &window_copy_mode);
|
||||
window_copy_init_for_output(wp);
|
||||
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
|
||||
cause = ARRAY_ITEM(&cfg_causes, i);
|
||||
window_more_add(wp, "%s", cause);
|
||||
window_copy_add(wp, "%s", cause);
|
||||
xfree(cause);
|
||||
}
|
||||
ARRAY_FREE(&cfg_causes);
|
||||
@@ -220,7 +197,7 @@ server_start(char *path)
|
||||
evtimer_set(&server_ev_second, server_second_callback, NULL);
|
||||
evtimer_add(&server_ev_second, &tv);
|
||||
|
||||
server_signal_set();
|
||||
set_signals(server_signal_callback);
|
||||
server_loop();
|
||||
exit(0);
|
||||
}
|
||||
@@ -240,14 +217,14 @@ server_loop(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the server should be shutting down (no more clients or windows). */
|
||||
/* Check if the server should be shutting down (no more clients or sessions). */
|
||||
int
|
||||
server_should_shutdown(void)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
if (ARRAY_ITEM(&sessions, i) != NULL)
|
||||
if (!options_get_number(&global_options, "exit-unattached")) {
|
||||
if (!RB_EMPTY(&sessions))
|
||||
return (0);
|
||||
}
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
@@ -262,7 +239,7 @@ void
|
||||
server_send_shutdown(void)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
struct session *s, *next_s;
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
@@ -276,9 +253,11 @@ server_send_shutdown(void)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
if ((s = ARRAY_ITEM(&sessions, i)) != NULL)
|
||||
session_destroy(s);
|
||||
s = RB_MIN(sessions, &sessions);
|
||||
while (s != NULL) {
|
||||
next_s = RB_NEXT(sessions, &sessions, s);
|
||||
session_destroy(s);
|
||||
s = next_s;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,16 +265,19 @@ server_send_shutdown(void)
|
||||
void
|
||||
server_clean_dead(void)
|
||||
{
|
||||
struct session *s;
|
||||
struct session *s, *next_s;
|
||||
struct client *c;
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) {
|
||||
s = ARRAY_ITEM(&dead_sessions, i);
|
||||
if (s == NULL || s->references != 0)
|
||||
continue;
|
||||
ARRAY_SET(&dead_sessions, i, NULL);
|
||||
xfree(s);
|
||||
s = RB_MIN(sessions, &dead_sessions);
|
||||
while (s != NULL) {
|
||||
next_s = RB_NEXT(sessions, &dead_sessions, s);
|
||||
if (s->references == 0) {
|
||||
RB_REMOVE(sessions, &dead_sessions, s);
|
||||
xfree(s->name);
|
||||
xfree(s);
|
||||
}
|
||||
s = next_s;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
|
||||
@@ -312,14 +294,13 @@ void
|
||||
server_update_socket(void)
|
||||
{
|
||||
struct session *s;
|
||||
u_int i;
|
||||
static int last = -1;
|
||||
int n;
|
||||
int n, mode;
|
||||
struct stat sb;
|
||||
|
||||
n = 0;
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
s = ARRAY_ITEM(&sessions, i);
|
||||
if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
if (!(s->flags & SESSION_UNATTACHED)) {
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
@@ -327,10 +308,20 @@ server_update_socket(void)
|
||||
|
||||
if (n != last) {
|
||||
last = n;
|
||||
if (n != 0)
|
||||
chmod(socket_path, S_IRWXU);
|
||||
else
|
||||
chmod(socket_path, S_IRUSR|S_IWUSR);
|
||||
|
||||
if (stat(socket_path, &sb) != 0)
|
||||
return;
|
||||
mode = sb.st_mode;
|
||||
if (n != 0) {
|
||||
if (mode & S_IRUSR)
|
||||
mode |= S_IXUSR;
|
||||
if (mode & S_IRGRP)
|
||||
mode |= S_IXGRP;
|
||||
if (mode & S_IROTH)
|
||||
mode |= S_IXOTH;
|
||||
} else
|
||||
mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
|
||||
chmod(socket_path, mode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,61 +350,6 @@ server_accept_callback(int fd, short events, unused void *data)
|
||||
server_client_create(newfd);
|
||||
}
|
||||
|
||||
/* Set up server signal handling. */
|
||||
void
|
||||
server_signal_set(void)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGINT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGHUP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
|
||||
signal_set(&server_ev_sigchld, SIGCHLD, server_signal_callback, NULL);
|
||||
signal_add(&server_ev_sigchld, NULL);
|
||||
signal_set(&server_ev_sigterm, SIGTERM, server_signal_callback, NULL);
|
||||
signal_add(&server_ev_sigterm, NULL);
|
||||
signal_set(&server_ev_sigusr1, SIGUSR1, server_signal_callback, NULL);
|
||||
signal_add(&server_ev_sigusr1, NULL);
|
||||
}
|
||||
|
||||
/* Destroy server signal events. */
|
||||
void
|
||||
server_signal_clear(void)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_DFL;
|
||||
if (sigaction(SIGINT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGHUP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
|
||||
signal_del(&server_ev_sigchld);
|
||||
signal_del(&server_ev_sigterm);
|
||||
signal_del(&server_ev_sigusr1);
|
||||
}
|
||||
|
||||
/* Signal handler. */
|
||||
/* ARGSUSED */
|
||||
void
|
||||
@@ -551,15 +487,11 @@ void
|
||||
server_lock_server(void)
|
||||
{
|
||||
struct session *s;
|
||||
u_int i;
|
||||
int timeout;
|
||||
time_t t;
|
||||
|
||||
t = time(NULL);
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
|
||||
continue;
|
||||
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
if (s->flags & SESSION_UNATTACHED) {
|
||||
if (gettimeofday(&s->activity_time, NULL) != 0)
|
||||
fatal("gettimeofday failed");
|
||||
@@ -580,15 +512,11 @@ void
|
||||
server_lock_sessions(void)
|
||||
{
|
||||
struct session *s;
|
||||
u_int i;
|
||||
int timeout;
|
||||
time_t t;
|
||||
|
||||
t = time(NULL);
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
|
||||
continue;
|
||||
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
if (s->flags & SESSION_UNATTACHED) {
|
||||
if (gettimeofday(&s->activity_time, NULL) != 0)
|
||||
fatal("gettimeofday failed");
|
||||
|
||||
234
session.c
234
session.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: session.c,v 1.74 2009-12-26 23:45:21 tcunha Exp $ */
|
||||
/* $Id: session.c,v 1.83 2010-12-22 15:36:44 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -29,71 +29,33 @@
|
||||
/* Global session list. */
|
||||
struct sessions sessions;
|
||||
struct sessions dead_sessions;
|
||||
u_int next_session;
|
||||
struct session_groups session_groups;
|
||||
|
||||
struct winlink *session_next_activity(struct session *, struct winlink *);
|
||||
struct winlink *session_previous_activity(struct session *, struct winlink *);
|
||||
struct winlink *session_next_alert(struct winlink *);
|
||||
struct winlink *session_previous_alert(struct winlink *);
|
||||
|
||||
void
|
||||
session_alert_cancel(struct session *s, struct winlink *wl)
|
||||
{
|
||||
struct session_alert *sa, *sb;
|
||||
|
||||
sa = SLIST_FIRST(&s->alerts);
|
||||
while (sa != NULL) {
|
||||
sb = sa;
|
||||
sa = SLIST_NEXT(sa, entry);
|
||||
|
||||
if (wl == NULL || sb->wl == wl) {
|
||||
SLIST_REMOVE(&s->alerts, sb, session_alert, entry);
|
||||
xfree(sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
session_alert_add(struct session *s, struct window *w, int type)
|
||||
{
|
||||
struct session_alert *sa;
|
||||
struct winlink *wl;
|
||||
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
if (wl == s->curw)
|
||||
continue;
|
||||
|
||||
if (wl->window == w &&
|
||||
!session_alert_has(s, wl, type)) {
|
||||
sa = xmalloc(sizeof *sa);
|
||||
sa->wl = wl;
|
||||
sa->type = type;
|
||||
SLIST_INSERT_HEAD(&s->alerts, sa, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
RB_GENERATE(sessions, session, entry, session_cmp);
|
||||
|
||||
int
|
||||
session_alert_has(struct session *s, struct winlink *wl, int type)
|
||||
session_cmp(struct session *s1, struct session *s2)
|
||||
{
|
||||
struct session_alert *sa;
|
||||
|
||||
SLIST_FOREACH(sa, &s->alerts, entry) {
|
||||
if (sa->wl == wl && sa->type == type)
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
return (strcmp(s1->name, s2->name));
|
||||
}
|
||||
|
||||
/*
|
||||
* Find if session is still alive. This is true if it is still on the global
|
||||
* sessions list.
|
||||
*/
|
||||
int
|
||||
session_alert_has_window(struct session *s, struct window *w, int type)
|
||||
session_alive(struct session *s)
|
||||
{
|
||||
struct session_alert *sa;
|
||||
struct session *s_loop;
|
||||
|
||||
SLIST_FOREACH(sa, &s->alerts, entry) {
|
||||
if (sa->wl->window == w && sa->type == type)
|
||||
RB_FOREACH(s_loop, sessions, &sessions) {
|
||||
if (s_loop == s)
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -101,15 +63,22 @@ session_alert_has_window(struct session *s, struct window *w, int type)
|
||||
struct session *
|
||||
session_find(const char *name)
|
||||
{
|
||||
struct session *s;
|
||||
u_int i;
|
||||
struct session s;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
s = ARRAY_ITEM(&sessions, i);
|
||||
if (s != NULL && strcmp(s->name, name) == 0)
|
||||
s.name = (char *) name;
|
||||
return (RB_FIND(sessions, &sessions, &s));
|
||||
}
|
||||
|
||||
/* Find session by index. */
|
||||
struct session *
|
||||
session_find_by_index(u_int idx)
|
||||
{
|
||||
struct session *s;
|
||||
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
if (s->idx == idx)
|
||||
return (s);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
@@ -120,7 +89,6 @@ session_create(const char *name, const char *cmd, const char *cwd,
|
||||
char **cause)
|
||||
{
|
||||
struct session *s;
|
||||
u_int i;
|
||||
|
||||
s = xmalloc(sizeof *s);
|
||||
s->references = 0;
|
||||
@@ -130,10 +98,11 @@ session_create(const char *name, const char *cmd, const char *cwd,
|
||||
fatal("gettimeofday failed");
|
||||
memcpy(&s->activity_time, &s->creation_time, sizeof s->activity_time);
|
||||
|
||||
s->cwd = xstrdup(cwd);
|
||||
|
||||
s->curw = NULL;
|
||||
TAILQ_INIT(&s->lastw);
|
||||
RB_INIT(&s->windows);
|
||||
SLIST_INIT(&s->alerts);
|
||||
|
||||
paste_init_stack(&s->buffers);
|
||||
|
||||
@@ -151,19 +120,12 @@ session_create(const char *name, const char *cmd, const char *cwd,
|
||||
s->sx = sx;
|
||||
s->sy = sy;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
if (ARRAY_ITEM(&sessions, i) == NULL) {
|
||||
ARRAY_SET(&sessions, i, s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == ARRAY_LENGTH(&sessions))
|
||||
ARRAY_ADD(&sessions, s);
|
||||
|
||||
s->idx = next_session++;
|
||||
if (name != NULL)
|
||||
s->name = xstrdup(name);
|
||||
else
|
||||
xasprintf(&s->name, "%u", i);
|
||||
xasprintf(&s->name, "%u", s->idx);
|
||||
RB_INSERT(sessions, &sessions, s);
|
||||
|
||||
if (cmd != NULL) {
|
||||
if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) {
|
||||
@@ -182,21 +144,14 @@ session_create(const char *name, const char *cmd, const char *cwd,
|
||||
void
|
||||
session_destroy(struct session *s)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
log_debug("session %s destroyed", s->name);
|
||||
|
||||
if (session_index(s, &i) != 0)
|
||||
fatalx("session not found");
|
||||
ARRAY_SET(&sessions, i, NULL);
|
||||
while (!ARRAY_EMPTY(&sessions) && ARRAY_LAST(&sessions) == NULL)
|
||||
ARRAY_TRUNC(&sessions, 1);
|
||||
RB_REMOVE(sessions, &sessions, s);
|
||||
|
||||
if (s->tio != NULL)
|
||||
xfree(s->tio);
|
||||
|
||||
session_group_remove(s);
|
||||
session_alert_cancel(s, NULL);
|
||||
environ_free(&s->environ);
|
||||
options_free(&s->options);
|
||||
paste_free_stack(&s->buffers);
|
||||
@@ -206,28 +161,49 @@ session_destroy(struct session *s)
|
||||
while (!RB_EMPTY(&s->windows))
|
||||
winlink_remove(&s->windows, RB_ROOT(&s->windows));
|
||||
|
||||
xfree(s->name);
|
||||
xfree(s->cwd);
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) {
|
||||
if (ARRAY_ITEM(&dead_sessions, i) == NULL) {
|
||||
ARRAY_SET(&dead_sessions, i, s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == ARRAY_LENGTH(&dead_sessions))
|
||||
ARRAY_ADD(&dead_sessions, s);
|
||||
s->flags |= SESSION_DEAD;
|
||||
RB_INSERT(sessions, &dead_sessions, s);
|
||||
}
|
||||
|
||||
/* Find session index. */
|
||||
int
|
||||
session_index(struct session *s, u_int *i)
|
||||
/* Find the next usable session. */
|
||||
struct session *
|
||||
session_next_session(struct session *s)
|
||||
{
|
||||
for (*i = 0; *i < ARRAY_LENGTH(&sessions); (*i)++) {
|
||||
if (s == ARRAY_ITEM(&sessions, *i))
|
||||
return (0);
|
||||
}
|
||||
return (-1);
|
||||
struct session *s2;
|
||||
|
||||
if (RB_EMPTY(&sessions) || !session_alive(s))
|
||||
return (NULL);
|
||||
|
||||
s2 = s;
|
||||
do {
|
||||
s2 = RB_NEXT(sessions, &sessions, s2);
|
||||
if (s2 == NULL)
|
||||
s2 = RB_MIN(sessions, &sessions);
|
||||
} while (s2 != s);
|
||||
if (s2 == s)
|
||||
return (NULL);
|
||||
return (s2);
|
||||
}
|
||||
|
||||
/* Find the previous usable session. */
|
||||
struct session *
|
||||
session_previous_session(struct session *s)
|
||||
{
|
||||
struct session *s2;
|
||||
|
||||
if (RB_EMPTY(&sessions) || !session_alive(s))
|
||||
return (NULL);
|
||||
|
||||
s2 = s;
|
||||
do {
|
||||
s2 = RB_PREV(sessions, &sessions, s2);
|
||||
if (s2 == NULL)
|
||||
s2 = RB_MAX(sessions, &sessions);
|
||||
} while (s2 != s);
|
||||
if (s2 == s)
|
||||
return (NULL);
|
||||
return (s2);
|
||||
}
|
||||
|
||||
/* Create a new window on a session. */
|
||||
@@ -284,7 +260,7 @@ session_detach(struct session *s, struct winlink *wl)
|
||||
session_last(s) != 0 && session_previous(s, 0) != 0)
|
||||
session_next(s, 0);
|
||||
|
||||
session_alert_cancel(s, wl);
|
||||
wl->flags &= ~WINLINK_ALERTFLAGS;
|
||||
winlink_stack_remove(&s->lastw, wl);
|
||||
winlink_remove(&s->windows, wl);
|
||||
session_group_synchronize_from(s);
|
||||
@@ -296,27 +272,23 @@ session_detach(struct session *s, struct winlink *wl)
|
||||
}
|
||||
|
||||
/* Return if session has window. */
|
||||
int
|
||||
struct winlink *
|
||||
session_has(struct session *s, struct window *w)
|
||||
{
|
||||
struct winlink *wl;
|
||||
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
if (wl->window == w)
|
||||
return (1);
|
||||
return (wl);
|
||||
}
|
||||
return (0);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct winlink *
|
||||
session_next_activity(struct session *s, struct winlink *wl)
|
||||
session_next_alert(struct winlink *wl)
|
||||
{
|
||||
while (wl != NULL) {
|
||||
if (session_alert_has(s, wl, WINDOW_BELL))
|
||||
break;
|
||||
if (session_alert_has(s, wl, WINDOW_ACTIVITY))
|
||||
break;
|
||||
if (session_alert_has(s, wl, WINDOW_CONTENT))
|
||||
if (wl->flags & WINLINK_ALERTFLAGS)
|
||||
break;
|
||||
wl = winlink_next(wl);
|
||||
}
|
||||
@@ -325,7 +297,7 @@ session_next_activity(struct session *s, struct winlink *wl)
|
||||
|
||||
/* Move session to next window. */
|
||||
int
|
||||
session_next(struct session *s, int activity)
|
||||
session_next(struct session *s, int alert)
|
||||
{
|
||||
struct winlink *wl;
|
||||
|
||||
@@ -333,11 +305,11 @@ session_next(struct session *s, int activity)
|
||||
return (-1);
|
||||
|
||||
wl = winlink_next(s->curw);
|
||||
if (activity)
|
||||
wl = session_next_activity(s, wl);
|
||||
if (alert)
|
||||
wl = session_next_alert(wl);
|
||||
if (wl == NULL) {
|
||||
wl = RB_MIN(winlinks, &s->windows);
|
||||
if (activity && ((wl = session_next_activity(s, wl)) == NULL))
|
||||
if (alert && ((wl = session_next_alert(wl)) == NULL))
|
||||
return (-1);
|
||||
}
|
||||
if (wl == s->curw)
|
||||
@@ -345,19 +317,15 @@ session_next(struct session *s, int activity)
|
||||
winlink_stack_remove(&s->lastw, wl);
|
||||
winlink_stack_push(&s->lastw, s->curw);
|
||||
s->curw = wl;
|
||||
session_alert_cancel(s, wl);
|
||||
wl->flags &= ~WINLINK_ALERTFLAGS;
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct winlink *
|
||||
session_previous_activity(struct session *s, struct winlink *wl)
|
||||
session_previous_alert(struct winlink *wl)
|
||||
{
|
||||
while (wl != NULL) {
|
||||
if (session_alert_has(s, wl, WINDOW_BELL))
|
||||
break;
|
||||
if (session_alert_has(s, wl, WINDOW_ACTIVITY))
|
||||
break;
|
||||
if (session_alert_has(s, wl, WINDOW_CONTENT))
|
||||
if (wl->flags & WINLINK_ALERTFLAGS)
|
||||
break;
|
||||
wl = winlink_previous(wl);
|
||||
}
|
||||
@@ -366,7 +334,7 @@ session_previous_activity(struct session *s, struct winlink *wl)
|
||||
|
||||
/* Move session to previous window. */
|
||||
int
|
||||
session_previous(struct session *s, int activity)
|
||||
session_previous(struct session *s, int alert)
|
||||
{
|
||||
struct winlink *wl;
|
||||
|
||||
@@ -374,11 +342,11 @@ session_previous(struct session *s, int activity)
|
||||
return (-1);
|
||||
|
||||
wl = winlink_previous(s->curw);
|
||||
if (activity)
|
||||
wl = session_previous_activity(s, wl);
|
||||
if (alert)
|
||||
wl = session_previous_alert(wl);
|
||||
if (wl == NULL) {
|
||||
wl = RB_MAX(winlinks, &s->windows);
|
||||
if (activity && (wl = session_previous_activity(s, wl)) == NULL)
|
||||
if (alert && (wl = session_previous_alert(wl)) == NULL)
|
||||
return (-1);
|
||||
}
|
||||
if (wl == s->curw)
|
||||
@@ -386,7 +354,7 @@ session_previous(struct session *s, int activity)
|
||||
winlink_stack_remove(&s->lastw, wl);
|
||||
winlink_stack_push(&s->lastw, s->curw);
|
||||
s->curw = wl;
|
||||
session_alert_cancel(s, wl);
|
||||
wl->flags &= ~WINLINK_ALERTFLAGS;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -404,7 +372,7 @@ session_select(struct session *s, int idx)
|
||||
winlink_stack_remove(&s->lastw, wl);
|
||||
winlink_stack_push(&s->lastw, s->curw);
|
||||
s->curw = wl;
|
||||
session_alert_cancel(s, wl);
|
||||
wl->flags &= ~WINLINK_ALERTFLAGS;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -423,7 +391,7 @@ session_last(struct session *s)
|
||||
winlink_stack_remove(&s->lastw, wl);
|
||||
winlink_stack_push(&s->lastw, s->curw);
|
||||
s->curw = wl;
|
||||
session_alert_cancel(s, wl);
|
||||
wl->flags &= ~WINLINK_ALERTFLAGS;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -540,7 +508,6 @@ session_group_synchronize1(struct session *target, struct session *s)
|
||||
struct winlinks old_windows, *ww;
|
||||
struct winlink_stack old_lastw;
|
||||
struct winlink *wl, *wl2;
|
||||
struct session_alert *sa;
|
||||
|
||||
/* Don't do anything if the session is empty (it'll be destroyed). */
|
||||
ww = &target->windows;
|
||||
@@ -558,8 +525,10 @@ session_group_synchronize1(struct session *target, struct session *s)
|
||||
RB_INIT(&s->windows);
|
||||
|
||||
/* Link all the windows from the target. */
|
||||
RB_FOREACH(wl, winlinks, ww)
|
||||
winlink_add(&s->windows, wl->window, wl->idx);
|
||||
RB_FOREACH(wl, winlinks, ww) {
|
||||
wl2 = winlink_add(&s->windows, wl->window, wl->idx);
|
||||
wl2->flags |= wl->flags & WINLINK_ALERTFLAGS;
|
||||
}
|
||||
|
||||
/* Fix up the current window. */
|
||||
if (s->curw != NULL)
|
||||
@@ -576,15 +545,6 @@ session_group_synchronize1(struct session *target, struct session *s)
|
||||
TAILQ_INSERT_TAIL(&s->lastw, wl2, sentry);
|
||||
}
|
||||
|
||||
/* And update the alerts list. */
|
||||
SLIST_FOREACH(sa, &s->alerts, entry) {
|
||||
wl = winlink_find_by_index(&s->windows, sa->wl->idx);
|
||||
if (wl == NULL)
|
||||
session_alert_cancel(s, sa->wl);
|
||||
else
|
||||
sa->wl = wl;
|
||||
}
|
||||
|
||||
/* Then free the old winlinks list. */
|
||||
while (!RB_EMPTY(&old_windows)) {
|
||||
wl = RB_ROOT(&old_windows);
|
||||
|
||||
103
signal.c
Normal file
103
signal.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/* $Id: signal.c,v 1.3 2010-08-29 14:42:11 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
* Copyright (c) 2010 Romain Francoise <rfrancoise@debian.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 <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
struct event ev_sighup;
|
||||
struct event ev_sigchld;
|
||||
struct event ev_sigcont;
|
||||
struct event ev_sigterm;
|
||||
struct event ev_sigusr1;
|
||||
struct event ev_sigwinch;
|
||||
|
||||
void
|
||||
set_signals(void(*handler)(int, short, unused void *))
|
||||
{
|
||||
struct sigaction sigact;
|
||||
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGINT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
|
||||
signal_set(&ev_sighup, SIGHUP, handler, NULL);
|
||||
signal_add(&ev_sighup, NULL);
|
||||
signal_set(&ev_sigchld, SIGCHLD, handler, NULL);
|
||||
signal_add(&ev_sigchld, NULL);
|
||||
signal_set(&ev_sigcont, SIGCONT, handler, NULL);
|
||||
signal_add(&ev_sigcont, NULL);
|
||||
signal_set(&ev_sigterm, SIGTERM, handler, NULL);
|
||||
signal_add(&ev_sigterm, NULL);
|
||||
signal_set(&ev_sigusr1, SIGUSR1, handler, NULL);
|
||||
signal_add(&ev_sigusr1, NULL);
|
||||
signal_set(&ev_sigwinch, SIGWINCH, handler, NULL);
|
||||
signal_add(&ev_sigwinch, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
clear_signals(int after_fork)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_DFL;
|
||||
if (sigaction(SIGINT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
|
||||
if (after_fork) {
|
||||
if (sigaction(SIGHUP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGCHLD, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGCONT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTERM, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR1, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGWINCH, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
} else {
|
||||
event_del(&ev_sighup);
|
||||
event_del(&ev_sigchld);
|
||||
event_del(&ev_sigcont);
|
||||
event_del(&ev_sigterm);
|
||||
event_del(&ev_sigusr1);
|
||||
event_del(&ev_sigwinch);
|
||||
}
|
||||
}
|
||||
157
status.c
157
status.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: status.c,v 1.144 2010-03-10 13:41:13 nicm Exp $ */
|
||||
/* $Id: status.c,v 1.151 2010-12-11 16:15:02 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -35,16 +35,20 @@ char *status_redraw_get_right(
|
||||
struct client *, time_t, int, struct grid_cell *, size_t *);
|
||||
char *status_job(struct client *, char **);
|
||||
void status_job_callback(struct job *);
|
||||
size_t status_width(struct client *, struct winlink *, time_t);
|
||||
char *status_print(
|
||||
struct client *, struct winlink *, time_t, struct grid_cell *);
|
||||
void status_replace1(struct client *,
|
||||
struct winlink *, char **, char **, char *, size_t, int);
|
||||
void status_message_callback(int, short, void *);
|
||||
|
||||
void status_prompt_add_history(struct client *);
|
||||
const char *status_prompt_up_history(u_int *);
|
||||
const char *status_prompt_down_history(u_int *);
|
||||
void status_prompt_add_history(const char *);
|
||||
char *status_prompt_complete(const char *);
|
||||
|
||||
/* Status prompt history. */
|
||||
ARRAY_DECL(, char *) status_prompt_history = ARRAY_INITIALIZER;
|
||||
|
||||
/* Retrieve options for left string. */
|
||||
char *
|
||||
status_redraw_get_left(struct client *c,
|
||||
@@ -249,25 +253,15 @@ status_redraw(struct client *c)
|
||||
*/
|
||||
offset = 0;
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
if (larrow == 1 && offset < wlstart) {
|
||||
if (session_alert_has(s, wl, WINDOW_ACTIVITY))
|
||||
larrow = -1;
|
||||
else if (session_alert_has(s, wl, WINDOW_BELL))
|
||||
larrow = -1;
|
||||
else if (session_alert_has(s, wl, WINDOW_CONTENT))
|
||||
larrow = -1;
|
||||
}
|
||||
if (wl->flags & WINLINK_ALERTFLAGS &&
|
||||
larrow == 1 && offset < wlstart)
|
||||
larrow = -1;
|
||||
|
||||
offset += wl->status_width;
|
||||
|
||||
if (rarrow == 1 && offset > wlstart + wlwidth) {
|
||||
if (session_alert_has(s, wl, WINDOW_ACTIVITY))
|
||||
rarrow = -1;
|
||||
else if (session_alert_has(s, wl, WINDOW_BELL))
|
||||
rarrow = -1;
|
||||
else if (session_alert_has(s, wl, WINDOW_CONTENT))
|
||||
rarrow = -1;
|
||||
}
|
||||
if (wl->flags & WINLINK_ALERTFLAGS &&
|
||||
rarrow == 1 && offset > wlstart + wlwidth)
|
||||
rarrow = -1;
|
||||
}
|
||||
|
||||
draw:
|
||||
@@ -400,12 +394,14 @@ status_replace1(struct client *c,struct winlink *wl,
|
||||
goto do_replace;
|
||||
case 'F':
|
||||
tmp[0] = ' ';
|
||||
if (session_alert_has(s, wl, WINDOW_CONTENT))
|
||||
if (wl->flags & WINLINK_CONTENT)
|
||||
tmp[0] = '+';
|
||||
else if (session_alert_has(s, wl, WINDOW_BELL))
|
||||
else if (wl->flags & WINLINK_BELL)
|
||||
tmp[0] = '!';
|
||||
else if (session_alert_has(s, wl, WINDOW_ACTIVITY))
|
||||
else if (wl->flags & WINLINK_ACTIVITY)
|
||||
tmp[0] = '#';
|
||||
else if (wl->flags & WINLINK_SILENCE)
|
||||
tmp[0] = '~';
|
||||
else if (wl == s->curw)
|
||||
tmp[0] = '*';
|
||||
else if (wl == TAILQ_FIRST(&s->lastw))
|
||||
@@ -560,30 +556,6 @@ status_job_callback(struct job *job)
|
||||
job->data = xstrdup(line);
|
||||
}
|
||||
|
||||
/* Calculate winlink status line entry width. */
|
||||
size_t
|
||||
status_width(struct client *c, struct winlink *wl, time_t t)
|
||||
{
|
||||
struct options *oo = &wl->window->options;
|
||||
struct session *s = c->session;
|
||||
const char *fmt;
|
||||
char *text;
|
||||
size_t size;
|
||||
int utf8flag;
|
||||
|
||||
utf8flag = options_get_number(&s->options, "status-utf8");
|
||||
|
||||
fmt = options_get_string(&wl->window->options, "window-status-format");
|
||||
if (wl == s->curw)
|
||||
fmt = options_get_string(oo, "window-status-current-format");
|
||||
|
||||
text = status_replace(c, wl, fmt, t, 1);
|
||||
size = screen_write_cstrlen(utf8flag, "%s", text);
|
||||
xfree(text);
|
||||
|
||||
return (size);
|
||||
}
|
||||
|
||||
/* Return winlink status line entry and adjust gc as necessary. */
|
||||
char *
|
||||
status_print(
|
||||
@@ -618,10 +590,17 @@ status_print(
|
||||
fmt = options_get_string(oo, "window-status-current-format");
|
||||
}
|
||||
|
||||
if (session_alert_has(s, wl, WINDOW_ACTIVITY) ||
|
||||
session_alert_has(s, wl, WINDOW_BELL) ||
|
||||
session_alert_has(s, wl, WINDOW_CONTENT))
|
||||
gc->attr ^= GRID_ATTR_REVERSE;
|
||||
if (wl->flags & WINLINK_ALERTFLAGS) {
|
||||
fg = options_get_number(oo, "window-status-alert-fg");
|
||||
if (fg != 8)
|
||||
colour_set_fg(gc, fg);
|
||||
bg = options_get_number(oo, "window-status-alert-bg");
|
||||
if (bg != 8)
|
||||
colour_set_bg(gc, bg);
|
||||
attr = options_get_number(oo, "window-status-alert-attr");
|
||||
if (attr != 0)
|
||||
gc->attr = attr;
|
||||
}
|
||||
|
||||
text = status_replace(c, wl, fmt, t, 1);
|
||||
return (text);
|
||||
@@ -886,6 +865,7 @@ status_prompt_key(struct client *c, int key)
|
||||
{
|
||||
struct paste_buffer *pb;
|
||||
char *s, *first, *last, word[64], swapc;
|
||||
const char *histstr;
|
||||
u_char ch;
|
||||
size_t size, n, off, idx;
|
||||
|
||||
@@ -998,29 +978,20 @@ status_prompt_key(struct client *c, int key)
|
||||
}
|
||||
break;
|
||||
case MODEKEYEDIT_HISTORYUP:
|
||||
if (ARRAY_LENGTH(&c->prompt_hdata) == 0)
|
||||
histstr = status_prompt_up_history(&c->prompt_hindex);
|
||||
if (histstr == NULL)
|
||||
break;
|
||||
xfree(c->prompt_buffer);
|
||||
|
||||
c->prompt_buffer = xstrdup(ARRAY_ITEM(&c->prompt_hdata,
|
||||
ARRAY_LENGTH(&c->prompt_hdata) - 1 - c->prompt_hindex));
|
||||
if (c->prompt_hindex != ARRAY_LENGTH(&c->prompt_hdata) - 1)
|
||||
c->prompt_hindex++;
|
||||
|
||||
c->prompt_buffer = xstrdup(histstr);
|
||||
c->prompt_index = strlen(c->prompt_buffer);
|
||||
c->flags |= CLIENT_STATUS;
|
||||
break;
|
||||
case MODEKEYEDIT_HISTORYDOWN:
|
||||
histstr = status_prompt_down_history(&c->prompt_hindex);
|
||||
if (histstr == NULL)
|
||||
break;
|
||||
xfree(c->prompt_buffer);
|
||||
|
||||
if (c->prompt_hindex != 0) {
|
||||
c->prompt_hindex--;
|
||||
c->prompt_buffer = xstrdup(ARRAY_ITEM(
|
||||
&c->prompt_hdata, ARRAY_LENGTH(
|
||||
&c->prompt_hdata) - 1 - c->prompt_hindex));
|
||||
} else
|
||||
c->prompt_buffer = xstrdup("");
|
||||
|
||||
c->prompt_buffer = xstrdup(histstr);
|
||||
c->prompt_index = strlen(c->prompt_buffer);
|
||||
c->flags |= CLIENT_STATUS;
|
||||
break;
|
||||
@@ -1062,7 +1033,7 @@ status_prompt_key(struct client *c, int key)
|
||||
break;
|
||||
case MODEKEYEDIT_ENTER:
|
||||
if (*c->prompt_buffer != '\0')
|
||||
status_prompt_add_history(c);
|
||||
status_prompt_add_history(c->prompt_buffer);
|
||||
if (c->prompt_callbackfn(c->prompt_data, c->prompt_buffer) == 0)
|
||||
status_prompt_clear(c);
|
||||
break;
|
||||
@@ -1071,7 +1042,7 @@ status_prompt_key(struct client *c, int key)
|
||||
status_prompt_clear(c);
|
||||
break;
|
||||
case MODEKEY_OTHER:
|
||||
if (key < 32 || key == 127)
|
||||
if ((key & 0xff00) != 0 || key < 32 || key == 127)
|
||||
break;
|
||||
c->prompt_buffer = xrealloc(c->prompt_buffer, 1, size + 2);
|
||||
|
||||
@@ -1098,20 +1069,56 @@ status_prompt_key(struct client *c, int key)
|
||||
}
|
||||
}
|
||||
|
||||
/* Get previous line from the history. */
|
||||
const char *
|
||||
status_prompt_up_history(u_int *idx)
|
||||
{
|
||||
u_int size;
|
||||
|
||||
/*
|
||||
* History runs from 0 to size - 1.
|
||||
*
|
||||
* Index is from 0 to size. Zero is empty.
|
||||
*/
|
||||
|
||||
size = ARRAY_LENGTH(&status_prompt_history);
|
||||
if (size == 0 || *idx == size)
|
||||
return (NULL);
|
||||
(*idx)++;
|
||||
return (ARRAY_ITEM(&status_prompt_history, size - *idx));
|
||||
}
|
||||
|
||||
/* Get next line from the history. */
|
||||
const char *
|
||||
status_prompt_down_history(u_int *idx)
|
||||
{
|
||||
u_int size;
|
||||
|
||||
size = ARRAY_LENGTH(&status_prompt_history);
|
||||
if (size == 0 || *idx == 0)
|
||||
return ("");
|
||||
(*idx)--;
|
||||
if (*idx == 0)
|
||||
return ("");
|
||||
return (ARRAY_ITEM(&status_prompt_history, size - *idx));
|
||||
}
|
||||
|
||||
/* Add line to the history. */
|
||||
void
|
||||
status_prompt_add_history(struct client *c)
|
||||
status_prompt_add_history(const char *line)
|
||||
{
|
||||
if (ARRAY_LENGTH(&c->prompt_hdata) > 0 &&
|
||||
strcmp(ARRAY_LAST(&c->prompt_hdata), c->prompt_buffer) == 0)
|
||||
u_int size;
|
||||
|
||||
size = ARRAY_LENGTH(&status_prompt_history);
|
||||
if (size > 0 && strcmp(ARRAY_LAST(&status_prompt_history), line) == 0)
|
||||
return;
|
||||
|
||||
if (ARRAY_LENGTH(&c->prompt_hdata) == PROMPT_HISTORY) {
|
||||
xfree(ARRAY_FIRST(&c->prompt_hdata));
|
||||
ARRAY_REMOVE(&c->prompt_hdata, 0);
|
||||
if (size == PROMPT_HISTORY) {
|
||||
xfree(ARRAY_FIRST(&status_prompt_history));
|
||||
ARRAY_REMOVE(&status_prompt_history, 0);
|
||||
}
|
||||
|
||||
ARRAY_ADD(&c->prompt_hdata, xstrdup(c->prompt_buffer));
|
||||
ARRAY_ADD(&status_prompt_history, xstrdup(line));
|
||||
}
|
||||
|
||||
/* Complete word. */
|
||||
|
||||
498
tmux.1
498
tmux.1
@@ -1,4 +1,4 @@
|
||||
.\" $Id: tmux.1,v 1.237 2010-03-08 15:02:07 tcunha Exp $
|
||||
.\" $Id: tmux.1,v 1.280 2010-12-27 21:17:25 tcunha Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
.\"
|
||||
@@ -14,7 +14,7 @@
|
||||
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: March 2 2010 $
|
||||
.Dd $Mdocdate: December 10 2010 $
|
||||
.Dt TMUX 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -23,7 +23,7 @@
|
||||
.Sh SYNOPSIS
|
||||
.Nm tmux
|
||||
.Bk -words
|
||||
.Op Fl 28lquv
|
||||
.Op Fl 28lquvV
|
||||
.Op Fl c Ar shell-command
|
||||
.Op Fl f Ar file
|
||||
.Op Fl L Ar socket-name
|
||||
@@ -131,10 +131,6 @@ commands which are executed in sequence when the server is first started.
|
||||
If a command in the configuration file fails,
|
||||
.Nm
|
||||
will report an error and exit without executing further commands.
|
||||
.It Fl l
|
||||
Behave as a login shell.
|
||||
This flag currently has no effect and is for compatibility with other shells
|
||||
when using tmux as a login shell.
|
||||
.It Fl L Ar socket-name
|
||||
.Nm
|
||||
stores the server socket in a directory under
|
||||
@@ -155,6 +151,10 @@ If the socket is accidentally removed, the
|
||||
signal may be sent to the
|
||||
.Nm
|
||||
server process to recreate it.
|
||||
.It Fl l
|
||||
Behave as a login shell.
|
||||
This flag currently has no effect and is for compatibility with other shells
|
||||
when using tmux as a login shell.
|
||||
.It Fl q
|
||||
Set the
|
||||
.Ic quiet
|
||||
@@ -198,6 +198,10 @@ and
|
||||
files in the current directory, where
|
||||
.Em PID
|
||||
is the PID of the server or client process.
|
||||
.It Fl V
|
||||
Report the
|
||||
.Nm
|
||||
version.
|
||||
.It Ar command Op Ar flags
|
||||
This specifies one of a set of commands used to control
|
||||
.Nm ,
|
||||
@@ -213,32 +217,114 @@ prefix key,
|
||||
.Ql C-b
|
||||
(Ctrl-b) by default, followed by a command key.
|
||||
.Pp
|
||||
Some of the default key bindings are:
|
||||
The default command key bindings are:
|
||||
.Pp
|
||||
.Bl -tag -width Ds -offset indent -compact
|
||||
.Bl -tag -width "XXXXXXXXXX" -offset indent -compact
|
||||
.It C-b
|
||||
Send the prefix key (C-b) through to the application.
|
||||
.It C-o
|
||||
Rotate the panes in the current window forwards.
|
||||
.It C-z
|
||||
Suspend the
|
||||
.Nm
|
||||
client.
|
||||
.It !
|
||||
Break the current pane out of the window.
|
||||
.It \&"
|
||||
Split the current pane into two, top and bottom.
|
||||
.It #
|
||||
List all paste buffers.
|
||||
.It %
|
||||
Split the current pane into two, left and right.
|
||||
.It &
|
||||
Kill the current window.
|
||||
.It '
|
||||
Prompt for a window index to select.
|
||||
.It ,
|
||||
Rename the current window.
|
||||
.It -
|
||||
Delete the most recently copied buffer of text.
|
||||
.It .
|
||||
Prompt for an index to move the current window.
|
||||
.It 0 to 9
|
||||
Select windows 0 to 9.
|
||||
.It :
|
||||
Enter the
|
||||
.Nm
|
||||
command prompt.
|
||||
.It ;
|
||||
Move to the previously active pane.
|
||||
.It =
|
||||
Choose which buffer to paste interactively from a list.
|
||||
.It \&?
|
||||
List all key bindings.
|
||||
.It D
|
||||
Choose a client to detach.
|
||||
.It \&[
|
||||
Enter copy mode to copy text or view the history.
|
||||
.It \&]
|
||||
Paste the most recently copied buffer of text.
|
||||
.It c
|
||||
Create a new window.
|
||||
.It d
|
||||
Detach the current client.
|
||||
.It f
|
||||
Prompt to search for text in open windows.
|
||||
.It i
|
||||
Display some information about the current window.
|
||||
.It l
|
||||
Move to the previously selected window.
|
||||
.It n
|
||||
Change to the next window.
|
||||
.It o
|
||||
Select the next pane in the current window.
|
||||
.It p
|
||||
Change to the previous window.
|
||||
.It &
|
||||
Kill the current window.
|
||||
.It ,
|
||||
Rename the current window.
|
||||
.It \&?
|
||||
List all key bindings.
|
||||
.It q
|
||||
Briefly display pane indexes.
|
||||
.It r
|
||||
Force redraw of the attached client.
|
||||
.It s
|
||||
Select a new session for the attached client interactively.
|
||||
.It L
|
||||
Switch the attached client back to the last session.
|
||||
.It t
|
||||
Show the time.
|
||||
.It w
|
||||
Choose the current window interactively.
|
||||
.It x
|
||||
Kill the current pane.
|
||||
.It {
|
||||
Swap the current pane with the previous pane.
|
||||
.It }
|
||||
Swap the current pane with the next pane.
|
||||
.It ~
|
||||
Show previous messages from
|
||||
.Nm ,
|
||||
if any.
|
||||
.It Page Up
|
||||
Enter copy mode and scroll one page up.
|
||||
.It Up, Down
|
||||
.It Left, Right
|
||||
Change to the pane above, below, to the left, or to the right of the current
|
||||
pane.
|
||||
.It M-1 to M-5
|
||||
Arrange panes in one of the five preset layouts: even-horizontal,
|
||||
even-vertical, main-horizontal, main-vertical, or tiled.
|
||||
.It M-n
|
||||
Move to the next window with a bell or activity marker.
|
||||
.It M-o
|
||||
Rotate the panes in the current window backwards.
|
||||
.It M-p
|
||||
Move to the previous window with a bell or activity marker.
|
||||
.It C-Up, C-Down
|
||||
.It C-Left, C-Right
|
||||
Resize the current pane in steps of one cell.
|
||||
.It M-Up, M-Down
|
||||
.It M-Left, M-Right
|
||||
Resize the current pane in steps of five cells.
|
||||
.El
|
||||
.Pp
|
||||
A complete list may be obtained with the
|
||||
.Ic list-keys
|
||||
command (bound to
|
||||
.Ql \&?
|
||||
by default).
|
||||
Key bindings may be changed with the
|
||||
.Ic bind-key
|
||||
and
|
||||
@@ -336,6 +422,11 @@ If neither a colon nor period appears,
|
||||
first attempts to use the argument as a pane index; if that fails, it is looked
|
||||
up as for
|
||||
.Ar target-window .
|
||||
A
|
||||
.Ql +
|
||||
or
|
||||
.Ql -
|
||||
indicate the next or previous pane index, respectively.
|
||||
One of the strings
|
||||
.Em top ,
|
||||
.Em bottom ,
|
||||
@@ -347,6 +438,18 @@ One of the strings
|
||||
.Em bottom-right
|
||||
may be used instead of a pane index.
|
||||
.Pp
|
||||
The special characters
|
||||
.Ql +
|
||||
and
|
||||
.Ql -
|
||||
may be followed by an offset, for example:
|
||||
.Bd -literal -offset indent
|
||||
select-window -t:+2
|
||||
.Ed
|
||||
.Pp
|
||||
When dealing with a session that doesn't contain sequential window indexes,
|
||||
they will be correctly skipped.
|
||||
.Pp
|
||||
.Ar shell-command
|
||||
arguments are
|
||||
.Xr sh 1
|
||||
@@ -368,7 +471,6 @@ bind-key F1 set-window-option force-width 81
|
||||
.Pp
|
||||
Or if using
|
||||
.Xr sh 1 :
|
||||
.Pp
|
||||
.Bd -literal -offset indent
|
||||
$ tmux bind-key F1 set-window-option force-width 81
|
||||
.Ed
|
||||
@@ -396,13 +498,12 @@ new-window ; split-window -d
|
||||
.Pp
|
||||
Or from
|
||||
.Xr sh 1 :
|
||||
.Pp
|
||||
.Bd -literal -offset indent
|
||||
$ tmux kill-window -t :1
|
||||
|
||||
$ tmux new-window \\; split-window -d
|
||||
$ tmux new-window \e; split-window -d
|
||||
|
||||
$ tmux new-session -d 'vi /etc/passwd' \\; split-window -d \\; attach
|
||||
$ tmux new-session -d 'vi /etc/passwd' \e; split-window -d \e; attach
|
||||
.Ed
|
||||
.Sh CLIENTS AND SESSIONS
|
||||
The
|
||||
@@ -414,7 +515,7 @@ when they are created with the
|
||||
command, or later with the
|
||||
.Ic attach-session
|
||||
command.
|
||||
Each session has one of more windows
|
||||
Each session has one or more windows
|
||||
.Em linked
|
||||
into it.
|
||||
Windows may be linked to multiple sessions and are made up of one or
|
||||
@@ -475,17 +576,15 @@ List the syntax of all commands supported by
|
||||
.It Ic list-sessions
|
||||
.D1 (alias: Ic ls )
|
||||
List all sessions managed by the server.
|
||||
.It Xo Ic lock-client
|
||||
.Op Fl t Ar target-client
|
||||
.Xc
|
||||
.It Ic lock-client Op Fl t Ar target-client
|
||||
.D1 (alias: Ic lockc )
|
||||
Lock
|
||||
.Ar target-client ,
|
||||
see the
|
||||
.Ic lock-server
|
||||
command.
|
||||
.It Xo Ic lock-session
|
||||
.Op Fl t Ar target-session
|
||||
.Xc
|
||||
.It Ic lock-session Op Fl t Ar target-session
|
||||
.D1 (alias: Ic locks )
|
||||
Lock all clients attached to
|
||||
.Ar target-session .
|
||||
.It Xo Ic new-session
|
||||
@@ -569,6 +668,7 @@ Suspend a client by sending
|
||||
.Dv SIGTSTP
|
||||
(tty stop).
|
||||
.It Xo Ic switch-client
|
||||
.Op Fl lnp
|
||||
.Op Fl c Ar target-client
|
||||
.Op Fl t Ar target-session
|
||||
.Xc
|
||||
@@ -577,20 +677,21 @@ Switch the current session for client
|
||||
.Ar target-client
|
||||
to
|
||||
.Ar target-session .
|
||||
If
|
||||
.Fl l ,
|
||||
.Fl n
|
||||
or
|
||||
.Fl p
|
||||
is used, the client is moved to the last, next or previous session
|
||||
respectively.
|
||||
.El
|
||||
.Sh WINDOWS AND PANES
|
||||
A
|
||||
.Nm
|
||||
window may be in one of several modes.
|
||||
The default permits direct access to the terminal attached to the window.
|
||||
The others are:
|
||||
.Bl -tag -width Ds
|
||||
.It Em output mode
|
||||
This is entered when a command which produces output, such as
|
||||
.Ic list-keys ,
|
||||
is executed from a key binding.
|
||||
.It Em copy mode
|
||||
This permits a section of a window or its history to be copied to a
|
||||
The other is copy mode, which permits a section of a window or its
|
||||
history to be copied to a
|
||||
.Em paste buffer
|
||||
for later insertion into another window.
|
||||
This mode is entered with the
|
||||
@@ -598,14 +699,16 @@ This mode is entered with the
|
||||
command, bound to
|
||||
.Ql \&[
|
||||
by default.
|
||||
.El
|
||||
It is also entered when a command that produces output, such as
|
||||
.Ic list-keys ,
|
||||
is executed from a key binding.
|
||||
.Pp
|
||||
The keys available depend on whether emacs or vi mode is selected
|
||||
(see the
|
||||
.Ic mode-keys
|
||||
option).
|
||||
The following keys are supported as appropriate for the mode:
|
||||
.Bl -column "FunctionXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent
|
||||
.Bl -column "FunctionXXXXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent
|
||||
.It Sy "Function" Ta Sy "vi" Ta Sy "emacs"
|
||||
.It Li "Back to indentation" Ta "^" Ta "M-m"
|
||||
.It Li "Bottom of history" Ta "G" Ta "M-<"
|
||||
@@ -624,6 +727,10 @@ The following keys are supported as appropriate for the mode:
|
||||
.It Li "Go to line" Ta ":" Ta "g"
|
||||
.It Li "Half page down" Ta "C-d" Ta "M-Down"
|
||||
.It Li "Half page up" Ta "C-u" Ta "M-Up"
|
||||
.It Li "Jump forward" Ta "f" Ta "f"
|
||||
.It Li "Jump backward" Ta "F" Ta "F"
|
||||
.It Li "Jump again" Ta ";" Ta ";"
|
||||
.It Li "Jump again in reverse" Ta "," Ta ","
|
||||
.It Li "Next page" Ta "C-f" Ta "Page down"
|
||||
.It Li "Next space" Ta "W" Ta ""
|
||||
.It Li "Next space, end of word" Ta "E" Ta ""
|
||||
@@ -661,6 +768,18 @@ next word and previous word to the start of the previous word.
|
||||
The three next and previous space keys work similarly but use a space alone as
|
||||
the word separator.
|
||||
.Pp
|
||||
The jump commands enable quick movement within a line.
|
||||
For instance, typing
|
||||
.Ql f
|
||||
followed by
|
||||
.Ql /
|
||||
will move the cursor to the next
|
||||
.Ql /
|
||||
character on the current line.
|
||||
A
|
||||
.Ql \&;
|
||||
will then jump to the next occurrence.
|
||||
.Pp
|
||||
Commands in copy mode may be prefaced by an optional repeat count.
|
||||
With vi key bindings, a prefix is entered using the number keys; with
|
||||
emacs, the Alt (meta) key and a number begins prefix entry.
|
||||
@@ -680,7 +799,7 @@ and
|
||||
.Em emacs-choice
|
||||
for keys used when choosing from lists (such as produced by the
|
||||
.Ic choose-window
|
||||
command) or in output mode; and
|
||||
command); and
|
||||
.Em vi-copy
|
||||
and
|
||||
.Em emacs-copy
|
||||
@@ -695,7 +814,9 @@ and
|
||||
The paste buffer key pastes the first line from the top paste buffer on the
|
||||
stack.
|
||||
.Pp
|
||||
The mode commands are as follows:
|
||||
The synopsis for the
|
||||
.Ic copy-mode
|
||||
command is:
|
||||
.Bl -tag -width Ds
|
||||
.It Xo Ic copy-mode
|
||||
.Op Fl u
|
||||
@@ -727,10 +848,8 @@ command (bound to
|
||||
and
|
||||
.Ql C-right
|
||||
by default), the current pane may be changed with the
|
||||
.Ic up-pane
|
||||
and
|
||||
.Ic down-pane
|
||||
commands and the
|
||||
.Ic select-pane
|
||||
command and the
|
||||
.Ic rotate-window
|
||||
and
|
||||
.Ic swap-pane
|
||||
@@ -769,8 +888,30 @@ bottom along the right.
|
||||
See the
|
||||
.Em main-pane-width
|
||||
window option.
|
||||
.It Ic tiled
|
||||
Panes are spread out as evenly as possible over the window in both rows and
|
||||
columns.
|
||||
.El
|
||||
.Pp
|
||||
In addition,
|
||||
.Ic select-layout
|
||||
may be used to apply a previously used layout - the
|
||||
.Ic list-windows
|
||||
command displays the layout of each window in a form suitable for use with
|
||||
.Ic select-layout .
|
||||
For example:
|
||||
.Bd -literal -offset indent
|
||||
$ tmux list-windows
|
||||
0: ksh [159x48]
|
||||
layout: bb62,159x48,0,0{79x48,0,0,79x48,80,0}
|
||||
$ tmux select-layout bb62,159x48,0,0{79x48,0,0,79x48,80,0}
|
||||
.Ed
|
||||
.Pp
|
||||
.Nm
|
||||
automatically adjusts the size of the layout for the current window size.
|
||||
Note that a layout cannot be applied to a window with more panes than that
|
||||
from which the layout was originally defined.
|
||||
.Pp
|
||||
Commands related to windows and panes are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Xo Ic break-pane
|
||||
@@ -859,9 +1000,6 @@ While the indicator is on screen, a pane may be selected with the
|
||||
to
|
||||
.Ql 9
|
||||
keys.
|
||||
.It Ic down-pane Op Fl t Ar target-pane
|
||||
.D1 (alias: Ic downp )
|
||||
Change the active pane to the next pane (higher index).
|
||||
.It Xo Ic find-window
|
||||
.Op Fl t Ar target-window
|
||||
.Ar match-string
|
||||
@@ -910,6 +1048,9 @@ option kills all but the pane given with
|
||||
Kill the current window or the window at
|
||||
.Ar target-window ,
|
||||
removing it from any sessions to which it is linked.
|
||||
.It Ic last-pane Op Fl t Ar target-window
|
||||
.D1 (alias: Ic lastp )
|
||||
Select the last (previously selected) pane.
|
||||
.It Ic last-window Op Fl t Ar target-session
|
||||
.D1 (alias: Ic last )
|
||||
Select the last (previously selected) window.
|
||||
@@ -948,7 +1089,7 @@ List the panes in the current window or in
|
||||
List windows in the current session or in
|
||||
.Ar target-session .
|
||||
.It Xo Ic move-window
|
||||
.Op Fl d
|
||||
.Op Fl dk
|
||||
.Op Fl s Ar src-window
|
||||
.Op Fl t Ar dst-window
|
||||
.Xc
|
||||
@@ -960,13 +1101,22 @@ except the window at
|
||||
is moved to
|
||||
.Ar dst-window .
|
||||
.It Xo Ic new-window
|
||||
.Op Fl dk
|
||||
.Op Fl adk
|
||||
.Op Fl n Ar window-name
|
||||
.Op Fl t Ar target-window
|
||||
.Op Ar shell-command
|
||||
.Xc
|
||||
.D1 (alias: Ic neww )
|
||||
Create a new window.
|
||||
With
|
||||
.Fl a ,
|
||||
the new window is inserted at the next index up from the specified
|
||||
.Ar target-window ,
|
||||
moving windows up if necessary,
|
||||
otherwise
|
||||
.Ar target-window
|
||||
is the new window location.
|
||||
.Pp
|
||||
If
|
||||
.Fl d
|
||||
is given, the session does not make the new window the current window.
|
||||
@@ -1024,6 +1174,11 @@ A pane may only be piped to one command at a time, any existing pipe is
|
||||
closed before
|
||||
.Ar shell-command
|
||||
is executed.
|
||||
The
|
||||
.Ar shell-command
|
||||
string may contain the special character sequences supported by the
|
||||
.Ic status-left
|
||||
command.
|
||||
If no
|
||||
.Ar shell-command
|
||||
is given, the current pipe (if any) is closed.
|
||||
@@ -1033,8 +1188,13 @@ The
|
||||
option only opens a new pipe if no previous pipe exists, allowing a pipe to
|
||||
be toggled with a single key, for example:
|
||||
.Bd -literal -offset indent
|
||||
bind-key C-p pipe-pane -o 'cat >>~/output'
|
||||
bind-key C-p pipe-pane -o 'cat >>~/output.#I-#P'
|
||||
.Ed
|
||||
.It Xo Ic previous-layout
|
||||
.Op Fl t Ar target-window
|
||||
.Xc
|
||||
.D1 (alias: Ic prevl )
|
||||
Move to the previous layout in the session.
|
||||
.It Xo Ic previous-window
|
||||
.Op Fl a
|
||||
.Op Fl t Ar target-session
|
||||
@@ -1098,17 +1258,28 @@ or downward (numerically higher).
|
||||
.Op Fl t Ar target-window
|
||||
.Op Ar layout-name
|
||||
.Xc
|
||||
.D1 (alias: selectl )
|
||||
.D1 (alias: Ic selectl )
|
||||
Choose a specific layout for a window.
|
||||
If
|
||||
.Ar layout-name
|
||||
is not given, the last layout used (if any) is reapplied.
|
||||
.It Ic select-pane Op Fl t Ar target-pane
|
||||
is not given, the last preset layout used (if any) is reapplied.
|
||||
.It Xo Ic select-pane
|
||||
.Op Fl DLRU
|
||||
.Op Fl t Ar target-pane
|
||||
.Xc
|
||||
.D1 (alias: Ic selectp )
|
||||
Make pane
|
||||
.Ar target-pane
|
||||
the active pane in window
|
||||
.Ar target-window .
|
||||
If one of
|
||||
.Fl D ,
|
||||
.Fl L ,
|
||||
.Fl R ,
|
||||
or
|
||||
.Fl U
|
||||
is used, respectively the pane below, to the left, to the right, or above the
|
||||
target pane is used.
|
||||
.It Ic select-window Op Fl t Ar target-window
|
||||
.D1 (alias: Ic selectw )
|
||||
Select the window at
|
||||
@@ -1121,7 +1292,7 @@ Select the window at
|
||||
.Op Fl t Ar target-pane
|
||||
.Op Ar shell-command
|
||||
.Xc
|
||||
.D1 (alias: splitw )
|
||||
.D1 (alias: Ic splitw )
|
||||
Create a new pane by splitting
|
||||
.Ar target-pane :
|
||||
.Fl h
|
||||
@@ -1184,9 +1355,6 @@ if
|
||||
.Fl k
|
||||
is specified and the window is linked to only one session, it is unlinked and
|
||||
destroyed.
|
||||
.It Ic up-pane Op Fl t Ar target-pane
|
||||
.D1 (alias: Ic upp )
|
||||
Change the active pane to the previous pane (lower index).
|
||||
.El
|
||||
.Sh KEY BINDINGS
|
||||
.Nm
|
||||
@@ -1233,7 +1401,7 @@ or
|
||||
keys, quotation marks are necessary, for example:
|
||||
.Bd -literal -offset indent
|
||||
bind-key '"' split-window
|
||||
bind-key "'" select-prompt
|
||||
bind-key "'" new-window
|
||||
.Ed
|
||||
.Pp
|
||||
Commands related to key bindings are as follows:
|
||||
@@ -1320,7 +1488,7 @@ All arguments are sent sequentially from first to last.
|
||||
Send the prefix key to a window as if it was pressed.
|
||||
If multiple prefix keys are configured, only the first is sent.
|
||||
.It Xo Ic unbind-key
|
||||
.Op Fl cn
|
||||
.Op Fl acn
|
||||
.Op Fl t Ar key-table
|
||||
.Ar key
|
||||
.Xc
|
||||
@@ -1334,6 +1502,9 @@ the primary key bindings are modified; in this case, if
|
||||
is specified, the command bound to
|
||||
.Ar key
|
||||
without a prefix (if any) is removed.
|
||||
If
|
||||
.Fl a
|
||||
is present, all key bindings are removed.
|
||||
.Pp
|
||||
If
|
||||
.Fl t
|
||||
@@ -1433,6 +1604,9 @@ Set the time in milliseconds for which
|
||||
waits after an escape is input to determine if it is part of a function or meta
|
||||
key sequences.
|
||||
The default is 500 milliseconds.
|
||||
.It Ic exit-unattached
|
||||
If enabled, the server will exit when there are no attached clients, rather
|
||||
than when there are no attached sessions.
|
||||
.It Ic quiet
|
||||
Enable or disable the display of various informational messages (see also the
|
||||
.Fl q
|
||||
@@ -1472,6 +1646,11 @@ The default is an empty string, which instructs
|
||||
to create a login shell using the value of the
|
||||
.Ic default-shell
|
||||
option.
|
||||
.It Ic default-path Ar path
|
||||
Set the default working directory for processes created from keys, or
|
||||
interactively from the prompt.
|
||||
The default is empty, which means to use the working directory of the shell
|
||||
from which the server was started if it is available or the user's home if not.
|
||||
.It Ic default-shell Ar path
|
||||
Specify the default shell.
|
||||
This is used as the login shell for new windows when the
|
||||
@@ -1488,10 +1667,6 @@ or
|
||||
This option should be configured when
|
||||
.Nm
|
||||
is used as a login shell.
|
||||
.It Ic default-path Ar path
|
||||
Set the default working directory for processes created from keys, or
|
||||
interactively from the prompt.
|
||||
The default is the current working directory when the server is started.
|
||||
.It Ic default-terminal Ar terminal
|
||||
Set the default terminal for new windows created in this session - the
|
||||
default value of the
|
||||
@@ -1504,6 +1679,14 @@ to work correctly, this
|
||||
be set to
|
||||
.Ql screen
|
||||
or a derivative of it.
|
||||
.It Ic destroy-unattached
|
||||
If enabled and the session is no longer attached to any clients, it is
|
||||
destroyed.
|
||||
.It Ic detach-on-destroy
|
||||
If on (the default), the client is detached when the session it is attached to
|
||||
is destroyed.
|
||||
If off, the client is switched to the most recently active of the remaining
|
||||
sessions.
|
||||
.It Ic display-panes-active-colour Ar colour
|
||||
Set the colour used by the
|
||||
.Ic display-panes
|
||||
@@ -1557,7 +1740,7 @@ This has no effect as a session option; it must be set as a global option.
|
||||
Set status line message attributes, where
|
||||
.Ar attributes
|
||||
is either
|
||||
.Ic default
|
||||
.Ic none
|
||||
or a comma-delimited list of one or more of:
|
||||
.Ic bright
|
||||
(or
|
||||
@@ -1600,12 +1783,12 @@ If on,
|
||||
captures the mouse and when a window is split into multiple panes the mouse may
|
||||
be used to select the current pane.
|
||||
The mouse click is also passed through to the application as normal.
|
||||
.It Ic pane-border-fg Ar colour
|
||||
.It Ic pane-border-bg Ar colour
|
||||
Set the pane border colour for panes aside from the active pane.
|
||||
.It Ic pane-active-border-fg Ar colour
|
||||
.It Ic pane-active-border-bg Ar colour
|
||||
.It Ic pane-active-border-fg Ar colour
|
||||
Set the pane border colour for the currently active pane.
|
||||
.It Ic pane-border-bg Ar colour
|
||||
.It Ic pane-border-fg Ar colour
|
||||
Set the pane border colour for panes aside from the active pane.
|
||||
.It Ic prefix Ar keys
|
||||
Set the keys accepted as a prefix key.
|
||||
.Ar keys
|
||||
@@ -1678,7 +1861,12 @@ or right justified.
|
||||
.Xc
|
||||
Use vi or emacs-style
|
||||
key bindings in the status line, for example at the command prompt.
|
||||
Defaults to emacs.
|
||||
The default is emacs, unless the
|
||||
.Ev VISUAL
|
||||
or
|
||||
.Ev EDITOR
|
||||
environment variables are set and contain the string
|
||||
.Ql vi .
|
||||
.It Ic status-left Ar string
|
||||
Display
|
||||
.Ar string
|
||||
@@ -1712,6 +1900,19 @@ the
|
||||
.Ic status-interval
|
||||
option: if the status line is redrawn in the meantime, the previous result is
|
||||
used.
|
||||
Shell commands are executed with the
|
||||
.Nm
|
||||
global environment set (see the
|
||||
.Sx ENVIRONMENT
|
||||
section).
|
||||
.Pp
|
||||
The window title (#T) is the title set by the program running within the window
|
||||
using the OSC title setting sequence, for example:
|
||||
.Bd -literal -offset indent
|
||||
$ printf '\e033]2;My Title\e033\e\e'
|
||||
.Ed
|
||||
.Pp
|
||||
When a window is first created, its title is the hostname.
|
||||
.Pp
|
||||
#[attributes] allows a comma-separated list of attributes to be specified,
|
||||
these may be
|
||||
@@ -1742,10 +1943,10 @@ is not interpreted, to enable UTF-8, use the
|
||||
option.
|
||||
.It Ic status-left-attr Ar attributes
|
||||
Set the attribute of the left part of the status line.
|
||||
.It Ic status-left-fg Ar colour
|
||||
Set the foreground colour of the left part of the status line.
|
||||
.It Ic status-left-bg Ar colour
|
||||
Set the background colour of the left part of the status line.
|
||||
.It Ic status-left-fg Ar colour
|
||||
Set the foreground colour of the left part of the status line.
|
||||
.It Ic status-left-length Ar length
|
||||
Set the maximum
|
||||
.Ar length
|
||||
@@ -1767,16 +1968,15 @@ character pairs are replaced, and UTF-8 is dependent on the
|
||||
option.
|
||||
.It Ic status-right-attr Ar attributes
|
||||
Set the attribute of the right part of the status line.
|
||||
.It Ic status-right-fg Ar colour
|
||||
Set the foreground colour of the right part of the status line.
|
||||
.It Ic status-right-bg Ar colour
|
||||
Set the background colour of the right part of the status line.
|
||||
.It Ic status-right-fg Ar colour
|
||||
Set the foreground colour of the right part of the status line.
|
||||
.It Ic status-right-length Ar length
|
||||
Set the maximum
|
||||
.Ar length
|
||||
of the right component of the status bar.
|
||||
The default is 40.
|
||||
.Pp
|
||||
.It Xo Ic status-utf8
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
@@ -1835,7 +2035,8 @@ was given to the
|
||||
.Ic set-environment
|
||||
command).
|
||||
The default is
|
||||
"DISPLAY WINDOWID SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION".
|
||||
"DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION WINDOWID
|
||||
XAUTHORITY".
|
||||
.It Xo Ic visual-activity
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
@@ -1860,6 +2061,12 @@ display a message when content is present in a window
|
||||
for which the
|
||||
.Ic monitor-content
|
||||
window option is enabled.
|
||||
.It Xo Ic visual-silence
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
If
|
||||
.Ic monitor-silence
|
||||
is enabled, prints a message after the interval has expired on a given window.
|
||||
.El
|
||||
.It Xo Ic set-window-option
|
||||
.Op Fl agu
|
||||
@@ -1893,6 +2100,19 @@ this option is good for full-screen programs which support
|
||||
.Dv SIGWINCH
|
||||
and poor for interactive programs such as shells.
|
||||
.Pp
|
||||
.It Xo Ic alternate-screen
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
This option configures whether programs running inside
|
||||
.Nm
|
||||
may use the terminal alternate screen feature, which allows the
|
||||
.Em smcup
|
||||
and
|
||||
.Em rmcup
|
||||
.Xr terminfo 5
|
||||
capabilities to be issued to preserve the existing window content on start and
|
||||
restore it on exit.
|
||||
.Pp
|
||||
.It Xo Ic automatic-rename
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
@@ -1903,7 +2123,8 @@ will attempt - on supported platforms - to rename the window to reflect the
|
||||
command currently running in it.
|
||||
This flag is automatically disabled for an individual window when a name
|
||||
is specified at creation with
|
||||
.Ic new-window or
|
||||
.Ic new-window
|
||||
or
|
||||
.Ic new-session ,
|
||||
or later with
|
||||
.Ic rename-window .
|
||||
@@ -1930,8 +2151,8 @@ or
|
||||
.Ar height .
|
||||
A value of zero restores the default unlimited setting.
|
||||
.Pp
|
||||
.It Ic main-pane-width Ar width
|
||||
.It Ic main-pane-height Ar height
|
||||
.It Ic main-pane-width Ar width
|
||||
Set the width or height of the main (left or top) pane in the
|
||||
.Ic main-horizontal
|
||||
or
|
||||
@@ -1951,16 +2172,21 @@ Set window modes foreground colour.
|
||||
.Op Ic vi | emacs
|
||||
.Xc
|
||||
Use vi or emacs-style key bindings in copy and choice modes.
|
||||
Key bindings default to emacs.
|
||||
As with the
|
||||
.Ic status-keys
|
||||
option, the default is emacs, unless
|
||||
.Ev VISUAL
|
||||
or
|
||||
.Ev EDITOR
|
||||
contains
|
||||
.Ql vi .
|
||||
.Pp
|
||||
.It Xo Ic mode-mouse
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
Mouse state in modes.
|
||||
If on,
|
||||
.Nm
|
||||
will respond to mouse clicks by moving the cursor in copy mode or selecting an
|
||||
option in choice mode.
|
||||
If on, the mouse may be used to copy a selection by dragging in copy mode, or
|
||||
to select an option in choice mode.
|
||||
.Pp
|
||||
.It Xo Ic monitor-activity
|
||||
.Op Ic on | off
|
||||
@@ -1976,6 +2202,35 @@ pattern
|
||||
.Ar match-string
|
||||
appears in the window, it is highlighted in the status line.
|
||||
.Pp
|
||||
.It Xo Ic monitor-silence
|
||||
.Op Ic interval
|
||||
.Xc
|
||||
Monitor for silence (no activity) in the window within
|
||||
.Ic interval
|
||||
seconds.
|
||||
Windows that have been silent for the interval are highlighted in the
|
||||
status line.
|
||||
An interval of zero disables the monitoring.
|
||||
.Pp
|
||||
.It Ic other-pane-height Ar height
|
||||
Set the height of the other panes (not the main pane) in the
|
||||
.Ic main-horizontal
|
||||
layout.
|
||||
If this option is set to 0 (the default), it will have no effect.
|
||||
If both the
|
||||
.Ic main-pane-height
|
||||
and
|
||||
.Ic other-pane-height
|
||||
options are set, the main pane will grow taller to make the other panes the
|
||||
specified height, but will never shrink to do so.
|
||||
.Pp
|
||||
.It Ic other-pane-width Ar width
|
||||
Like
|
||||
.Ic other-pane-height ,
|
||||
but set the width of other panes in the
|
||||
.Ic main-vertical
|
||||
layout.
|
||||
.Pp
|
||||
.It Xo Ic remain-on-exit
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
@@ -1988,21 +2243,8 @@ command.
|
||||
.It Xo Ic synchronize-panes
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
Duplicate input to any pane to all other panes in the same window, except
|
||||
for panes that are not in output mode.
|
||||
.Pp
|
||||
.It Xo Ic alternate-screen
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
This option configures whether programs running inside
|
||||
.Nm
|
||||
may use the terminal alternate screen feature, which allows the
|
||||
.Em smcup
|
||||
and
|
||||
.Em rmcup
|
||||
.Xr terminfo 5
|
||||
capabilities to be issued to preserve the existing window content on start and
|
||||
restore it on exit.
|
||||
Duplicate input to any pane to all other panes in the same window (only
|
||||
for panes that are not in any special mode).
|
||||
.Pp
|
||||
.It Xo Ic utf8
|
||||
.Op Ic on | off
|
||||
@@ -2028,6 +2270,16 @@ option for details of special character sequences available.
|
||||
The default is
|
||||
.Ql #I:#W#F .
|
||||
.Pp
|
||||
.It Ic window-status-alert-attr Ar attributes
|
||||
Set status line attributes for windows which have an alert (bell, activity
|
||||
or content).
|
||||
.Pp
|
||||
.It Ic window-status-alert-bg Ar colour
|
||||
Set status line background colour for windows with an alert.
|
||||
.Pp
|
||||
.It Ic window-status-alert-fg Ar colour
|
||||
Set status line foreground colour for windows with an alert.
|
||||
.Pp
|
||||
.It Ic window-status-current-attr Ar attributes
|
||||
Set status line attributes for the currently active window.
|
||||
.Pp
|
||||
@@ -2094,9 +2346,9 @@ copies the environment into the
|
||||
.Em global environment ;
|
||||
in addition, each session has a
|
||||
.Em session environment .
|
||||
When a window is created, the session and global environments are merged with
|
||||
the session environment overriding any variable present in both.
|
||||
This is the initial environment passed to the new process.
|
||||
When a window is created, the session and global environments are merged.
|
||||
If a variable exists in both, the value from the session environment is used.
|
||||
The result is the initial environment passed to the new process.
|
||||
.Pp
|
||||
The
|
||||
.Ic update-environment
|
||||
@@ -2177,6 +2429,7 @@ The flag is one of the following symbols appended to the window name:
|
||||
.It Li "#" Ta "Window is monitored and activity has been detected."
|
||||
.It Li "!" Ta "A bell has occurred in the window."
|
||||
.It Li "+" Ta "Window is monitored for content and it has appeared."
|
||||
.It Li "~" Ta "The window has been silent for the monitor-silence interval."
|
||||
.El
|
||||
.Pp
|
||||
The # symbol relates to the
|
||||
@@ -2271,10 +2524,6 @@ The format of
|
||||
is as for
|
||||
.Ic status-left ,
|
||||
with the exception that #() are not handled.
|
||||
.It Ic select-prompt Op Fl t Ar target-client
|
||||
Open a prompt inside
|
||||
.Ar target-client
|
||||
allowing a window index to be entered interactively.
|
||||
.El
|
||||
.Sh BUFFERS
|
||||
.Nm
|
||||
@@ -2302,6 +2551,23 @@ command above).
|
||||
.Pp
|
||||
The buffer commands are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Xo
|
||||
.Ic choose-buffer
|
||||
.Op Fl t Ar target-window
|
||||
.Op Ar template
|
||||
.Xc
|
||||
Put a window into buffer choice mode, where a buffer may be chosen
|
||||
interactively from a list.
|
||||
After a buffer is selected,
|
||||
.Ql %%
|
||||
is replaced by the buffer index in
|
||||
.Ar template
|
||||
and the result executed as a command.
|
||||
If
|
||||
.Ar template
|
||||
is not given, "paste-buffer -b '%%'" is used.
|
||||
This command works only from inside
|
||||
.Nm .
|
||||
.It Ic clear-history Op Fl t Ar target-pane
|
||||
.D1 (alias: Ic clearhist )
|
||||
Remove and free the history for the specified pane.
|
||||
@@ -2336,18 +2602,23 @@ Load the contents of the specified paste buffer from
|
||||
.It Xo Ic paste-buffer
|
||||
.Op Fl dr
|
||||
.Op Fl b Ar buffer-index
|
||||
.Op Fl t Ar target-window
|
||||
.Op Fl s Ar separator
|
||||
.Op Fl t Ar target-pane
|
||||
.Xc
|
||||
.D1 (alias: Ic pasteb )
|
||||
Insert the contents of a paste buffer into the current window.
|
||||
Insert the contents of a paste buffer into the specified pane.
|
||||
If not specified, paste into the current one.
|
||||
With
|
||||
.Fl d ,
|
||||
also delete the paste buffer from the stack.
|
||||
When output, any linefeed (LF) characters in the paste buffer are replaced with
|
||||
carriage returns (CR).
|
||||
This translation may be disabled with the
|
||||
.Fl r
|
||||
a separator, by default carriage return (CR).
|
||||
A custom separator may be specified using the
|
||||
.Fl s
|
||||
flag.
|
||||
The
|
||||
.Fl r
|
||||
flag means to do no replacement (equivalent to a separator of LF).
|
||||
.It Xo Ic save-buffer
|
||||
.Op Fl a
|
||||
.Op Fl b Ar buffer-index
|
||||
@@ -2376,7 +2647,6 @@ Set the contents of the specified buffer to
|
||||
Display the contents of the specified buffer.
|
||||
.El
|
||||
.Sh MISCELLANEOUS
|
||||
.Pp
|
||||
Miscellaneous commands are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Ic clock-mode Op Fl t Ar target-pane
|
||||
@@ -2398,7 +2668,7 @@ option.
|
||||
Execute
|
||||
.Ar shell-command
|
||||
in the background without creating a window.
|
||||
After it finishes, any output to stdout is displayed in output mode.
|
||||
After it finishes, any output to stdout is displayed in copy mode.
|
||||
If the command doesn't return success, the exit status is also displayed.
|
||||
.It Ic server-info
|
||||
.D1 (alias: Ic info )
|
||||
|
||||
393
tmux.c
393
tmux.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: tmux.c,v 1.204 2010-02-26 13:31:39 tcunha Exp $ */
|
||||
/* $Id: tmux.c,v 1.228 2010-12-27 21:22:24 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -21,11 +21,10 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <event.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
@@ -34,37 +33,26 @@
|
||||
extern char *malloc_options;
|
||||
#endif
|
||||
|
||||
char *cfg_file;
|
||||
struct options global_options; /* server options */
|
||||
struct options global_s_options; /* session options */
|
||||
struct options global_w_options; /* window options */
|
||||
struct environ global_environ;
|
||||
|
||||
struct event_base *ev_base;
|
||||
|
||||
char *cfg_file;
|
||||
char *shell_cmd;
|
||||
int debug_level;
|
||||
time_t start_time;
|
||||
char *socket_path;
|
||||
char socket_path[MAXPATHLEN];
|
||||
int login_shell;
|
||||
|
||||
struct env_data {
|
||||
char *path;
|
||||
pid_t pid;
|
||||
u_int idx;
|
||||
};
|
||||
char *environ_path;
|
||||
pid_t environ_pid;
|
||||
u_int environ_idx;
|
||||
|
||||
__dead void usage(void);
|
||||
void parse_env(struct env_data *);
|
||||
char *makesockpath(const char *);
|
||||
__dead void shell_exec(const char *, const char *);
|
||||
|
||||
struct imsgbuf *main_ibuf;
|
||||
struct event main_ev_sigterm;
|
||||
int main_exitval;
|
||||
|
||||
void main_set_signals(void);
|
||||
void main_clear_signals(void);
|
||||
void main_signal(int, short, unused void *);
|
||||
void main_callback(int, short, void *);
|
||||
void main_dispatch(const char *);
|
||||
void parseenvironment(void);
|
||||
char *makesocketpath(const char *);
|
||||
|
||||
#ifndef HAVE_PROGNAME
|
||||
char *__progname = (char *) "tmux";
|
||||
@@ -74,7 +62,7 @@ __dead void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s [-28lquv] [-c shell-command] [-f file] [-L socket-name]\n"
|
||||
"usage: %s [-28lquvV] [-c shell-command] [-f file] [-L socket-name]\n"
|
||||
" [-S socket-path] [command [flags]]\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
@@ -138,14 +126,14 @@ areshell(const char *shell)
|
||||
}
|
||||
|
||||
void
|
||||
parse_env(struct env_data *data)
|
||||
parseenvironment(void)
|
||||
{
|
||||
char *env, *path_pid, *pid_idx, buf[256];
|
||||
size_t len;
|
||||
const char *errstr;
|
||||
long long ll;
|
||||
|
||||
data->pid = -1;
|
||||
environ_pid = -1;
|
||||
if ((env = getenv("TMUX")) == NULL)
|
||||
return;
|
||||
|
||||
@@ -158,9 +146,9 @@ parse_env(struct env_data *data)
|
||||
|
||||
/* path */
|
||||
len = path_pid - env;
|
||||
data->path = xmalloc (len + 1);
|
||||
memcpy(data->path, env, len);
|
||||
data->path[len] = '\0';
|
||||
environ_path = xmalloc(len + 1);
|
||||
memcpy(environ_path, env, len);
|
||||
environ_path[len] = '\0';
|
||||
|
||||
/* pid */
|
||||
len = pid_idx - path_pid - 1;
|
||||
@@ -172,17 +160,17 @@ parse_env(struct env_data *data)
|
||||
ll = strtonum(buf, 0, LONG_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
return;
|
||||
data->pid = ll;
|
||||
environ_pid = ll;
|
||||
|
||||
/* idx */
|
||||
ll = strtonum(pid_idx+1, 0, UINT_MAX, &errstr);
|
||||
ll = strtonum(pid_idx + 1, 0, UINT_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
return;
|
||||
data->idx = ll;
|
||||
environ_idx = ll;
|
||||
}
|
||||
|
||||
char *
|
||||
makesockpath(const char *label)
|
||||
makesocketpath(const char *label)
|
||||
{
|
||||
char base[MAXPATHLEN], *path;
|
||||
struct stat sb;
|
||||
@@ -214,6 +202,7 @@ shell_exec(const char *shell, const char *shellcmd)
|
||||
{
|
||||
const char *shellname, *ptr;
|
||||
char *argv0;
|
||||
int mode;
|
||||
|
||||
ptr = strrchr(shell, '/');
|
||||
if (ptr != NULL && *(ptr + 1) != '\0')
|
||||
@@ -226,6 +215,14 @@ shell_exec(const char *shell, const char *shellcmd)
|
||||
xasprintf(&argv0, "%s", shellname);
|
||||
setenv("SHELL", shell, 1);
|
||||
|
||||
if ((mode = fcntl(STDIN_FILENO, F_GETFL)) != -1)
|
||||
fcntl(STDIN_FILENO, F_SETFL, mode & ~O_NONBLOCK);
|
||||
if ((mode = fcntl(STDOUT_FILENO, F_GETFL)) != -1)
|
||||
fcntl(STDOUT_FILENO, F_SETFL, mode & ~O_NONBLOCK);
|
||||
if ((mode = fcntl(STDERR_FILENO, F_GETFL)) != -1)
|
||||
fcntl(STDERR_FILENO, F_SETFL, mode & ~O_NONBLOCK);
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
|
||||
execl(shell, argv0, "-c", shellcmd, (char *) NULL);
|
||||
fatal("execl failed");
|
||||
}
|
||||
@@ -233,30 +230,20 @@ shell_exec(const char *shell, const char *shellcmd)
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct cmd_list *cmdlist;
|
||||
struct cmd *cmd;
|
||||
enum msgtype msg;
|
||||
struct passwd *pw;
|
||||
struct options *oo, *so, *wo;
|
||||
struct keylist *keylist;
|
||||
struct env_data envdata;
|
||||
struct msg_command_data cmddata;
|
||||
char *s, *shellcmd, *path, *label, *home, *cause;
|
||||
char cwd[MAXPATHLEN], **var;
|
||||
void *buf;
|
||||
size_t len;
|
||||
int opt, flags, quiet = 0, cmdflags = 0;
|
||||
short events;
|
||||
struct passwd *pw;
|
||||
struct options *oo, *so, *wo;
|
||||
struct keylist *keylist;
|
||||
char *s, *path, *label, *home, **var;
|
||||
int opt, flags, quiet, keys;
|
||||
|
||||
#if defined(DEBUG) && defined(__OpenBSD__)
|
||||
malloc_options = (char *) "AFGJPX";
|
||||
#endif
|
||||
|
||||
flags = 0;
|
||||
shellcmd = label = path = NULL;
|
||||
envdata.path = NULL;
|
||||
quiet = flags = 0;
|
||||
label = path = NULL;
|
||||
login_shell = (**argv == '-');
|
||||
while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUv")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUvV")) != -1) {
|
||||
switch (opt) {
|
||||
case '2':
|
||||
flags |= IDENTIFY_256COLOURS;
|
||||
@@ -267,10 +254,13 @@ main(int argc, char **argv)
|
||||
flags &= ~IDENTIFY_256COLOURS;
|
||||
break;
|
||||
case 'c':
|
||||
if (shellcmd != NULL)
|
||||
xfree(shellcmd);
|
||||
shellcmd = xstrdup(optarg);
|
||||
if (shell_cmd != NULL)
|
||||
xfree(shell_cmd);
|
||||
shell_cmd = xstrdup(optarg);
|
||||
break;
|
||||
case 'V':
|
||||
printf("%s %s\n", __progname, BUILD);
|
||||
exit(0);
|
||||
case 'f':
|
||||
if (cfg_file != NULL)
|
||||
xfree(cfg_file);
|
||||
@@ -305,7 +295,7 @@ main(int argc, char **argv)
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (shellcmd != NULL && argc != 0)
|
||||
if (shell_cmd != NULL && argc != 0)
|
||||
usage();
|
||||
|
||||
log_open_tty(debug_level);
|
||||
@@ -335,6 +325,7 @@ main(int argc, char **argv)
|
||||
oo = &global_options;
|
||||
options_set_number(oo, "quiet", quiet);
|
||||
options_set_number(oo, "escape-time", 500);
|
||||
options_set_number(oo, "exit-unattached", 0);
|
||||
|
||||
options_init(&global_s_options, NULL);
|
||||
so = &global_s_options;
|
||||
@@ -342,10 +333,13 @@ main(int argc, char **argv)
|
||||
options_set_number(so, "bell-action", BELL_ANY);
|
||||
options_set_number(so, "buffer-limit", 9);
|
||||
options_set_string(so, "default-command", "%s", "");
|
||||
options_set_string(so, "default-path", "%s", "");
|
||||
options_set_string(so, "default-shell", "%s", getshell());
|
||||
options_set_string(so, "default-terminal", "screen");
|
||||
options_set_number(so, "display-panes-colour", 4);
|
||||
options_set_number(so, "destroy-unattached", 0);
|
||||
options_set_number(so, "detach-on-destroy", 1);
|
||||
options_set_number(so, "display-panes-active-colour", 1);
|
||||
options_set_number(so, "display-panes-colour", 4);
|
||||
options_set_number(so, "display-panes-time", 1000);
|
||||
options_set_number(so, "display-time", 750);
|
||||
options_set_number(so, "history-limit", 2000);
|
||||
@@ -357,8 +351,8 @@ main(int argc, char **argv)
|
||||
options_set_number(so, "message-fg", 0);
|
||||
options_set_number(so, "message-limit", 20);
|
||||
options_set_number(so, "mouse-select-pane", 0);
|
||||
options_set_number(so, "pane-active-border-bg", 2);
|
||||
options_set_number(so, "pane-active-border-fg", 8);
|
||||
options_set_number(so, "pane-active-border-bg", 8);
|
||||
options_set_number(so, "pane-active-border-fg", 2);
|
||||
options_set_number(so, "pane-border-bg", 8);
|
||||
options_set_number(so, "pane-border-fg", 8);
|
||||
options_set_number(so, "repeat-time", 500);
|
||||
@@ -371,7 +365,6 @@ main(int argc, char **argv)
|
||||
options_set_number(so, "status-fg", 0);
|
||||
options_set_number(so, "status-interval", 15);
|
||||
options_set_number(so, "status-justify", 0);
|
||||
options_set_number(so, "status-keys", MODEKEY_EMACS);
|
||||
options_set_string(so, "status-left", "[#S]");
|
||||
options_set_number(so, "status-left-attr", 0);
|
||||
options_set_number(so, "status-left-bg", 8);
|
||||
@@ -384,11 +377,15 @@ main(int argc, char **argv)
|
||||
options_set_number(so, "status-right-length", 40);
|
||||
options_set_string(so, "terminal-overrides",
|
||||
"*88col*:colors=88,*256col*:colors=256");
|
||||
options_set_string(so, "update-environment", "DISPLAY "
|
||||
"WINDOWID SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION");
|
||||
options_set_string(so, "update-environment",
|
||||
"DISPLAY "
|
||||
"SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION "
|
||||
"WINDOWID "
|
||||
"XAUTHORITY");
|
||||
options_set_number(so, "visual-activity", 0);
|
||||
options_set_number(so, "visual-bell", 0);
|
||||
options_set_number(so, "visual-content", 0);
|
||||
options_set_number(so, "visual-silence", 0);
|
||||
|
||||
keylist = xmalloc(sizeof *keylist);
|
||||
ARRAY_INIT(keylist);
|
||||
@@ -405,20 +402,25 @@ main(int argc, char **argv)
|
||||
options_set_number(wo, "force-height", 0);
|
||||
options_set_number(wo, "force-width", 0);
|
||||
options_set_number(wo, "main-pane-height", 24);
|
||||
options_set_number(wo, "main-pane-width", 81);
|
||||
options_set_number(wo, "main-pane-width", 80);
|
||||
options_set_number(wo, "mode-attr", 0);
|
||||
options_set_number(wo, "mode-bg", 3);
|
||||
options_set_number(wo, "mode-fg", 0);
|
||||
options_set_number(wo, "mode-keys", MODEKEY_EMACS);
|
||||
options_set_number(wo, "mode-mouse", 0);
|
||||
options_set_number(wo, "monitor-activity", 0);
|
||||
options_set_string(wo, "monitor-content", "%s", "");
|
||||
options_set_number(wo, "monitor-silence", 0);
|
||||
options_set_number(wo, "other-pane-height", 0);
|
||||
options_set_number(wo, "other-pane-width", 0);
|
||||
options_set_number(wo, "window-status-attr", 0);
|
||||
options_set_number(wo, "window-status-bg", 8);
|
||||
options_set_number(wo, "window-status-current-attr", 0);
|
||||
options_set_number(wo, "window-status-current-bg", 8);
|
||||
options_set_number(wo, "window-status-current-fg", 8);
|
||||
options_set_number(wo, "window-status-fg", 8);
|
||||
options_set_number(wo, "window-status-alert-attr", GRID_ATTR_REVERSE);
|
||||
options_set_number(wo, "window-status-alert-bg", 8);
|
||||
options_set_number(wo, "window-status-alert-fg", 8);
|
||||
options_set_string(wo, "window-status-format", "#I:#W#F");
|
||||
options_set_string(wo, "window-status-current-format", "#I:#W#F");
|
||||
options_set_string(wo, "word-separators", " -_@");
|
||||
@@ -434,15 +436,17 @@ main(int argc, char **argv)
|
||||
options_set_number(wo, "utf8", 0);
|
||||
}
|
||||
|
||||
if (getcwd(cwd, sizeof cwd) == NULL) {
|
||||
pw = getpwuid(getuid());
|
||||
if (pw->pw_dir != NULL && *pw->pw_dir != '\0')
|
||||
strlcpy(cwd, pw->pw_dir, sizeof cwd);
|
||||
else
|
||||
strlcpy(cwd, "/", sizeof cwd);
|
||||
keys = MODEKEY_EMACS;
|
||||
if ((s = getenv("VISUAL")) != NULL || (s = getenv("EDITOR")) != NULL) {
|
||||
if (strrchr(s, '/') != NULL)
|
||||
s = strrchr(s, '/') + 1;
|
||||
if (strstr(s, "vi") != NULL)
|
||||
keys = MODEKEY_VI;
|
||||
}
|
||||
options_set_string(so, "default-path", "%s", cwd);
|
||||
options_set_number(so, "status-keys", keys);
|
||||
options_set_number(wo, "mode-keys", keys);
|
||||
|
||||
/* Locate the configuration file. */
|
||||
if (cfg_file == NULL) {
|
||||
home = getenv("HOME");
|
||||
if (home == NULL || *home == '\0') {
|
||||
@@ -458,21 +462,22 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out the socket path. If specified on the command-line with
|
||||
* -S or -L, use it, otherwise try $TMUX or assume -L default.
|
||||
* Figure out the socket path. If specified on the command-line with -S
|
||||
* or -L, use it, otherwise try $TMUX or assume -L default.
|
||||
*/
|
||||
parse_env(&envdata);
|
||||
parseenvironment();
|
||||
if (path == NULL) {
|
||||
/* No -L. Try $TMUX, or default. */
|
||||
/* If no -L, use the environment. */
|
||||
if (label == NULL) {
|
||||
path = envdata.path;
|
||||
if (path == NULL)
|
||||
if (environ_path != NULL)
|
||||
path = xstrdup(environ_path);
|
||||
else
|
||||
label = xstrdup("default");
|
||||
}
|
||||
|
||||
/* -L or default set. */
|
||||
if (label != NULL) {
|
||||
if ((path = makesockpath(label)) == NULL) {
|
||||
if ((path = makesocketpath(label)) == NULL) {
|
||||
log_warn("can't create socket");
|
||||
exit(1);
|
||||
}
|
||||
@@ -480,70 +485,16 @@ main(int argc, char **argv)
|
||||
}
|
||||
if (label != NULL)
|
||||
xfree(label);
|
||||
|
||||
if (shellcmd != NULL) {
|
||||
msg = MSG_SHELL;
|
||||
buf = NULL;
|
||||
len = 0;
|
||||
} else {
|
||||
cmddata.pid = envdata.pid;
|
||||
cmddata.idx = envdata.idx;
|
||||
|
||||
/* Prepare command for server. */
|
||||
cmddata.argc = argc;
|
||||
if (cmd_pack_argv(
|
||||
argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) {
|
||||
log_warnx("command too long");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
msg = MSG_COMMAND;
|
||||
buf = &cmddata;
|
||||
len = sizeof cmddata;
|
||||
}
|
||||
|
||||
if (shellcmd != NULL)
|
||||
cmdflags |= CMD_STARTSERVER;
|
||||
else if (argc == 0) /* new-session is the default */
|
||||
cmdflags |= CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST;
|
||||
else {
|
||||
/*
|
||||
* It sucks parsing the command string twice (in client and
|
||||
* later in server) but it is necessary to get the start server
|
||||
* flag.
|
||||
*/
|
||||
if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
|
||||
log_warnx("%s", cause);
|
||||
exit(1);
|
||||
}
|
||||
cmdflags &= ~CMD_STARTSERVER;
|
||||
TAILQ_FOREACH(cmd, cmdlist, qentry) {
|
||||
if (cmd->entry->flags & CMD_STARTSERVER)
|
||||
cmdflags |= CMD_STARTSERVER;
|
||||
if (cmd->entry->flags & CMD_SENDENVIRON)
|
||||
cmdflags |= CMD_SENDENVIRON;
|
||||
if (cmd->entry->flags & CMD_CANTNEST)
|
||||
cmdflags |= CMD_CANTNEST;
|
||||
}
|
||||
cmd_list_free(cmdlist);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if this could be a nested session, if the command can't nest:
|
||||
* if the socket path matches $TMUX, this is probably the same server.
|
||||
*/
|
||||
if (shellcmd == NULL && envdata.path != NULL &&
|
||||
cmdflags & CMD_CANTNEST &&
|
||||
(path == envdata.path || strcmp(path, envdata.path) == 0)) {
|
||||
log_warnx("sessions should be nested with care. "
|
||||
"unset $TMUX to force.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL)
|
||||
exit(1);
|
||||
if (realpath(path, socket_path) == NULL)
|
||||
strlcpy(socket_path, path, sizeof socket_path);
|
||||
xfree(path);
|
||||
|
||||
#ifdef HAVE_SETPROCTITLE
|
||||
/* Set process title. */
|
||||
setproctitle("%s (%s)", __progname, socket_path);
|
||||
#endif
|
||||
|
||||
/* Pass control to the client. */
|
||||
#ifdef HAVE_BROKEN_KQUEUE
|
||||
if (setenv("EVENT_NOKQUEUE", "1", 1) != 0)
|
||||
fatal("setenv failed");
|
||||
@@ -552,170 +503,12 @@ main(int argc, char **argv)
|
||||
if (setenv("EVENT_NOPOLL", "1", 1) != 0)
|
||||
fatal("setenv failed");
|
||||
#endif
|
||||
event_init();
|
||||
ev_base = event_init();
|
||||
#ifdef HAVE_BROKEN_KQUEUE
|
||||
unsetenv("EVENT_NOKQUEUE");
|
||||
#endif
|
||||
#ifdef HAVE_BROKEN_POLL
|
||||
unsetenv("EVENT_NOPOLL");
|
||||
#endif
|
||||
|
||||
imsg_compose(main_ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len);
|
||||
|
||||
main_set_signals();
|
||||
|
||||
events = EV_READ;
|
||||
if (main_ibuf->w.queued > 0)
|
||||
events |= EV_WRITE;
|
||||
event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL);
|
||||
|
||||
main_exitval = 0;
|
||||
event_dispatch();
|
||||
|
||||
main_clear_signals();
|
||||
|
||||
client_main(); /* doesn't return */
|
||||
}
|
||||
|
||||
void
|
||||
main_set_signals(void)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGINT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR1, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
|
||||
signal_set(&main_ev_sigterm, SIGTERM, main_signal, NULL);
|
||||
signal_add(&main_ev_sigterm, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
main_clear_signals(void)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_DFL;
|
||||
if (sigaction(SIGINT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR1, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
|
||||
event_del(&main_ev_sigterm);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
main_signal(int sig, unused short events, unused void *data)
|
||||
{
|
||||
switch (sig) {
|
||||
case SIGTERM:
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
main_callback(unused int fd, short events, void *data)
|
||||
{
|
||||
char *shellcmd = data;
|
||||
|
||||
if (events & EV_READ)
|
||||
main_dispatch(shellcmd);
|
||||
|
||||
if (events & EV_WRITE) {
|
||||
if (msgbuf_write(&main_ibuf->w) < 0)
|
||||
fatalx("msgbuf_write failed");
|
||||
}
|
||||
|
||||
events = EV_READ;
|
||||
if (main_ibuf->w.queued > 0)
|
||||
events |= EV_WRITE;
|
||||
event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
main_dispatch(const char *shellcmd)
|
||||
{
|
||||
struct imsg imsg;
|
||||
ssize_t n, datalen;
|
||||
struct msg_print_data printdata;
|
||||
struct msg_shell_data shelldata;
|
||||
|
||||
if ((n = imsg_read(main_ibuf)) == -1 || n == 0)
|
||||
fatalx("imsg_read failed");
|
||||
|
||||
for (;;) {
|
||||
if ((n = imsg_get(main_ibuf, &imsg)) == -1)
|
||||
fatalx("imsg_get failed");
|
||||
if (n == 0)
|
||||
return;
|
||||
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
|
||||
|
||||
switch (imsg.hdr.type) {
|
||||
case MSG_EXIT:
|
||||
case MSG_SHUTDOWN:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_EXIT size");
|
||||
|
||||
exit(main_exitval);
|
||||
case MSG_ERROR:
|
||||
case MSG_PRINT:
|
||||
if (datalen != sizeof printdata)
|
||||
fatalx("bad MSG_PRINT size");
|
||||
memcpy(&printdata, imsg.data, sizeof printdata);
|
||||
printdata.msg[(sizeof printdata.msg) - 1] = '\0';
|
||||
|
||||
log_info("%s", printdata.msg);
|
||||
if (imsg.hdr.type == MSG_ERROR)
|
||||
main_exitval = 1;
|
||||
break;
|
||||
case MSG_READY:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_READY size");
|
||||
|
||||
event_loopexit(NULL); /* move to client_main() */
|
||||
break;
|
||||
case MSG_VERSION:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_VERSION size");
|
||||
|
||||
log_warnx("protocol version mismatch (client %u, "
|
||||
"server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
|
||||
exit(1);
|
||||
case MSG_SHELL:
|
||||
if (datalen != sizeof shelldata)
|
||||
fatalx("bad MSG_SHELL size");
|
||||
memcpy(&shelldata, imsg.data, sizeof shelldata);
|
||||
shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
|
||||
|
||||
main_clear_signals();
|
||||
|
||||
shell_exec(shelldata.shell, shellcmd);
|
||||
default:
|
||||
fatalx("unexpected message");
|
||||
}
|
||||
|
||||
imsg_free(&imsg);
|
||||
}
|
||||
exit(client_main(argc, argv, flags));
|
||||
}
|
||||
|
||||
253
tmux.h
253
tmux.h
@@ -1,4 +1,4 @@
|
||||
/* $Id: tmux.h,v 1.547 2010-03-08 15:02:07 tcunha Exp $ */
|
||||
/* $Id: tmux.h,v 1.591 2010-12-22 15:36:44 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define PROTOCOL_VERSION 5
|
||||
#define PROTOCOL_VERSION 6
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
|
||||
@@ -58,8 +57,8 @@ extern char **environ;
|
||||
/* Automatic name refresh interval, in milliseconds. */
|
||||
#define NAME_INTERVAL 500
|
||||
|
||||
/* Maximum data to buffer for output before suspending reading from panes. */
|
||||
#define BACKOFF_THRESHOLD 1024
|
||||
/* Maximum data to buffer for output before suspending writing to a tty. */
|
||||
#define BACKOFF_THRESHOLD 16384
|
||||
|
||||
/*
|
||||
* Maximum sizes of strings in message data. Don't forget to bump
|
||||
@@ -67,7 +66,6 @@ extern char **environ;
|
||||
*/
|
||||
#define COMMAND_LENGTH 2048 /* packed argv size */
|
||||
#define TERMINAL_LENGTH 128 /* length of TERM environment variable */
|
||||
#define PRINT_LENGTH 512 /* printed error/message size */
|
||||
#define ENVIRON_LENGTH 1024 /* environment variable length */
|
||||
|
||||
/*
|
||||
@@ -110,6 +108,10 @@ extern char **environ;
|
||||
#define KEYC_SHIFT 0x8000
|
||||
#define KEYC_PREFIX 0x10000
|
||||
|
||||
/* Mask to obtain key w/o modifiers */
|
||||
#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_PREFIX)
|
||||
#define KEYC_MASK_KEY (~KEYC_MASK_MOD)
|
||||
|
||||
/* Other key codes. */
|
||||
enum key_code {
|
||||
/* Mouse key. */
|
||||
@@ -368,7 +370,9 @@ enum msgtype {
|
||||
MSG_ENVIRON,
|
||||
MSG_UNLOCK,
|
||||
MSG_LOCK,
|
||||
MSG_SHELL
|
||||
MSG_SHELL,
|
||||
MSG_STDERR,
|
||||
MSG_STDOUT,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -376,10 +380,6 @@ enum msgtype {
|
||||
*
|
||||
* Don't forget to bump PROTOCOL_VERSION if any of these change!
|
||||
*/
|
||||
struct msg_print_data {
|
||||
char msg[PRINT_LENGTH];
|
||||
};
|
||||
|
||||
struct msg_command_data {
|
||||
pid_t pid; /* pid from $TMUX or -1 */
|
||||
u_int idx; /* index from $TMUX */
|
||||
@@ -411,6 +411,10 @@ struct msg_shell_data {
|
||||
char shell[MAXPATHLEN];
|
||||
};
|
||||
|
||||
struct msg_exit_data {
|
||||
int retcode;
|
||||
};
|
||||
|
||||
/* Mode key commands. */
|
||||
enum mode_key_cmd {
|
||||
MODEKEY_NONE,
|
||||
@@ -458,6 +462,10 @@ enum mode_key_cmd {
|
||||
MODEKEYCOPY_HALFPAGEUP,
|
||||
MODEKEYCOPY_HISTORYBOTTOM,
|
||||
MODEKEYCOPY_HISTORYTOP,
|
||||
MODEKEYCOPY_JUMP,
|
||||
MODEKEYCOPY_JUMPAGAIN,
|
||||
MODEKEYCOPY_JUMPREVERSE,
|
||||
MODEKEYCOPY_JUMPBACK,
|
||||
MODEKEYCOPY_LEFT,
|
||||
MODEKEYCOPY_MIDDLELINE,
|
||||
MODEKEYCOPY_NEXTPAGE,
|
||||
@@ -536,6 +544,8 @@ struct mode_key_table {
|
||||
#define MODE_KCURSOR 0x4
|
||||
#define MODE_KKEYPAD 0x8 /* set = application, clear = number */
|
||||
#define MODE_MOUSE 0x10
|
||||
#define MODE_MOUSEMOTION 0x20
|
||||
#define MODE_WRAP 0x40 /* whether lines wrap */
|
||||
|
||||
/*
|
||||
* A single UTF-8 character.
|
||||
@@ -718,59 +728,52 @@ struct screen_write_ctx {
|
||||
#define screen_hsize(s) ((s)->grid->hsize)
|
||||
#define screen_hlimit(s) ((s)->grid->hlimit)
|
||||
|
||||
/* Input parser sequence argument. */
|
||||
struct input_arg {
|
||||
u_char data[64];
|
||||
size_t used;
|
||||
};
|
||||
|
||||
/* Input parser context. */
|
||||
struct input_ctx {
|
||||
struct window_pane *wp;
|
||||
struct window_pane *wp;
|
||||
struct screen_write_ctx ctx;
|
||||
|
||||
u_char *buf;
|
||||
size_t len;
|
||||
size_t off;
|
||||
size_t was;
|
||||
struct grid_cell cell;
|
||||
|
||||
struct grid_cell cell;
|
||||
struct grid_cell old_cell;
|
||||
u_int old_cx;
|
||||
u_int old_cy;
|
||||
|
||||
struct grid_cell saved_cell;
|
||||
u_int saved_cx;
|
||||
u_int saved_cy;
|
||||
u_char interm_buf[4];
|
||||
size_t interm_len;
|
||||
|
||||
#define MAXSTRINGLEN 1024
|
||||
u_char *string_buf;
|
||||
size_t string_len;
|
||||
int string_type;
|
||||
#define STRING_SYSTEM 0
|
||||
#define STRING_APPLICATION 1
|
||||
#define STRING_NAME 2
|
||||
u_char param_buf[64];
|
||||
size_t param_len;
|
||||
|
||||
struct utf8_data utf8data;
|
||||
u_char input_buf[256];
|
||||
size_t input_len;
|
||||
|
||||
u_char intermediate;
|
||||
void *(*state)(u_char, struct input_ctx *);
|
||||
int param_list[24]; /* -1 not present */
|
||||
u_int param_list_len;
|
||||
|
||||
u_char private;
|
||||
ARRAY_DECL(, struct input_arg) args;
|
||||
struct utf8_data utf8data;
|
||||
|
||||
int ch;
|
||||
int flags;
|
||||
#define INPUT_DISCARD 0x1
|
||||
|
||||
const struct input_state *state;
|
||||
};
|
||||
|
||||
/*
|
||||
* Window mode. Windows can be in several modes and this is used to call the
|
||||
* right function to handle input and output.
|
||||
*/
|
||||
struct client;
|
||||
struct session;
|
||||
struct window;
|
||||
struct mouse_event;
|
||||
struct window_mode {
|
||||
struct screen *(*init)(struct window_pane *);
|
||||
void (*free)(struct window_pane *);
|
||||
void (*resize)(struct window_pane *, u_int, u_int);
|
||||
void (*key)(struct window_pane *, struct client *, int);
|
||||
void (*key)(struct window_pane *, struct session *, int);
|
||||
void (*mouse)(struct window_pane *,
|
||||
struct client *, struct mouse_event *);
|
||||
struct session *, struct mouse_event *);
|
||||
void (*timer)(struct window_pane *);
|
||||
};
|
||||
|
||||
@@ -825,8 +828,10 @@ TAILQ_HEAD(window_panes, window_pane);
|
||||
struct window {
|
||||
char *name;
|
||||
struct event name_timer;
|
||||
struct timeval silence_timer;
|
||||
|
||||
struct window_pane *active;
|
||||
struct window_pane *last;
|
||||
struct window_panes panes;
|
||||
|
||||
int lastlayout;
|
||||
@@ -837,10 +842,9 @@ struct window {
|
||||
|
||||
int flags;
|
||||
#define WINDOW_BELL 0x1
|
||||
#define WINDOW_HIDDEN 0x2
|
||||
#define WINDOW_ACTIVITY 0x4
|
||||
#define WINDOW_CONTENT 0x8
|
||||
#define WINDOW_REDRAW 0x10
|
||||
#define WINDOW_ACTIVITY 0x2
|
||||
#define WINDOW_REDRAW 0x4
|
||||
#define WINDOW_SILENCE 0x8
|
||||
|
||||
struct options options;
|
||||
|
||||
@@ -857,6 +861,14 @@ struct winlink {
|
||||
struct grid_cell status_cell;
|
||||
char *status_text;
|
||||
|
||||
int flags;
|
||||
#define WINLINK_BELL 0x1
|
||||
#define WINLINK_ACTIVITY 0x2
|
||||
#define WINLINK_CONTENT 0x4
|
||||
#define WINLINK_SILENCE 0x8
|
||||
#define WINLINK_ALERTFLAGS \
|
||||
(WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_CONTENT|WINLINK_SILENCE)
|
||||
|
||||
RB_ENTRY(winlink) entry;
|
||||
TAILQ_ENTRY(winlink) sentry;
|
||||
};
|
||||
@@ -908,13 +920,6 @@ struct environ_entry {
|
||||
RB_HEAD(environ, environ_entry);
|
||||
|
||||
/* Client session. */
|
||||
struct session_alert {
|
||||
struct winlink *wl;
|
||||
int type;
|
||||
|
||||
SLIST_ENTRY(session_alert) entry;
|
||||
};
|
||||
|
||||
struct session_group {
|
||||
TAILQ_HEAD(, session) sessions;
|
||||
|
||||
@@ -923,7 +928,10 @@ struct session_group {
|
||||
TAILQ_HEAD(session_groups, session_group);
|
||||
|
||||
struct session {
|
||||
u_int idx;
|
||||
|
||||
char *name;
|
||||
char *cwd;
|
||||
|
||||
struct timeval creation_time;
|
||||
struct timeval activity_time;
|
||||
@@ -939,10 +947,7 @@ struct session {
|
||||
|
||||
struct paste_stack buffers;
|
||||
|
||||
SLIST_HEAD(, session_alert) alerts;
|
||||
|
||||
#define SESSION_UNATTACHED 0x1 /* not attached to any clients */
|
||||
#define SESSION_DEAD 0x2
|
||||
int flags;
|
||||
|
||||
struct termios *tio;
|
||||
@@ -952,8 +957,10 @@ struct session {
|
||||
int references;
|
||||
|
||||
TAILQ_ENTRY(session) gentry;
|
||||
RB_ENTRY(session) entry;
|
||||
};
|
||||
ARRAY_DECL(sessions, struct session *);
|
||||
RB_HEAD(sessions, session);
|
||||
ARRAY_DECL(sessionslist, struct session *);
|
||||
|
||||
/* TTY information. */
|
||||
struct tty_key {
|
||||
@@ -970,6 +977,8 @@ struct tty_term {
|
||||
char *name;
|
||||
u_int references;
|
||||
|
||||
char acs[UCHAR_MAX + 1][2];
|
||||
|
||||
struct tty_code codes[NTTYCODE];
|
||||
|
||||
#define TERM_256COLOURS 0x1
|
||||
@@ -1007,14 +1016,13 @@ struct tty {
|
||||
|
||||
struct grid_cell cell;
|
||||
|
||||
u_char acs[UCHAR_MAX + 1];
|
||||
|
||||
#define TTY_NOCURSOR 0x1
|
||||
#define TTY_FREEZE 0x2
|
||||
#define TTY_ESCAPE 0x4
|
||||
#define TTY_UTF8 0x8
|
||||
#define TTY_STARTED 0x10
|
||||
#define TTY_OPENED 0x20
|
||||
#define TTY_BACKOFF 0x40
|
||||
int flags;
|
||||
|
||||
int term_flags;
|
||||
@@ -1052,9 +1060,23 @@ struct tty_ctx {
|
||||
u_int last_width;
|
||||
};
|
||||
|
||||
/*
|
||||
* xterm mouse mode is fairly silly. Buttons are in the bottom two
|
||||
* bits: 0 button 1; 1 button 2; 2 button 3; 3 buttons released.
|
||||
*
|
||||
* Bit 3 is shift; bit 4 is meta; bit 5 control.
|
||||
*
|
||||
* Bit 6 is added for mouse buttons 4 and 5.
|
||||
*/
|
||||
/* Mouse input. */
|
||||
struct mouse_event {
|
||||
u_char b;
|
||||
#define MOUSE_1 0
|
||||
#define MOUSE_2 1
|
||||
#define MOUSE_3 2
|
||||
#define MOUSE_UP 3
|
||||
#define MOUSE_BUTTON 3
|
||||
#define MOUSE_45 64
|
||||
u_char x;
|
||||
u_char y;
|
||||
};
|
||||
@@ -1069,6 +1091,7 @@ struct message_entry {
|
||||
struct client {
|
||||
struct imsgbuf ibuf;
|
||||
struct event event;
|
||||
int retcode;
|
||||
|
||||
struct timeval creation_time;
|
||||
struct timeval activity_time;
|
||||
@@ -1079,6 +1102,18 @@ struct client {
|
||||
char *cwd;
|
||||
|
||||
struct tty tty;
|
||||
|
||||
int stdin_fd;
|
||||
void *stdin_data;
|
||||
void (*stdin_callback)(struct client *, void *);
|
||||
struct bufferevent *stdin_event;
|
||||
|
||||
int stdout_fd;
|
||||
struct bufferevent *stdout_event;
|
||||
|
||||
int stderr_fd;
|
||||
struct bufferevent *stderr_event;
|
||||
|
||||
struct event repeat_timer;
|
||||
|
||||
struct timeval status_timer;
|
||||
@@ -1087,7 +1122,7 @@ struct client {
|
||||
|
||||
#define CLIENT_TERMINAL 0x1
|
||||
#define CLIENT_PREFIX 0x2
|
||||
#define CLIENT_MOUSE 0x4
|
||||
#define CLIENT_EXIT 0x4
|
||||
#define CLIENT_REDRAW 0x8
|
||||
#define CLIENT_STATUS 0x10
|
||||
#define CLIENT_REPEAT 0x20 /* allow command to repeat within repeat time */
|
||||
@@ -1097,6 +1132,8 @@ struct client {
|
||||
#define CLIENT_DEAD 0x200
|
||||
#define CLIENT_BORDERS 0x400
|
||||
#define CLIENT_READONLY 0x800
|
||||
#define CLIENT_BACKOFF 0x1000
|
||||
#define CLIENT_REDRAWWINDOW 0x2000
|
||||
int flags;
|
||||
|
||||
struct event identify_timer;
|
||||
@@ -1111,16 +1148,15 @@ struct client {
|
||||
int (*prompt_callbackfn)(void *, const char *);
|
||||
void (*prompt_freefn)(void *);
|
||||
void *prompt_data;
|
||||
u_int prompt_hindex;
|
||||
|
||||
#define PROMPT_SINGLE 0x1
|
||||
int prompt_flags;
|
||||
|
||||
u_int prompt_hindex;
|
||||
ARRAY_DECL(, char *) prompt_hdata;
|
||||
|
||||
struct mode_key_data prompt_mdata;
|
||||
|
||||
struct session *session;
|
||||
struct session *last_session;
|
||||
|
||||
int references;
|
||||
};
|
||||
@@ -1161,7 +1197,10 @@ struct cmd {
|
||||
|
||||
TAILQ_ENTRY(cmd) qentry;
|
||||
};
|
||||
TAILQ_HEAD(cmd_list, cmd);
|
||||
struct cmd_list {
|
||||
int references;
|
||||
TAILQ_HEAD(, cmd) list;
|
||||
};
|
||||
|
||||
struct cmd_entry {
|
||||
const char *name;
|
||||
@@ -1254,20 +1293,25 @@ extern struct options global_options;
|
||||
extern struct options global_s_options;
|
||||
extern struct options global_w_options;
|
||||
extern struct environ global_environ;
|
||||
extern struct event_base *ev_base;
|
||||
extern char *cfg_file;
|
||||
extern char *shell_cmd;
|
||||
extern int debug_level;
|
||||
extern int be_quiet;
|
||||
extern time_t start_time;
|
||||
extern char *socket_path;
|
||||
extern char socket_path[MAXPATHLEN];
|
||||
extern int login_shell;
|
||||
extern char *environ_path;
|
||||
extern pid_t environ_pid;
|
||||
extern u_int environ_idx;
|
||||
void logfile(const char *);
|
||||
const char *getshell(void);
|
||||
int checkshell(const char *);
|
||||
int areshell(const char *);
|
||||
__dead void shell_exec(const char *, const char *);
|
||||
|
||||
/* cfg.c */
|
||||
extern int cfg_finished;
|
||||
struct causelist cfg_causes;
|
||||
extern struct causelist cfg_causes;
|
||||
void printflike2 cfg_add_cause(struct causelist *, const char *, ...);
|
||||
int load_cfg(const char *, struct cmd_ctx *, struct causelist *);
|
||||
|
||||
@@ -1332,10 +1376,10 @@ void environ_set(struct environ *, const char *, const char *);
|
||||
void environ_put(struct environ *, const char *);
|
||||
void environ_unset(struct environ *, const char *);
|
||||
void environ_update(const char *, struct environ *, struct environ *);
|
||||
void environ_push(struct environ *);
|
||||
|
||||
/* tty.c */
|
||||
void tty_raw(struct tty *, const char *);
|
||||
u_char tty_get_acs(struct tty *, u_char);
|
||||
void tty_attributes(struct tty *, const struct grid_cell *);
|
||||
void tty_reset(struct tty *);
|
||||
void tty_region_pane(struct tty *, const struct tty_ctx *, u_int, u_int);
|
||||
@@ -1349,7 +1393,7 @@ void tty_puts(struct tty *, const char *);
|
||||
void tty_putc(struct tty *, u_char);
|
||||
void tty_pututf8(struct tty *, const struct grid_utf8 *);
|
||||
void tty_init(struct tty *, int, char *);
|
||||
void tty_resize(struct tty *);
|
||||
int tty_resize(struct tty *);
|
||||
void tty_start_tty(struct tty *);
|
||||
void tty_stop_tty(struct tty *);
|
||||
void tty_set_title(struct tty *, const char *);
|
||||
@@ -1389,6 +1433,9 @@ const char *tty_term_string2(
|
||||
int tty_term_number(struct tty_term *, enum tty_code_code);
|
||||
int tty_term_flag(struct tty_term *, enum tty_code_code);
|
||||
|
||||
/* tty-acs.c */
|
||||
const char *tty_acs_get(struct tty *, u_char);
|
||||
|
||||
/* tty-keys.c */
|
||||
void tty_keys_init(struct tty *);
|
||||
void tty_keys_free(struct tty *);
|
||||
@@ -1404,6 +1451,7 @@ int paste_free_top(struct paste_stack *);
|
||||
int paste_free_index(struct paste_stack *, u_int);
|
||||
void paste_add(struct paste_stack *, char *, size_t, u_int);
|
||||
int paste_replace(struct paste_stack *, u_int, char *, size_t);
|
||||
char *paste_print(struct paste_buffer *, size_t);
|
||||
|
||||
/* clock.c */
|
||||
extern const char clock_table[14][5][5];
|
||||
@@ -1419,6 +1467,7 @@ const char *cmd_set_option_print(
|
||||
/* cmd.c */
|
||||
int cmd_pack_argv(int, char **, char *, size_t);
|
||||
int cmd_unpack_argv(char *, size_t, int, char ***);
|
||||
char **cmd_copy_argv(int, char **);
|
||||
void cmd_free_argv(int, char **);
|
||||
struct cmd *cmd_parse(int, char **, char **);
|
||||
int cmd_exec(struct cmd *, struct cmd_ctx *);
|
||||
@@ -1440,6 +1489,7 @@ extern const struct cmd_entry cmd_attach_session_entry;
|
||||
extern const struct cmd_entry cmd_bind_key_entry;
|
||||
extern const struct cmd_entry cmd_break_pane_entry;
|
||||
extern const struct cmd_entry cmd_capture_pane_entry;
|
||||
extern const struct cmd_entry cmd_choose_buffer_entry;
|
||||
extern const struct cmd_entry cmd_choose_client_entry;
|
||||
extern const struct cmd_entry cmd_choose_session_entry;
|
||||
extern const struct cmd_entry cmd_choose_window_entry;
|
||||
@@ -1462,6 +1512,7 @@ extern const struct cmd_entry cmd_kill_pane_entry;
|
||||
extern const struct cmd_entry cmd_kill_server_entry;
|
||||
extern const struct cmd_entry cmd_kill_session_entry;
|
||||
extern const struct cmd_entry cmd_kill_window_entry;
|
||||
extern const struct cmd_entry cmd_last_pane_entry;
|
||||
extern const struct cmd_entry cmd_last_window_entry;
|
||||
extern const struct cmd_entry cmd_link_window_entry;
|
||||
extern const struct cmd_entry cmd_list_buffers_entry;
|
||||
@@ -1494,7 +1545,6 @@ extern const struct cmd_entry cmd_run_shell_entry;
|
||||
extern const struct cmd_entry cmd_save_buffer_entry;
|
||||
extern const struct cmd_entry cmd_select_layout_entry;
|
||||
extern const struct cmd_entry cmd_select_pane_entry;
|
||||
extern const struct cmd_entry cmd_select_prompt_entry;
|
||||
extern const struct cmd_entry cmd_select_window_entry;
|
||||
extern const struct cmd_entry cmd_send_keys_entry;
|
||||
extern const struct cmd_entry cmd_send_prefix_entry;
|
||||
@@ -1558,8 +1608,7 @@ void cmd_buffer_free(struct cmd *);
|
||||
size_t cmd_buffer_print(struct cmd *, char *, size_t);
|
||||
|
||||
/* client.c */
|
||||
struct imsgbuf *client_init(char *, int, int);
|
||||
__dead void client_main(void);
|
||||
int client_main(int, char **, int);
|
||||
|
||||
/* key-bindings.c */
|
||||
extern struct key_bindings key_bindings;
|
||||
@@ -1582,9 +1631,7 @@ const char *key_string_lookup_key(int);
|
||||
/* server.c */
|
||||
extern struct clients clients;
|
||||
extern struct clients dead_clients;
|
||||
int server_start(char *);
|
||||
void server_signal_set(void);
|
||||
void server_signal_clear(void);
|
||||
int server_start(void);
|
||||
void server_update_socket(void);
|
||||
|
||||
/* server-client.c */
|
||||
@@ -1599,7 +1646,6 @@ void server_window_loop(void);
|
||||
|
||||
/* server-fn.c */
|
||||
void server_fill_environ(struct session *, struct environ *);
|
||||
void server_write_error(struct client *, const char *);
|
||||
void server_write_client(
|
||||
struct client *, enum msgtype, const void *, size_t);
|
||||
void server_write_session(
|
||||
@@ -1624,6 +1670,7 @@ void server_unlink_window(struct session *, struct winlink *);
|
||||
void server_destroy_pane(struct window_pane *);
|
||||
void server_destroy_session_group(struct session *);
|
||||
void server_destroy_session(struct session *);
|
||||
void server_check_unattached (void);
|
||||
void server_set_identify(struct client *);
|
||||
void server_clear_identify(struct client *);
|
||||
void server_update_event(struct client *);
|
||||
@@ -1789,9 +1836,7 @@ int screen_check_selection(struct screen *, u_int, u_int);
|
||||
|
||||
/* window.c */
|
||||
extern struct windows windows;
|
||||
int window_cmp(struct window *, struct window *);
|
||||
int winlink_cmp(struct winlink *, struct winlink *);
|
||||
RB_PROTOTYPE(windows, window, entry, window_cmp);
|
||||
RB_PROTOTYPE(winlinks, winlink, entry, winlink_cmp);
|
||||
struct winlink *winlink_find_by_index(struct winlinks *, int);
|
||||
struct winlink *winlink_find_by_window(struct winlinks *, struct window *);
|
||||
@@ -1801,6 +1846,10 @@ struct winlink *winlink_add(struct winlinks *, struct window *, int);
|
||||
void winlink_remove(struct winlinks *, struct winlink *);
|
||||
struct winlink *winlink_next(struct winlink *);
|
||||
struct winlink *winlink_previous(struct winlink *);
|
||||
struct winlink *winlink_next_by_number(struct winlink *, struct session *,
|
||||
int);
|
||||
struct winlink *winlink_previous_by_number(struct winlink *, struct session *,
|
||||
int);
|
||||
void winlink_stack_push(struct winlink_stack *, struct winlink *);
|
||||
void winlink_stack_remove(struct winlink_stack *, struct winlink *);
|
||||
int window_index(struct window *, u_int *);
|
||||
@@ -1815,6 +1864,10 @@ struct window_pane *window_add_pane(struct window *, u_int);
|
||||
void window_resize(struct window *, u_int, u_int);
|
||||
void window_remove_pane(struct window *, struct window_pane *);
|
||||
struct window_pane *window_pane_at_index(struct window *, u_int);
|
||||
struct window_pane *window_pane_next_by_number(struct window *,
|
||||
struct window_pane *, u_int);
|
||||
struct window_pane *window_pane_previous_by_number(struct window *,
|
||||
struct window_pane *, u_int);
|
||||
u_int window_pane_index(struct window *, struct window_pane *);
|
||||
u_int window_count_panes(struct window *);
|
||||
void window_destroy_panes(struct window *);
|
||||
@@ -1824,21 +1877,30 @@ int window_pane_spawn(struct window_pane *, const char *,
|
||||
const char *, const char *, struct environ *,
|
||||
struct termios *, char **);
|
||||
void window_pane_resize(struct window_pane *, u_int, u_int);
|
||||
void window_pane_alternate_on(
|
||||
struct window_pane *, struct grid_cell *);
|
||||
void window_pane_alternate_off(
|
||||
struct window_pane *, struct grid_cell *);
|
||||
int window_pane_set_mode(
|
||||
struct window_pane *, const struct window_mode *);
|
||||
void window_pane_reset_mode(struct window_pane *);
|
||||
void window_pane_parse(struct window_pane *);
|
||||
void window_pane_key(struct window_pane *, struct client *, int);
|
||||
void window_pane_key(struct window_pane *, struct session *, int);
|
||||
void window_pane_mouse(struct window_pane *,
|
||||
struct client *, struct mouse_event *);
|
||||
struct session *, struct mouse_event *);
|
||||
int window_pane_visible(struct window_pane *);
|
||||
char *window_pane_search(
|
||||
struct window_pane *, const char *, u_int *);
|
||||
struct window_pane *window_pane_find_up(struct window_pane *);
|
||||
struct window_pane *window_pane_find_down(struct window_pane *);
|
||||
struct window_pane *window_pane_find_left(struct window_pane *);
|
||||
struct window_pane *window_pane_find_right(struct window_pane *);
|
||||
|
||||
/* layout.c */
|
||||
u_int layout_count_cells(struct layout_cell *);
|
||||
struct layout_cell *layout_create_cell(struct layout_cell *);
|
||||
void layout_free_cell(struct layout_cell *);
|
||||
void layout_print_cell(struct layout_cell *, const char *, u_int);
|
||||
void layout_destroy_cell(struct layout_cell *, struct layout_cell **);
|
||||
void layout_set_size(
|
||||
struct layout_cell *, u_int, u_int, u_int, u_int);
|
||||
void layout_make_leaf(
|
||||
@@ -1859,6 +1921,10 @@ struct layout_cell *layout_split_pane(
|
||||
struct window_pane *, enum layout_type, int);
|
||||
void layout_close_pane(struct window_pane *);
|
||||
|
||||
/* layout-custom.c */
|
||||
char *layout_dump(struct window *);
|
||||
int layout_parse(struct window *, const char *);
|
||||
|
||||
/* layout-set.c */
|
||||
const char *layout_set_name(u_int);
|
||||
int layout_set_lookup(const char *);
|
||||
@@ -1869,19 +1935,19 @@ void layout_set_active_changed(struct window *);
|
||||
|
||||
/* layout-string.c */
|
||||
struct layout_cell *layout_find_string(struct window *, const char *);
|
||||
struct layout_cell *layout_find_bottomright(struct layout_cell *);
|
||||
|
||||
/* window-clock.c */
|
||||
extern const struct window_mode window_clock_mode;
|
||||
|
||||
/* window-copy.c */
|
||||
extern const struct window_mode window_copy_mode;
|
||||
void window_copy_init_from_pane(struct window_pane *);
|
||||
void window_copy_init_for_output(struct window_pane *);
|
||||
void window_copy_add(struct window_pane *, const char *, ...);
|
||||
void window_copy_vadd(struct window_pane *, const char *, va_list);
|
||||
void window_copy_pageup(struct window_pane *);
|
||||
|
||||
/* window-more.c */
|
||||
extern const struct window_mode window_more_mode;
|
||||
void window_more_add(struct window_pane *, const char *, ...);
|
||||
void window_more_vadd(struct window_pane *, const char *, va_list);
|
||||
|
||||
/* window-choose.c */
|
||||
extern const struct window_mode window_choose_mode;
|
||||
void window_choose_vadd(
|
||||
@@ -1895,26 +1961,31 @@ void window_choose_ready(struct window_pane *,
|
||||
void queue_window_name(struct window *);
|
||||
char *default_window_name(struct window *);
|
||||
|
||||
/* signal.c */
|
||||
void set_signals(void(*)(int, short, void *));
|
||||
void clear_signals(int);
|
||||
|
||||
/* session.c */
|
||||
extern struct sessions sessions;
|
||||
extern struct sessions dead_sessions;
|
||||
extern struct session_groups session_groups;
|
||||
void session_alert_add(struct session *, struct window *, int);
|
||||
void session_alert_cancel(struct session *, struct winlink *);
|
||||
int session_alert_has(struct session *, struct winlink *, int);
|
||||
int session_alert_has_window(struct session *, struct window *, int);
|
||||
int session_cmp(struct session *, struct session *);
|
||||
RB_PROTOTYPE(sessions, session, entry, session_cmp);
|
||||
int session_alive(struct session *);
|
||||
struct session *session_find(const char *);
|
||||
struct session *session_find_by_index(u_int);
|
||||
struct session *session_create(const char *, const char *, const char *,
|
||||
struct environ *, struct termios *, int, u_int, u_int,
|
||||
char **);
|
||||
void session_destroy(struct session *);
|
||||
int session_index(struct session *, u_int *);
|
||||
struct session *session_next_session(struct session *);
|
||||
struct session *session_previous_session(struct session *);
|
||||
struct winlink *session_new(struct session *,
|
||||
const char *, const char *, const char *, int, char **);
|
||||
struct winlink *session_attach(
|
||||
struct session *, struct window *, int, char **);
|
||||
int session_detach(struct session *, struct winlink *);
|
||||
int session_has(struct session *, struct window *);
|
||||
struct winlink* session_has(struct session *, struct window *);
|
||||
int session_next(struct session *, int);
|
||||
int session_previous(struct session *, int);
|
||||
int session_select(struct session *, int);
|
||||
|
||||
5
tools/check-compat.sh
Normal file
5
tools/check-compat.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
# $Id: check-compat.sh,v 1.1 2010-10-24 00:42:04 tcunha Exp $
|
||||
|
||||
grep "#include" compat.h|while read line; do
|
||||
grep "$line" *.[ch] compat/*.[ch]
|
||||
done
|
||||
@@ -1,6 +1,6 @@
|
||||
# $Id: dist.mk,v 1.8 2010-03-10 15:16:19 tcunha Exp $
|
||||
# $Id: dist.mk,v 1.11 2010-12-27 21:32:16 tcunha Exp $
|
||||
|
||||
VERSION= 1.2
|
||||
VERSION= 1.4
|
||||
|
||||
DISTDIR= tmux-${VERSION}
|
||||
DISTFILES= *.[ch] Makefile GNUmakefile configure tmux.1 \
|
||||
@@ -20,7 +20,7 @@ dist:
|
||||
|
||||
upload-index.html: update-index.html
|
||||
scp www/index.html www/main.css www/images/*.png \
|
||||
nicm,tmux@web.sf.net:/home/groups/t/tm/tmux/htdocs
|
||||
${USER},tmux@web.sf.net:/home/groups/t/tm/tmux/htdocs
|
||||
rm -f www/index.html www/images/small-*
|
||||
|
||||
update-index.html:
|
||||
|
||||
31
tools/fuzz.c
Normal file
31
tools/fuzz.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
time_t t;
|
||||
int i;
|
||||
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
t = time(NULL);
|
||||
srandom((u_int) t);
|
||||
|
||||
for (;;) {
|
||||
putchar('\033');
|
||||
|
||||
for (i = 0; i < random() % 25; i++) {
|
||||
if (i > 22)
|
||||
putchar(';');
|
||||
else
|
||||
putchar(random() % 256);
|
||||
}
|
||||
|
||||
/* usleep(100); */
|
||||
}
|
||||
}
|
||||
97
tty-acs.c
Normal file
97
tty-acs.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/* $Id: tty-acs.c,v 1.1 2010-09-18 15:43:53 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF 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 "tmux.h"
|
||||
|
||||
int tty_acs_cmp(const void *, const void *);
|
||||
|
||||
/* Table mapping ACS entries to UTF-8. */
|
||||
struct tty_acs_entry {
|
||||
u_char key;
|
||||
const char *string;
|
||||
};
|
||||
const struct tty_acs_entry tty_acs_table[] = {
|
||||
{ '+', "\342\206\222" },
|
||||
{ ',', "\342\206\220" },
|
||||
{ '-', "\342\206\221" },
|
||||
{ '.', "\342\206\223" },
|
||||
{ '0', "\342\226\256" },
|
||||
{ '`', "\342\227\206" },
|
||||
{ 'a', "\342\226\222" },
|
||||
{ 'f', "\302\260" },
|
||||
{ 'g', "\302\261" },
|
||||
{ 'h', "\342\226\222" },
|
||||
{ 'i', "\342\230\203" },
|
||||
{ 'j', "\342\224\230" },
|
||||
{ 'k', "\342\224\220" },
|
||||
{ 'l', "\342\224\214" },
|
||||
{ 'm', "\342\224\224" },
|
||||
{ 'n', "\342\224\274" },
|
||||
{ 'o', "\342\216\272" },
|
||||
{ 'p', "\342\216\273" },
|
||||
{ 'q', "\342\224\200" },
|
||||
{ 'r', "\342\216\274" },
|
||||
{ 's', "\342\216\275" },
|
||||
{ 't', "\342\224\234" },
|
||||
{ 'u', "\342\224\244" },
|
||||
{ 'v', "\342\224\264" },
|
||||
{ 'w', "\342\224\254" },
|
||||
{ 'x', "\342\224\202" },
|
||||
{ 'y', "\342\211\244" },
|
||||
{ 'z', "\342\211\245" },
|
||||
{ '{', "\317\200" },
|
||||
{ '|', "\342\211\240" },
|
||||
{ '}', "\302\243" },
|
||||
{ '~', "\302\267" }
|
||||
};
|
||||
|
||||
int
|
||||
tty_acs_cmp(const void *key, const void *value)
|
||||
{
|
||||
const struct tty_acs_entry *entry = value;
|
||||
u_char ch;
|
||||
|
||||
ch = *(u_char *) key;
|
||||
return (ch - entry->key);
|
||||
}
|
||||
|
||||
/* Retrieve ACS to output as a string. */
|
||||
const char *
|
||||
tty_acs_get(struct tty *tty, u_char ch)
|
||||
{
|
||||
struct tty_acs_entry *entry;
|
||||
|
||||
/* If not a UTF-8 terminal, use the ACS set. */
|
||||
if (!(tty->flags & TTY_UTF8)) {
|
||||
if (tty->term->acs[ch][0] == '\0')
|
||||
return (NULL);
|
||||
return (&tty->term->acs[ch][0]);
|
||||
}
|
||||
|
||||
/* Otherwise look up the UTF-8 translation. */
|
||||
entry = bsearch(&ch,
|
||||
tty_acs_table, nitems(tty_acs_table), sizeof tty_acs_table[0],
|
||||
tty_acs_cmp);
|
||||
if (entry == NULL)
|
||||
return (NULL);
|
||||
return (entry->string);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: tty-keys.c,v 1.55 2009-12-18 18:57:00 tcunha Exp $ */
|
||||
/* $Id: tty-keys.c,v 1.57 2010-06-06 00:23:44 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -408,7 +408,7 @@ tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size)
|
||||
(*size)++;
|
||||
|
||||
/* At the end of the string, return the current node. */
|
||||
if (len == 0)
|
||||
if (len == 0 || (tk->next == NULL && tk->key != KEYC_NONE))
|
||||
return (tk);
|
||||
|
||||
/* Move into the next tree for the following character. */
|
||||
@@ -612,7 +612,8 @@ tty_keys_mouse(const char *buf, size_t len, size_t *size, struct mouse_event *m)
|
||||
return (1);
|
||||
*size = 6;
|
||||
|
||||
log_debug("mouse input is: %.6s", buf);
|
||||
log_debug(
|
||||
"mouse input: %.6s (%hhu,%hhu/%hhu)", buf, buf[4], buf[5], buf[3]);
|
||||
|
||||
m->b = buf[3];
|
||||
m->x = buf[4];
|
||||
|
||||
17
tty-term.c
17
tty-term.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: tty-term.c,v 1.41 2009-12-18 07:42:30 nicm Exp $ */
|
||||
/* $Id: tty-term.c,v 1.43 2010-09-18 15:43:53 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -252,7 +252,8 @@ tty_term_override(struct tty_term *term, const char *overrides)
|
||||
} else if (entstr[strlen(entstr) - 1] == '@') {
|
||||
entstr[strlen(entstr) - 1] = '\0';
|
||||
removeflag = 1;
|
||||
}
|
||||
} else
|
||||
continue;
|
||||
|
||||
for (i = 0; i < NTTYCODE; i++) {
|
||||
ent = &tty_term_codes[i];
|
||||
@@ -304,6 +305,7 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause)
|
||||
u_int i;
|
||||
int n, error;
|
||||
char *s;
|
||||
const char *acs;
|
||||
|
||||
SLIST_FOREACH(term, &tty_terms, entry) {
|
||||
if (strcmp(term->name, name) == 0) {
|
||||
@@ -317,7 +319,7 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause)
|
||||
term->name = xstrdup(name);
|
||||
term->references = 1;
|
||||
term->flags = 0;
|
||||
memset(&term->codes, 0, sizeof term->codes);
|
||||
memset(term->codes, 0, sizeof term->codes);
|
||||
SLIST_INSERT_HEAD(&tty_terms, term, entry);
|
||||
|
||||
/* Set up curses terminal. */
|
||||
@@ -415,6 +417,15 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause)
|
||||
if (!tty_term_flag(term, TTYC_XENL))
|
||||
term->flags |= TERM_EARLYWRAP;
|
||||
|
||||
/* Generate ACS table. If none is present, use nearest ASCII. */
|
||||
memset(term->acs, 0, sizeof term->acs);
|
||||
if (tty_term_has(term, TTYC_ACSC))
|
||||
acs = tty_term_string(term, TTYC_ACSC);
|
||||
else
|
||||
acs = "a#j+k+l+m+n+o-p-q-r-s-t+u+v+w+x|y<z>~.";
|
||||
for (; acs[0] != '\0' && acs[1] != '\0'; acs += 2)
|
||||
term->acs[(u_char) acs[0]][0] = acs[1];
|
||||
|
||||
return (term);
|
||||
|
||||
error:
|
||||
|
||||
124
tty.c
124
tty.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: tty.c,v 1.189 2010-03-08 14:53:49 tcunha Exp $ */
|
||||
/* $Id: tty.c,v 1.197 2010-12-06 21:57:56 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -31,8 +31,6 @@
|
||||
void tty_read_callback(struct bufferevent *, void *);
|
||||
void tty_error_callback(struct bufferevent *, short, void *);
|
||||
|
||||
void tty_fill_acs(struct tty *);
|
||||
|
||||
int tty_try_256(struct tty *, u_char, const char *);
|
||||
int tty_try_88(struct tty *, u_char, const char *);
|
||||
|
||||
@@ -48,6 +46,9 @@ void tty_emulate_repeat(
|
||||
void tty_cell(struct tty *,
|
||||
const struct grid_cell *, const struct grid_utf8 *);
|
||||
|
||||
#define tty_use_acs(tty) \
|
||||
(tty_term_has(tty->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8))
|
||||
|
||||
void
|
||||
tty_init(struct tty *tty, int fd, char *term)
|
||||
{
|
||||
@@ -60,9 +61,6 @@ tty_init(struct tty *tty, int fd, char *term)
|
||||
tty->termname = xstrdup("unknown");
|
||||
else
|
||||
tty->termname = xstrdup(term);
|
||||
|
||||
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
|
||||
fatal("fcntl failed");
|
||||
tty->fd = fd;
|
||||
|
||||
if ((path = ttyname(fd)) == NULL)
|
||||
@@ -73,34 +71,55 @@ tty_init(struct tty *tty, int fd, char *term)
|
||||
tty->term_flags = 0;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
tty_resize(struct tty *tty)
|
||||
{
|
||||
struct winsize ws;
|
||||
u_int sx, sy;
|
||||
|
||||
if (ioctl(tty->fd, TIOCGWINSZ, &ws) != -1) {
|
||||
tty->sx = ws.ws_col;
|
||||
tty->sy = ws.ws_row;
|
||||
sx = ws.ws_col;
|
||||
if (sx == 0)
|
||||
sx = 80;
|
||||
sy = ws.ws_row;
|
||||
if (sy == 0)
|
||||
sy = 24;
|
||||
} else {
|
||||
sx = 80;
|
||||
sy = 24;
|
||||
}
|
||||
if (tty->sx == 0)
|
||||
tty->sx = 80;
|
||||
if (tty->sy == 0)
|
||||
tty->sy = 24;
|
||||
if (sx == tty->sx && sy == tty->sy)
|
||||
return (0);
|
||||
tty->sx = sx;
|
||||
tty->sy = sy;
|
||||
|
||||
tty->cx = UINT_MAX;
|
||||
tty->cy = UINT_MAX;
|
||||
|
||||
tty->rupper = UINT_MAX;
|
||||
tty->rlower = UINT_MAX;
|
||||
|
||||
/*
|
||||
* If the terminal has been started, reset the actual scroll region and
|
||||
* cursor position, as this may not have happened.
|
||||
*/
|
||||
if (tty->flags & TTY_STARTED) {
|
||||
tty_cursor(tty, 0, 0);
|
||||
tty_region(tty, 0, tty->sy - 1);
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
int
|
||||
tty_open(struct tty *tty, const char *overrides, char **cause)
|
||||
{
|
||||
char out[64];
|
||||
int fd;
|
||||
|
||||
if (debug_level > 3) {
|
||||
fd = open("tmux.out", O_WRONLY|O_CREAT|O_TRUNC, 0644);
|
||||
xsnprintf(out, sizeof out, "tmux-out-%ld.log", (long) getpid());
|
||||
fd = open(out, O_WRONLY|O_CREAT|O_TRUNC, 0644);
|
||||
if (fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
|
||||
fatal("fcntl failed");
|
||||
tty->log_fd = fd;
|
||||
@@ -122,8 +141,6 @@ tty_open(struct tty *tty, const char *overrides, char **cause)
|
||||
|
||||
tty_keys_init(tty);
|
||||
|
||||
tty_fill_acs(tty);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -180,7 +197,8 @@ tty_start_tty(struct tty *tty)
|
||||
memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell);
|
||||
|
||||
tty_putcode(tty, TTYC_RMKX);
|
||||
tty_putcode(tty, TTYC_ENACS);
|
||||
if (tty_use_acs(tty))
|
||||
tty_putcode(tty, TTYC_ENACS);
|
||||
tty_putcode(tty, TTYC_CLEAR);
|
||||
|
||||
tty_putcode(tty, TTYC_CNORM);
|
||||
@@ -221,7 +239,8 @@ tty_stop_tty(struct tty *tty)
|
||||
return;
|
||||
|
||||
tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1));
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS));
|
||||
if (tty_use_acs(tty))
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS));
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0));
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX));
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR));
|
||||
@@ -236,30 +255,6 @@ tty_stop_tty(struct tty *tty)
|
||||
fcntl(tty->fd, F_SETFL, mode & ~O_NONBLOCK);
|
||||
}
|
||||
|
||||
void
|
||||
tty_fill_acs(struct tty *tty)
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
memset(tty->acs, 0, sizeof tty->acs);
|
||||
if (!tty_term_has(tty->term, TTYC_ACSC))
|
||||
return;
|
||||
|
||||
ptr = tty_term_string(tty->term, TTYC_ACSC);
|
||||
if (strlen(ptr) % 2 != 0)
|
||||
return;
|
||||
for (; *ptr != '\0'; ptr += 2)
|
||||
tty->acs[(u_char) ptr[0]] = ptr[1];
|
||||
}
|
||||
|
||||
u_char
|
||||
tty_get_acs(struct tty *tty, u_char ch)
|
||||
{
|
||||
if (tty->acs[ch] != '\0')
|
||||
return (tty->acs[ch]);
|
||||
return (ch);
|
||||
}
|
||||
|
||||
void
|
||||
tty_close(struct tty *tty)
|
||||
{
|
||||
@@ -339,11 +334,17 @@ tty_puts(struct tty *tty, const char *s)
|
||||
void
|
||||
tty_putc(struct tty *tty, u_char ch)
|
||||
{
|
||||
u_int sx;
|
||||
const char *acs;
|
||||
u_int sx;
|
||||
|
||||
if (tty->cell.attr & GRID_ATTR_CHARSET)
|
||||
ch = tty_get_acs(tty, ch);
|
||||
bufferevent_write(tty->event, &ch, 1);
|
||||
if (tty->cell.attr & GRID_ATTR_CHARSET) {
|
||||
acs = tty_acs_get(tty, ch);
|
||||
if (acs != NULL)
|
||||
bufferevent_write(tty->event, acs, strlen(acs));
|
||||
else
|
||||
bufferevent_write(tty->event, &ch, 1);
|
||||
} else
|
||||
bufferevent_write(tty->event, &ch, 1);
|
||||
|
||||
if (ch >= 0x20 && ch != 0x7f) {
|
||||
sx = tty->sx;
|
||||
@@ -402,11 +403,18 @@ tty_update_mode(struct tty *tty, int mode)
|
||||
else
|
||||
tty_putcode(tty, TTYC_CIVIS);
|
||||
}
|
||||
if (changed & MODE_MOUSE) {
|
||||
if (mode & MODE_MOUSE)
|
||||
tty_puts(tty, "\033[?1000h");
|
||||
else
|
||||
tty_puts(tty, "\033[?1000l");
|
||||
if (changed & (MODE_MOUSE|MODE_MOUSEMOTION)) {
|
||||
if (mode & MODE_MOUSE) {
|
||||
if (mode & MODE_MOUSEMOTION)
|
||||
tty_puts(tty, "\033[?1003h");
|
||||
else
|
||||
tty_puts(tty, "\033[?1000h");
|
||||
} else {
|
||||
if (mode & MODE_MOUSEMOTION)
|
||||
tty_puts(tty, "\033[?1003l");
|
||||
else
|
||||
tty_puts(tty, "\033[?1000l");
|
||||
}
|
||||
}
|
||||
if (changed & MODE_KKEYPAD) {
|
||||
if (mode & MODE_KKEYPAD)
|
||||
@@ -539,7 +547,7 @@ tty_write(void (*cmdfn)(
|
||||
|
||||
if (wp->window->flags & WINDOW_REDRAW || wp->flags & PANE_REDRAW)
|
||||
return;
|
||||
if (wp->window->flags & WINDOW_HIDDEN || !window_pane_visible(wp))
|
||||
if (!window_pane_visible(wp))
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
@@ -550,7 +558,9 @@ tty_write(void (*cmdfn)(
|
||||
continue;
|
||||
|
||||
if (c->session->curw->window == wp->window) {
|
||||
if (c->tty.flags & TTY_FREEZE || c->tty.term == NULL)
|
||||
if (c->tty.term == NULL)
|
||||
continue;
|
||||
if (c->tty.flags & (TTY_FREEZE|TTY_BACKOFF))
|
||||
continue;
|
||||
cmdfn(&c->tty, ctx);
|
||||
}
|
||||
@@ -967,7 +977,7 @@ tty_reset(struct tty *tty)
|
||||
if (memcmp(gc, &grid_default_cell, sizeof *gc) == 0)
|
||||
return;
|
||||
|
||||
if (tty_term_has(tty->term, TTYC_RMACS) && gc->attr & GRID_ATTR_CHARSET)
|
||||
if ((gc->attr & GRID_ATTR_CHARSET) && tty_use_acs(tty))
|
||||
tty_putcode(tty, TTYC_RMACS);
|
||||
tty_putcode(tty, TTYC_SGR0);
|
||||
memcpy(gc, &grid_default_cell, sizeof *gc);
|
||||
@@ -1083,7 +1093,7 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy)
|
||||
* Use HPA if change is larger than absolute, otherwise move
|
||||
* the cursor with CUB/CUF.
|
||||
*/
|
||||
if (abs(change) > cx && tty_term_has(term, TTYC_HPA)) {
|
||||
if ((u_int) abs(change) > cx && tty_term_has(term, TTYC_HPA)) {
|
||||
tty_putcode1(tty, TTYC_HPA, cx);
|
||||
goto out;
|
||||
} else if (change > 0 && tty_term_has(term, TTYC_CUB)) {
|
||||
@@ -1119,7 +1129,7 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy)
|
||||
* Try to use VPA if change is larger than absolute or if this
|
||||
* change would cross the scroll region, otherwise use CUU/CUD.
|
||||
*/
|
||||
if (abs(change) > cy ||
|
||||
if ((u_int) abs(change) > cy ||
|
||||
(change < 0 && cy - change > tty->rlower) ||
|
||||
(change > 0 && cy - change < tty->rupper)) {
|
||||
if (tty_term_has(term, TTYC_VPA)) {
|
||||
@@ -1204,7 +1214,7 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc)
|
||||
}
|
||||
if (changed & GRID_ATTR_HIDDEN)
|
||||
tty_putcode(tty, TTYC_INVIS);
|
||||
if (changed & GRID_ATTR_CHARSET)
|
||||
if ((changed & GRID_ATTR_CHARSET) && tty_use_acs(tty))
|
||||
tty_putcode(tty, TTYC_SMACS);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: window-choose.c,v 1.29 2010-02-02 23:55:21 tcunha Exp $ */
|
||||
/* $Id: window-choose.c,v 1.30 2010-05-22 21:56:04 micahcowan Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -25,9 +25,9 @@
|
||||
struct screen *window_choose_init(struct window_pane *);
|
||||
void window_choose_free(struct window_pane *);
|
||||
void window_choose_resize(struct window_pane *, u_int, u_int);
|
||||
void window_choose_key(struct window_pane *, struct client *, int);
|
||||
void window_choose_key(struct window_pane *, struct session *, int);
|
||||
void window_choose_mouse(
|
||||
struct window_pane *, struct client *, struct mouse_event *);
|
||||
struct window_pane *, struct session *, struct mouse_event *);
|
||||
|
||||
void window_choose_redraw_screen(struct window_pane *);
|
||||
void window_choose_write_line(
|
||||
@@ -171,7 +171,7 @@ window_choose_resize(struct window_pane *wp, u_int sx, u_int sy)
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
window_choose_key(struct window_pane *wp, unused struct client *c, int key)
|
||||
window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
|
||||
{
|
||||
struct window_choose_mode_data *data = wp->modedata;
|
||||
struct screen *s = &data->screen;
|
||||
@@ -304,7 +304,7 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key)
|
||||
/* ARGSUSED */
|
||||
void
|
||||
window_choose_mouse(
|
||||
struct window_pane *wp, unused struct client *c, struct mouse_event *m)
|
||||
struct window_pane *wp, unused struct session *sess, struct mouse_event *m)
|
||||
{
|
||||
struct window_choose_mode_data *data = wp->modedata;
|
||||
struct screen *s = &data->screen;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: window-clock.c,v 1.11 2009-12-04 22:14:47 tcunha Exp $ */
|
||||
/* $Id: window-clock.c,v 1.12 2010-05-22 21:56:04 micahcowan Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -26,7 +26,7 @@
|
||||
struct screen *window_clock_init(struct window_pane *);
|
||||
void window_clock_free(struct window_pane *);
|
||||
void window_clock_resize(struct window_pane *, u_int, u_int);
|
||||
void window_clock_key(struct window_pane *, struct client *, int);
|
||||
void window_clock_key(struct window_pane *, struct session *, int);
|
||||
void window_clock_timer(struct window_pane *);
|
||||
|
||||
void window_clock_draw_screen(struct window_pane *);
|
||||
@@ -85,7 +85,7 @@ window_clock_resize(struct window_pane *wp, u_int sx, u_int sy)
|
||||
/* ARGSUSED */
|
||||
void
|
||||
window_clock_key(
|
||||
struct window_pane *wp, unused struct client *c, unused int key)
|
||||
struct window_pane *wp, unused struct session *sess, unused int key)
|
||||
{
|
||||
window_pane_reset_mode(wp);
|
||||
}
|
||||
|
||||
463
window-copy.c
463
window-copy.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: window-copy.c,v 1.109 2010-03-08 15:02:07 tcunha Exp $ */
|
||||
/* $Id: window-copy.c,v 1.125 2010-12-11 17:57:28 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -26,11 +26,11 @@
|
||||
struct screen *window_copy_init(struct window_pane *);
|
||||
void window_copy_free(struct window_pane *);
|
||||
void window_copy_resize(struct window_pane *, u_int, u_int);
|
||||
void window_copy_key(struct window_pane *, struct client *, int);
|
||||
void window_copy_key(struct window_pane *, struct session *, int);
|
||||
int window_copy_key_input(struct window_pane *, int);
|
||||
int window_copy_key_numeric_prefix(struct window_pane *, int);
|
||||
void window_copy_mouse(
|
||||
struct window_pane *, struct client *, struct mouse_event *);
|
||||
struct window_pane *, struct session *, struct mouse_event *);
|
||||
|
||||
void window_copy_redraw_lines(struct window_pane *, u_int, u_int);
|
||||
void window_copy_redraw_screen(struct window_pane *);
|
||||
@@ -52,7 +52,7 @@ void window_copy_goto_line(struct window_pane *, const char *);
|
||||
void window_copy_update_cursor(struct window_pane *, u_int, u_int);
|
||||
void window_copy_start_selection(struct window_pane *);
|
||||
int window_copy_update_selection(struct window_pane *);
|
||||
void window_copy_copy_selection(struct window_pane *, struct client *);
|
||||
void window_copy_copy_selection(struct window_pane *, struct session *);
|
||||
void window_copy_clear_selection(struct window_pane *);
|
||||
void window_copy_copy_line(
|
||||
struct window_pane *, char **, size_t *, u_int, u_int, u_int);
|
||||
@@ -65,6 +65,8 @@ void window_copy_cursor_left(struct window_pane *);
|
||||
void window_copy_cursor_right(struct window_pane *);
|
||||
void window_copy_cursor_up(struct window_pane *, int);
|
||||
void window_copy_cursor_down(struct window_pane *, int);
|
||||
void window_copy_cursor_jump(struct window_pane *);
|
||||
void window_copy_cursor_jump_back(struct window_pane *);
|
||||
void window_copy_cursor_next_word(struct window_pane *, const char *);
|
||||
void window_copy_cursor_next_word_end(struct window_pane *, const char *);
|
||||
void window_copy_cursor_previous_word(struct window_pane *, const char *);
|
||||
@@ -86,12 +88,33 @@ enum window_copy_input_type {
|
||||
WINDOW_COPY_NUMERICPREFIX,
|
||||
WINDOW_COPY_SEARCHUP,
|
||||
WINDOW_COPY_SEARCHDOWN,
|
||||
WINDOW_COPY_JUMPFORWARD,
|
||||
WINDOW_COPY_JUMPBACK,
|
||||
WINDOW_COPY_GOTOLINE,
|
||||
};
|
||||
|
||||
/*
|
||||
* Copy-mode's visible screen (the "screen" field) is filled from one of
|
||||
* two sources: the original contents of the pane (used when we
|
||||
* actually enter via the "copy-mode" command, to copy the contents of
|
||||
* the current pane), or else a series of lines containing the output
|
||||
* from an output-writing tmux command (such as any of the "show-*" or
|
||||
* "list-*" commands).
|
||||
*
|
||||
* In either case, the full content of the copy-mode grid is pointed at
|
||||
* by the "backing" field, and is copied into "screen" as needed (that
|
||||
* is, when scrolling occurs). When copy-mode is backed by a pane,
|
||||
* backing points directly at that pane's screen structure (&wp->base);
|
||||
* when backed by a list of output-lines from a command, it points at
|
||||
* a newly-allocated screen structure (which is deallocated when the
|
||||
* mode ends).
|
||||
*/
|
||||
struct window_copy_mode_data {
|
||||
struct screen screen;
|
||||
|
||||
struct screen *backing;
|
||||
int backing_written; /* backing display has started */
|
||||
|
||||
struct mode_key_data mdata;
|
||||
|
||||
u_int oy;
|
||||
@@ -115,6 +138,9 @@ struct window_copy_mode_data {
|
||||
|
||||
enum window_copy_input_type searchtype;
|
||||
char *searchstr;
|
||||
|
||||
enum window_copy_input_type jumptype;
|
||||
char jumpchar;
|
||||
};
|
||||
|
||||
struct screen *
|
||||
@@ -122,18 +148,18 @@ window_copy_init(struct window_pane *wp)
|
||||
{
|
||||
struct window_copy_mode_data *data;
|
||||
struct screen *s;
|
||||
struct screen_write_ctx ctx;
|
||||
u_int i;
|
||||
int keys;
|
||||
|
||||
wp->modedata = data = xmalloc(sizeof *data);
|
||||
data->oy = 0;
|
||||
data->cx = wp->base.cx;
|
||||
data->cy = wp->base.cy;
|
||||
data->cx = 0;
|
||||
data->cy = 0;
|
||||
|
||||
data->lastcx = 0;
|
||||
data->lastsx = 0;
|
||||
|
||||
data->backing_written = 0;
|
||||
|
||||
data->rectflag = 0;
|
||||
|
||||
data->inputtype = WINDOW_COPY_OFF;
|
||||
@@ -145,7 +171,11 @@ window_copy_init(struct window_pane *wp)
|
||||
data->searchstr = NULL;
|
||||
|
||||
wp->flags |= PANE_FREEZE;
|
||||
bufferevent_disable(wp->event, EV_READ|EV_WRITE);
|
||||
if (wp->fd != -1)
|
||||
bufferevent_disable(wp->event, EV_READ|EV_WRITE);
|
||||
|
||||
data->jumptype = WINDOW_COPY_OFF;
|
||||
data->jumpchar = '\0';
|
||||
|
||||
s = &data->screen;
|
||||
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
|
||||
@@ -158,6 +188,26 @@ window_copy_init(struct window_pane *wp)
|
||||
else
|
||||
mode_key_init(&data->mdata, &mode_key_tree_vi_copy);
|
||||
|
||||
data->backing = NULL;
|
||||
|
||||
return (s);
|
||||
}
|
||||
|
||||
void
|
||||
window_copy_init_from_pane(struct window_pane *wp)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *s = &data->screen;
|
||||
struct screen_write_ctx ctx;
|
||||
u_int i;
|
||||
|
||||
if (wp->mode != &window_copy_mode)
|
||||
fatalx("not in copy mode");
|
||||
|
||||
data->backing = &wp->base;
|
||||
data->cx = data->backing->cx;
|
||||
data->cy = data->backing->cy;
|
||||
|
||||
s->cx = data->cx;
|
||||
s->cy = data->cy;
|
||||
|
||||
@@ -166,8 +216,17 @@ window_copy_init(struct window_pane *wp)
|
||||
window_copy_write_line(wp, &ctx, i);
|
||||
screen_write_cursormove(&ctx, data->cx, data->cy);
|
||||
screen_write_stop(&ctx);
|
||||
}
|
||||
|
||||
return (s);
|
||||
void
|
||||
window_copy_init_for_output(struct window_pane *wp)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
|
||||
data->backing = xmalloc(sizeof *data->backing);
|
||||
screen_init(data->backing, screen_size_x(&wp->base),
|
||||
screen_size_y(&wp->base), UINT_MAX);
|
||||
data->backing->mode &= ~MODE_WRAP;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -176,17 +235,80 @@ window_copy_free(struct window_pane *wp)
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
|
||||
wp->flags &= ~PANE_FREEZE;
|
||||
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
|
||||
if (wp->fd != -1)
|
||||
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
|
||||
|
||||
if (data->searchstr != NULL)
|
||||
xfree(data->searchstr);
|
||||
xfree(data->inputstr);
|
||||
|
||||
if (data->backing != &wp->base) {
|
||||
screen_free(data->backing);
|
||||
xfree(data->backing);
|
||||
}
|
||||
screen_free(&data->screen);
|
||||
|
||||
xfree(data);
|
||||
}
|
||||
|
||||
void
|
||||
window_copy_add(struct window_pane *wp, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
window_copy_vadd(wp, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *backing = data->backing;
|
||||
struct screen_write_ctx back_ctx, ctx;
|
||||
struct grid_cell gc;
|
||||
int utf8flag;
|
||||
u_int old_hsize;
|
||||
|
||||
if (backing == &wp->base)
|
||||
return;
|
||||
|
||||
utf8flag = options_get_number(&wp->window->options, "utf8");
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
|
||||
old_hsize = screen_hsize(data->backing);
|
||||
screen_write_start(&back_ctx, NULL, backing);
|
||||
if (data->backing_written) {
|
||||
/*
|
||||
* On the second or later line, do a CRLF before writing
|
||||
* (so it's on a new line).
|
||||
*/
|
||||
screen_write_carriagereturn(&back_ctx);
|
||||
screen_write_linefeed(&back_ctx, 0);
|
||||
} else
|
||||
data->backing_written = 1;
|
||||
screen_write_vnputs(&back_ctx, 0, &gc, utf8flag, fmt, ap);
|
||||
screen_write_stop(&back_ctx);
|
||||
|
||||
data->oy += screen_hsize(data->backing) - old_hsize;
|
||||
|
||||
screen_write_start(&ctx, wp, &data->screen);
|
||||
|
||||
/*
|
||||
* If the history has changed, draw the top line.
|
||||
* (If there's any history at all, it has changed.)
|
||||
*/
|
||||
if (screen_hsize(data->backing))
|
||||
window_copy_redraw_lines(wp, 0, 1);
|
||||
|
||||
/* Write the line, if it's visible. */
|
||||
if (backing->cy + data->oy < screen_size_y(backing))
|
||||
window_copy_redraw_lines(wp, backing->cy, 1);
|
||||
|
||||
screen_write_stop(&ctx);
|
||||
}
|
||||
|
||||
void
|
||||
window_copy_pageup(struct window_pane *wp)
|
||||
{
|
||||
@@ -197,8 +319,8 @@ window_copy_pageup(struct window_pane *wp)
|
||||
n = 1;
|
||||
if (screen_size_y(s) > 2)
|
||||
n = screen_size_y(s) - 2;
|
||||
if (data->oy + n > screen_hsize(&wp->base))
|
||||
data->oy = screen_hsize(&wp->base);
|
||||
if (data->oy + n > screen_hsize(data->backing))
|
||||
data->oy = screen_hsize(data->backing);
|
||||
else
|
||||
data->oy += n;
|
||||
window_copy_update_selection(wp);
|
||||
@@ -213,11 +335,15 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
|
||||
struct screen_write_ctx ctx;
|
||||
|
||||
screen_resize(s, sx, sy);
|
||||
if (data->backing != &wp->base)
|
||||
screen_resize(data->backing, sx, sy);
|
||||
|
||||
if (data->cy > sy - 1)
|
||||
data->cy = sy - 1;
|
||||
if (data->cx > sx)
|
||||
data->cx = sx;
|
||||
if (data->oy > screen_hsize(data->backing))
|
||||
data->oy = screen_hsize(data->backing);
|
||||
|
||||
window_copy_clear_selection(wp);
|
||||
|
||||
@@ -229,7 +355,7 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
|
||||
}
|
||||
|
||||
void
|
||||
window_copy_key(struct window_pane *wp, struct client *c, int key)
|
||||
window_copy_key(struct window_pane *wp, struct session *sess, int key)
|
||||
{
|
||||
const char *word_separators;
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
@@ -242,7 +368,24 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
|
||||
if (np == 0)
|
||||
np = 1;
|
||||
|
||||
if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
|
||||
if (data->inputtype == WINDOW_COPY_JUMPFORWARD
|
||||
|| data->inputtype == WINDOW_COPY_JUMPBACK) {
|
||||
/* Ignore keys with modifiers. */
|
||||
if ((key & KEYC_MASK_MOD) == 0) {
|
||||
data->jumpchar = key;
|
||||
if (data->inputtype == WINDOW_COPY_JUMPFORWARD) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump(wp);
|
||||
} else {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump_back(wp);
|
||||
}
|
||||
}
|
||||
data->jumptype = data->inputtype;
|
||||
data->inputtype = WINDOW_COPY_OFF;
|
||||
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
|
||||
return;
|
||||
} if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
|
||||
if (window_copy_key_numeric_prefix(wp, key) == 0)
|
||||
return;
|
||||
data->inputtype = WINDOW_COPY_OFF;
|
||||
@@ -256,9 +399,8 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
|
||||
cmd = mode_key_lookup(&data->mdata, key);
|
||||
switch (cmd) {
|
||||
case MODEKEYCOPY_CANCEL:
|
||||
for (; np != 0; np--)
|
||||
window_pane_reset_mode(wp);
|
||||
break;
|
||||
window_pane_reset_mode(wp);
|
||||
return;
|
||||
case MODEKEYCOPY_LEFT:
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_left(wp);
|
||||
@@ -303,8 +445,8 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
|
||||
case MODEKEYCOPY_HALFPAGEUP:
|
||||
n = screen_size_y(s) / 2;
|
||||
for (; np != 0; np--) {
|
||||
if (data->oy + n > screen_hsize(&wp->base))
|
||||
data->oy = screen_hsize(&wp->base);
|
||||
if (data->oy + n > screen_hsize(data->backing))
|
||||
data->oy = screen_hsize(data->backing);
|
||||
else
|
||||
data->oy += n;
|
||||
}
|
||||
@@ -343,7 +485,7 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
|
||||
case MODEKEYCOPY_HISTORYTOP:
|
||||
data->cx = 0;
|
||||
data->cy = 0;
|
||||
data->oy = screen_hsize(&wp->base);
|
||||
data->oy = screen_hsize(data->backing);
|
||||
window_copy_update_selection(wp);
|
||||
window_copy_redraw_screen(wp);
|
||||
break;
|
||||
@@ -363,9 +505,10 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
|
||||
window_copy_redraw_screen(wp);
|
||||
break;
|
||||
case MODEKEYCOPY_COPYSELECTION:
|
||||
if (c != NULL && c->session != NULL) {
|
||||
window_copy_copy_selection(wp, c);
|
||||
if (sess != NULL) {
|
||||
window_copy_copy_selection(wp, sess);
|
||||
window_pane_reset_mode(wp);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case MODEKEYCOPY_STARTOFLINE:
|
||||
@@ -407,6 +550,36 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_previous_word(wp, word_separators);
|
||||
break;
|
||||
case MODEKEYCOPY_JUMP:
|
||||
data->inputtype = WINDOW_COPY_JUMPFORWARD;
|
||||
data->inputprompt = "Jump Forward";
|
||||
*data->inputstr = '\0';
|
||||
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
|
||||
return; /* skip numprefix reset */
|
||||
case MODEKEYCOPY_JUMPAGAIN:
|
||||
if (data->jumptype == WINDOW_COPY_JUMPFORWARD) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump(wp);
|
||||
} else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump_back(wp);
|
||||
}
|
||||
break;
|
||||
case MODEKEYCOPY_JUMPREVERSE:
|
||||
if (data->jumptype == WINDOW_COPY_JUMPFORWARD) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump_back(wp);
|
||||
} else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump(wp);
|
||||
}
|
||||
break;
|
||||
case MODEKEYCOPY_JUMPBACK:
|
||||
data->inputtype = WINDOW_COPY_JUMPBACK;
|
||||
data->inputprompt = "Jump Back";
|
||||
*data->inputstr = '\0';
|
||||
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
|
||||
return; /* skip numprefix reset */
|
||||
case MODEKEYCOPY_SEARCHUP:
|
||||
data->inputtype = WINDOW_COPY_SEARCHUP;
|
||||
data->inputprompt = "Search Up";
|
||||
@@ -420,6 +593,8 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
|
||||
switch (data->searchtype) {
|
||||
case WINDOW_COPY_OFF:
|
||||
case WINDOW_COPY_GOTOLINE:
|
||||
case WINDOW_COPY_JUMPFORWARD:
|
||||
case WINDOW_COPY_JUMPBACK:
|
||||
case WINDOW_COPY_NUMERICPREFIX:
|
||||
break;
|
||||
case WINDOW_COPY_SEARCHUP:
|
||||
@@ -456,7 +631,7 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
|
||||
*data->inputstr = '\0';
|
||||
goto input_on;
|
||||
case MODEKEYCOPY_STARTNUMBERPREFIX:
|
||||
key &= 0xff;
|
||||
key &= KEYC_MASK_KEY;
|
||||
if (key >= '0' && key <= '9') {
|
||||
data->inputtype = WINDOW_COPY_NUMERICPREFIX;
|
||||
data->numprefix = 0;
|
||||
@@ -524,6 +699,8 @@ window_copy_key_input(struct window_pane *wp, int key)
|
||||
|
||||
switch (data->inputtype) {
|
||||
case WINDOW_COPY_OFF:
|
||||
case WINDOW_COPY_JUMPFORWARD:
|
||||
case WINDOW_COPY_JUMPBACK:
|
||||
case WINDOW_COPY_NUMERICPREFIX:
|
||||
break;
|
||||
case WINDOW_COPY_SEARCHUP:
|
||||
@@ -568,7 +745,7 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key)
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *s = &data->screen;
|
||||
|
||||
key &= 0xff;
|
||||
key &= KEYC_MASK_KEY;
|
||||
if (key < '0' || key > '9')
|
||||
return 1;
|
||||
|
||||
@@ -583,29 +760,63 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key)
|
||||
/* ARGSUSED */
|
||||
void
|
||||
window_copy_mouse(
|
||||
struct window_pane *wp, unused struct client *c, struct mouse_event *m)
|
||||
struct window_pane *wp, unused struct session *sess, struct mouse_event *m)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *s = &data->screen;
|
||||
u_int i;
|
||||
|
||||
if ((m->b & 3) == 3)
|
||||
return;
|
||||
if (m->x >= screen_size_x(s))
|
||||
return;
|
||||
if (m->y >= screen_size_y(s))
|
||||
return;
|
||||
|
||||
window_copy_update_cursor(wp, m->x, m->y);
|
||||
if (window_copy_update_selection(wp))
|
||||
/* If mouse wheel (buttons 4 and 5), scroll. */
|
||||
if ((m->b & MOUSE_45)) {
|
||||
if ((m->b & MOUSE_BUTTON) == MOUSE_1) {
|
||||
for (i = 0; i < 5; i++)
|
||||
window_copy_cursor_up(wp, 0);
|
||||
} else if ((m->b & MOUSE_BUTTON) == MOUSE_2) {
|
||||
for (i = 0; i < 5; i++)
|
||||
window_copy_cursor_down(wp, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If already reading motion, move the cursor while buttons are still
|
||||
* pressed, or stop the selection on their release.
|
||||
*/
|
||||
if (s->mode & MODE_MOUSEMOTION) {
|
||||
if ((m->b & MOUSE_BUTTON) != MOUSE_UP) {
|
||||
window_copy_update_cursor(wp, m->x, m->y);
|
||||
if (window_copy_update_selection(wp))
|
||||
window_copy_redraw_screen(wp);
|
||||
} else {
|
||||
s->mode &= ~MODE_MOUSEMOTION;
|
||||
if (sess != NULL) {
|
||||
window_copy_copy_selection(wp, sess);
|
||||
window_pane_reset_mode(wp);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise i other buttons pressed, start selection and motion. */
|
||||
if ((m->b & MOUSE_BUTTON) != MOUSE_UP) {
|
||||
s->mode |= MODE_MOUSEMOTION;
|
||||
|
||||
window_copy_update_cursor(wp, m->x, m->y);
|
||||
window_copy_start_selection(wp);
|
||||
window_copy_redraw_screen(wp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *s = &wp->base;
|
||||
struct grid *gd = s->grid;
|
||||
struct grid *gd = data->backing->grid;
|
||||
u_int offset, gap;
|
||||
|
||||
data->cx = px;
|
||||
@@ -700,7 +911,7 @@ void
|
||||
window_copy_search_up(struct window_pane *wp, const char *searchstr)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *s = &wp->base, ss;
|
||||
struct screen *s = data->backing, ss;
|
||||
struct screen_write_ctx ctx;
|
||||
struct grid *gd = s->grid, *sgd;
|
||||
struct grid_cell gc;
|
||||
@@ -757,7 +968,7 @@ void
|
||||
window_copy_search_down(struct window_pane *wp, const char *searchstr)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *s = &wp->base, ss;
|
||||
struct screen *s = data->backing, ss;
|
||||
struct screen_write_ctx ctx;
|
||||
struct grid *gd = s->grid, *sgd;
|
||||
struct grid_cell gc;
|
||||
@@ -817,7 +1028,7 @@ window_copy_goto_line(struct window_pane *wp, const char *linestr)
|
||||
const char *errstr;
|
||||
u_int lineno;
|
||||
|
||||
lineno = strtonum(linestr, 0, screen_hsize(&wp->base), &errstr);
|
||||
lineno = strtonum(linestr, 0, screen_hsize(data->backing), &errstr);
|
||||
if (errstr != NULL)
|
||||
return;
|
||||
|
||||
@@ -845,7 +1056,9 @@ window_copy_write_line(
|
||||
last = screen_size_y(s) - 1;
|
||||
if (py == 0) {
|
||||
size = xsnprintf(hdr, sizeof hdr,
|
||||
"[%u/%u]", data->oy, screen_hsize(&wp->base));
|
||||
"[%u/%u]", data->oy, screen_hsize(data->backing));
|
||||
if (size > screen_size_x(s))
|
||||
size = screen_size_x(s);
|
||||
screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
|
||||
screen_write_puts(ctx, &gc, "%s", hdr);
|
||||
} else if (py == last && data->inputtype != WINDOW_COPY_OFF) {
|
||||
@@ -862,8 +1075,9 @@ window_copy_write_line(
|
||||
size = 0;
|
||||
|
||||
screen_write_cursormove(ctx, xoff, py);
|
||||
screen_write_copy(ctx, &wp->base, xoff, (screen_hsize(&wp->base) -
|
||||
data->oy) + py, screen_size_x(s) - size, 1);
|
||||
screen_write_copy(ctx, data->backing, xoff,
|
||||
(screen_hsize(data->backing) - data->oy) + py,
|
||||
screen_size_x(s) - size, 1);
|
||||
|
||||
if (py == data->cy && data->cx == screen_size_x(s)) {
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
@@ -932,7 +1146,7 @@ window_copy_start_selection(struct window_pane *wp)
|
||||
struct screen *s = &data->screen;
|
||||
|
||||
data->selx = data->cx;
|
||||
data->sely = screen_hsize(&wp->base) + data->cy - data->oy;
|
||||
data->sely = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
|
||||
s->sel.flag = 1;
|
||||
window_copy_update_selection(wp);
|
||||
@@ -957,7 +1171,7 @@ window_copy_update_selection(struct window_pane *wp)
|
||||
gc.attr |= options_get_number(oo, "mode-attr");
|
||||
|
||||
/* Find top of screen. */
|
||||
ty = screen_hsize(&wp->base) - data->oy;
|
||||
ty = screen_hsize(data->backing) - data->oy;
|
||||
|
||||
/* Adjust the selection. */
|
||||
sx = data->selx;
|
||||
@@ -994,7 +1208,7 @@ window_copy_update_selection(struct window_pane *wp)
|
||||
}
|
||||
|
||||
void
|
||||
window_copy_copy_selection(struct window_pane *wp, struct client *c)
|
||||
window_copy_copy_selection(struct window_pane *wp, struct session *sess)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *s = &data->screen;
|
||||
@@ -1018,7 +1232,7 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c)
|
||||
|
||||
/* Find start and end. */
|
||||
xx = data->cx;
|
||||
yy = screen_hsize(&wp->base) + data->cy - data->oy;
|
||||
yy = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
|
||||
sx = xx; sy = yy;
|
||||
ex = data->selx; ey = data->sely;
|
||||
@@ -1053,8 +1267,8 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c)
|
||||
/* Cursor is on the left. */
|
||||
lastex = data->selx + 1;
|
||||
restex = data->selx + 1;
|
||||
firstsx = data->cx + 1;
|
||||
restsx = data->cx + 1;
|
||||
firstsx = data->cx;
|
||||
restsx = data->cx;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
@@ -1089,20 +1303,21 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c)
|
||||
off--; /* remove final \n */
|
||||
|
||||
/* Add the buffer to the stack. */
|
||||
limit = options_get_number(&c->session->options, "buffer-limit");
|
||||
paste_add(&c->session->buffers, buf, off, limit);
|
||||
limit = options_get_number(&sess->options, "buffer-limit");
|
||||
paste_add(&sess->buffers, buf, off, limit);
|
||||
}
|
||||
|
||||
void
|
||||
window_copy_copy_line(struct window_pane *wp,
|
||||
char **buf, size_t *off, u_int sy, u_int sx, u_int ex)
|
||||
{
|
||||
struct grid *gd = wp->base.grid;
|
||||
const struct grid_cell *gc;
|
||||
const struct grid_utf8 *gu;
|
||||
struct grid_line *gl;
|
||||
u_int i, xx, wrapped = 0;
|
||||
size_t size;
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct grid *gd = data->backing->grid;
|
||||
const struct grid_cell *gc;
|
||||
const struct grid_utf8 *gu;
|
||||
struct grid_line *gl;
|
||||
u_int i, xx, wrapped = 0;
|
||||
size_t size;
|
||||
|
||||
if (sx > ex)
|
||||
return;
|
||||
@@ -1157,7 +1372,7 @@ window_copy_clear_selection(struct window_pane *wp)
|
||||
|
||||
screen_clear_selection(&data->screen);
|
||||
|
||||
py = screen_hsize(&wp->base) + data->cy - data->oy;
|
||||
py = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
px = window_copy_find_length(wp, py);
|
||||
if (data->cx > px)
|
||||
window_copy_update_cursor(wp, px, data->cy);
|
||||
@@ -1166,9 +1381,10 @@ window_copy_clear_selection(struct window_pane *wp)
|
||||
int
|
||||
window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set)
|
||||
{
|
||||
const struct grid_cell *gc;
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
const struct grid_cell *gc;
|
||||
|
||||
gc = grid_peek_cell(wp->base.grid, px, py);
|
||||
gc = grid_peek_cell(data->backing->grid, px, py);
|
||||
if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8))
|
||||
return (0);
|
||||
if (gc->data == 0x00 || gc->data == 0x7f)
|
||||
@@ -1179,8 +1395,10 @@ window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set)
|
||||
u_int
|
||||
window_copy_find_length(struct window_pane *wp, u_int py)
|
||||
{
|
||||
const struct grid_cell *gc;
|
||||
u_int px;
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *s = data->backing;
|
||||
const struct grid_cell *gc;
|
||||
u_int px;
|
||||
|
||||
/*
|
||||
* If the pane has been resized, its grid can contain old overlong
|
||||
@@ -1188,11 +1406,11 @@ window_copy_find_length(struct window_pane *wp, u_int py)
|
||||
* width of the grid, and screen_write_copy treats them as spaces, so
|
||||
* ignore them here too.
|
||||
*/
|
||||
px = wp->base.grid->linedata[py].cellsize;
|
||||
if (px > screen_size_x(&wp->base))
|
||||
px = screen_size_x(&wp->base);
|
||||
px = s->grid->linedata[py].cellsize;
|
||||
if (px > screen_size_x(s))
|
||||
px = screen_size_x(s);
|
||||
while (px > 0) {
|
||||
gc = grid_peek_cell(wp->base.grid, px - 1, py);
|
||||
gc = grid_peek_cell(s->grid, px - 1, py);
|
||||
if (gc->flags & GRID_FLAG_UTF8)
|
||||
break;
|
||||
if (gc->data != ' ')
|
||||
@@ -1206,7 +1424,17 @@ void
|
||||
window_copy_cursor_start_of_line(struct window_pane *wp)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *back_s = data->backing;
|
||||
struct grid *gd = back_s->grid;
|
||||
u_int py;
|
||||
|
||||
if (data->cx == 0) {
|
||||
py = screen_hsize(back_s) + data->cy - data->oy;
|
||||
while (py > 0 && gd->linedata[py-1].flags & GRID_LINE_WRAPPED) {
|
||||
window_copy_cursor_up(wp, 0);
|
||||
py = screen_hsize(back_s) + data->cy - data->oy;
|
||||
}
|
||||
}
|
||||
window_copy_update_cursor(wp, 0, data->cy);
|
||||
if (window_copy_update_selection(wp))
|
||||
window_copy_redraw_lines(wp, data->cy, 1);
|
||||
@@ -1220,11 +1448,11 @@ window_copy_cursor_back_to_indentation(struct window_pane *wp)
|
||||
const struct grid_cell *gc;
|
||||
|
||||
px = 0;
|
||||
py = screen_hsize(&wp->base) + data->cy - data->oy;
|
||||
py = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
xx = window_copy_find_length(wp, py);
|
||||
|
||||
while (px < xx) {
|
||||
gc = grid_peek_cell(wp->base.grid, px, py);
|
||||
gc = grid_peek_cell(data->backing->grid, px, py);
|
||||
if (gc->flags & GRID_FLAG_UTF8)
|
||||
break;
|
||||
if (gc->data != ' ')
|
||||
@@ -1241,21 +1469,22 @@ void
|
||||
window_copy_cursor_end_of_line(struct window_pane *wp)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *base_s = &wp->base;
|
||||
struct grid *gd = base_s->grid;
|
||||
struct screen *back_s = data->backing;
|
||||
struct grid *gd = back_s->grid;
|
||||
u_int px, py;
|
||||
|
||||
py = screen_hsize(base_s) + data->cy - data->oy;
|
||||
py = screen_hsize(back_s) + data->cy - data->oy;
|
||||
px = window_copy_find_length(wp, py);
|
||||
|
||||
if (data->cx == px) {
|
||||
if (data->screen.sel.flag && data->rectflag)
|
||||
px = screen_size_x(&wp->base);
|
||||
px = screen_size_x(back_s);
|
||||
if (gd->linedata[py].flags & GRID_LINE_WRAPPED) {
|
||||
while (py < gd->sy + gd->hsize &&
|
||||
gd->linedata[py].flags & GRID_LINE_WRAPPED) {
|
||||
window_copy_cursor_down(wp, 0);
|
||||
py = screen_hsize(base_s) + data->cy - data->oy;
|
||||
py = screen_hsize(back_s)
|
||||
+ data->cy - data->oy;
|
||||
}
|
||||
px = window_copy_find_length(wp, py);
|
||||
}
|
||||
@@ -1290,7 +1519,7 @@ window_copy_cursor_right(struct window_pane *wp)
|
||||
if (data->screen.sel.flag && data->rectflag)
|
||||
px = screen_size_x(&data->screen);
|
||||
else {
|
||||
py = screen_hsize(&wp->base) + data->cy - data->oy;
|
||||
py = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
px = window_copy_find_length(wp, py);
|
||||
}
|
||||
|
||||
@@ -1311,7 +1540,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
|
||||
struct screen *s = &data->screen;
|
||||
u_int ox, oy, px, py;
|
||||
|
||||
oy = screen_hsize(&wp->base) + data->cy - data->oy;
|
||||
oy = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
ox = window_copy_find_length(wp, oy);
|
||||
if (ox != 0) {
|
||||
data->lastcx = data->cx;
|
||||
@@ -1338,7 +1567,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
|
||||
}
|
||||
|
||||
if (!data->screen.sel.flag || !data->rectflag) {
|
||||
py = screen_hsize(&wp->base) + data->cy - data->oy;
|
||||
py = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
px = window_copy_find_length(wp, py);
|
||||
if ((data->cx >= data->lastsx && data->cx != px) ||
|
||||
data->cx > px)
|
||||
@@ -1353,7 +1582,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
|
||||
struct screen *s = &data->screen;
|
||||
u_int ox, oy, px, py;
|
||||
|
||||
oy = screen_hsize(&wp->base) + data->cy - data->oy;
|
||||
oy = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
ox = window_copy_find_length(wp, oy);
|
||||
if (ox != 0) {
|
||||
data->lastcx = data->cx;
|
||||
@@ -1372,7 +1601,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
|
||||
}
|
||||
|
||||
if (!data->screen.sel.flag || !data->rectflag) {
|
||||
py = screen_hsize(&wp->base) + data->cy - data->oy;
|
||||
py = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
px = window_copy_find_length(wp, py);
|
||||
if ((data->cx >= data->lastsx && data->cx != px) ||
|
||||
data->cx > px)
|
||||
@@ -1380,18 +1609,74 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
window_copy_cursor_jump(struct window_pane *wp)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *back_s = data->backing;
|
||||
const struct grid_cell *gc;
|
||||
uint px, py, xx;
|
||||
|
||||
px = data->cx + 1;
|
||||
py = screen_hsize(back_s) + data->cy - data->oy;
|
||||
xx = window_copy_find_length(wp, py);
|
||||
|
||||
while (px < xx) {
|
||||
gc = grid_peek_cell(back_s->grid, px, py);
|
||||
if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
|
||||
&& gc->data == data->jumpchar) {
|
||||
|
||||
window_copy_update_cursor(wp, px, data->cy);
|
||||
if (window_copy_update_selection(wp))
|
||||
window_copy_redraw_lines(wp, data->cy, 1);
|
||||
return;
|
||||
}
|
||||
px++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
window_copy_cursor_jump_back(struct window_pane *wp)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *back_s = data->backing;
|
||||
const struct grid_cell *gc;
|
||||
uint px, py;
|
||||
|
||||
px = data->cx;
|
||||
py = screen_hsize(back_s) + data->cy - data->oy;
|
||||
|
||||
if (px > 0)
|
||||
px--;
|
||||
|
||||
for (;;) {
|
||||
gc = grid_peek_cell(back_s->grid, px, py);
|
||||
if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
|
||||
&& gc->data == data->jumpchar) {
|
||||
|
||||
window_copy_update_cursor(wp, px, data->cy);
|
||||
if (window_copy_update_selection(wp))
|
||||
window_copy_redraw_lines(wp, data->cy, 1);
|
||||
return;
|
||||
}
|
||||
if (px == 0)
|
||||
break;
|
||||
px--;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *base_s = &wp->base;
|
||||
struct screen *back_s = data->backing;
|
||||
u_int px, py, xx, yy;
|
||||
int expected = 0;
|
||||
|
||||
px = data->cx;
|
||||
py = screen_hsize(base_s) + data->cy - data->oy;
|
||||
py = screen_hsize(back_s) + data->cy - data->oy;
|
||||
xx = window_copy_find_length(wp, py);
|
||||
yy = screen_hsize(base_s) + screen_size_y(base_s) - 1;
|
||||
yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
|
||||
|
||||
/*
|
||||
* First skip past any nonword characters and then any word characters.
|
||||
@@ -1409,7 +1694,7 @@ window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
|
||||
window_copy_cursor_down(wp, 0);
|
||||
px = 0;
|
||||
|
||||
py = screen_hsize(base_s) + data->cy - data->oy;
|
||||
py = screen_hsize(back_s) + data->cy - data->oy;
|
||||
xx = window_copy_find_length(wp, py);
|
||||
} else
|
||||
px++;
|
||||
@@ -1426,14 +1711,14 @@ void
|
||||
window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *base_s = &wp->base;
|
||||
struct screen *back_s = data->backing;
|
||||
u_int px, py, xx, yy;
|
||||
int expected = 1;
|
||||
|
||||
px = data->cx;
|
||||
py = screen_hsize(base_s) + data->cy - data->oy;
|
||||
py = screen_hsize(back_s) + data->cy - data->oy;
|
||||
xx = window_copy_find_length(wp, py);
|
||||
yy = screen_hsize(base_s) + screen_size_y(base_s) - 1;
|
||||
yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
|
||||
|
||||
/*
|
||||
* First skip past any word characters, then any nonword characters.
|
||||
@@ -1451,7 +1736,7 @@ window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators)
|
||||
window_copy_cursor_down(wp, 0);
|
||||
px = 0;
|
||||
|
||||
py = screen_hsize(base_s) + data->cy - data->oy;
|
||||
py = screen_hsize(back_s) + data->cy - data->oy;
|
||||
xx = window_copy_find_length(wp, py);
|
||||
} else
|
||||
px++;
|
||||
@@ -1472,7 +1757,7 @@ window_copy_cursor_previous_word(struct window_pane *wp, const char *separators)
|
||||
u_int px, py;
|
||||
|
||||
px = data->cx;
|
||||
py = screen_hsize(&wp->base) + data->cy - data->oy;
|
||||
py = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
|
||||
/* Move back to the previous word character. */
|
||||
for (;;) {
|
||||
@@ -1482,12 +1767,12 @@ window_copy_cursor_previous_word(struct window_pane *wp, const char *separators)
|
||||
break;
|
||||
} else {
|
||||
if (data->cy == 0 &&
|
||||
(screen_hsize(&wp->base) == 0 ||
|
||||
data->oy >= screen_hsize(&wp->base) - 1))
|
||||
(screen_hsize(data->backing) == 0 ||
|
||||
data->oy >= screen_hsize(data->backing) - 1))
|
||||
goto out;
|
||||
window_copy_cursor_up(wp, 0);
|
||||
|
||||
py = screen_hsize(&wp->base) + data->cy - data->oy;
|
||||
py = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
px = window_copy_find_length(wp, py);
|
||||
}
|
||||
}
|
||||
@@ -1540,11 +1825,11 @@ window_copy_scroll_down(struct window_pane *wp, u_int ny)
|
||||
struct screen *s = &data->screen;
|
||||
struct screen_write_ctx ctx;
|
||||
|
||||
if (ny > screen_hsize(&wp->base))
|
||||
if (ny > screen_hsize(data->backing))
|
||||
return;
|
||||
|
||||
if (data->oy > screen_hsize(&wp->base) - ny)
|
||||
ny = screen_hsize(&wp->base) - data->oy;
|
||||
if (data->oy > screen_hsize(data->backing) - ny)
|
||||
ny = screen_hsize(data->backing) - data->oy;
|
||||
if (ny == 0)
|
||||
return;
|
||||
data->oy += ny;
|
||||
@@ -1571,7 +1856,7 @@ window_copy_rectangle_toggle(struct window_pane *wp)
|
||||
|
||||
data->rectflag = !data->rectflag;
|
||||
|
||||
py = screen_hsize(&wp->base) + data->cy - data->oy;
|
||||
py = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
px = window_copy_find_length(wp, py);
|
||||
if (data->cx > px)
|
||||
window_copy_update_cursor(wp, px, data->cy);
|
||||
|
||||
260
window-more.c
260
window-more.c
@@ -1,260 +0,0 @@
|
||||
/* $Id: window-more.c,v 1.42 2010-02-08 18:10:07 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF 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 <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
struct screen *window_more_init(struct window_pane *);
|
||||
void window_more_free(struct window_pane *);
|
||||
void window_more_resize(struct window_pane *, u_int, u_int);
|
||||
void window_more_key(struct window_pane *, struct client *, int);
|
||||
|
||||
void window_more_redraw_screen(struct window_pane *);
|
||||
void window_more_write_line(
|
||||
struct window_pane *, struct screen_write_ctx *, u_int);
|
||||
|
||||
void window_more_scroll_up(struct window_pane *);
|
||||
void window_more_scroll_down(struct window_pane *);
|
||||
|
||||
const struct window_mode window_more_mode = {
|
||||
window_more_init,
|
||||
window_more_free,
|
||||
window_more_resize,
|
||||
window_more_key,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
struct window_more_mode_data {
|
||||
struct screen screen;
|
||||
|
||||
struct mode_key_data mdata;
|
||||
|
||||
ARRAY_DECL(, char *) list;
|
||||
u_int top;
|
||||
};
|
||||
|
||||
void
|
||||
window_more_add(struct window_pane *wp, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
window_more_vadd(wp, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
window_more_vadd(struct window_pane *wp, const char *fmt, va_list ap)
|
||||
{
|
||||
struct window_more_mode_data *data = wp->modedata;
|
||||
struct screen *s = &data->screen;
|
||||
struct screen_write_ctx ctx;
|
||||
char *msg;
|
||||
u_int size;
|
||||
|
||||
xvasprintf(&msg, fmt, ap);
|
||||
ARRAY_ADD(&data->list, msg);
|
||||
|
||||
screen_write_start(&ctx, wp, NULL);
|
||||
size = ARRAY_LENGTH(&data->list) - 1;
|
||||
if (size >= data->top && size <= data->top + screen_size_y(s) - 1) {
|
||||
window_more_write_line(wp, &ctx, size - data->top);
|
||||
if (size != data->top)
|
||||
window_more_write_line(wp, &ctx, 0);
|
||||
} else
|
||||
window_more_write_line(wp, &ctx, 0);
|
||||
screen_write_stop(&ctx);
|
||||
}
|
||||
|
||||
struct screen *
|
||||
window_more_init(struct window_pane *wp)
|
||||
{
|
||||
struct window_more_mode_data *data;
|
||||
struct screen *s;
|
||||
int keys;
|
||||
|
||||
wp->modedata = data = xmalloc(sizeof *data);
|
||||
ARRAY_INIT(&data->list);
|
||||
data->top = 0;
|
||||
|
||||
s = &data->screen;
|
||||
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
|
||||
s->mode &= ~MODE_CURSOR;
|
||||
|
||||
keys = options_get_number(&wp->window->options, "mode-keys");
|
||||
if (keys == MODEKEY_EMACS)
|
||||
mode_key_init(&data->mdata, &mode_key_tree_emacs_choice);
|
||||
else
|
||||
mode_key_init(&data->mdata, &mode_key_tree_vi_choice);
|
||||
|
||||
return (s);
|
||||
}
|
||||
|
||||
void
|
||||
window_more_free(struct window_pane *wp)
|
||||
{
|
||||
struct window_more_mode_data *data = wp->modedata;
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&data->list); i++)
|
||||
xfree(ARRAY_ITEM(&data->list, i));
|
||||
ARRAY_FREE(&data->list);
|
||||
|
||||
screen_free(&data->screen);
|
||||
xfree(data);
|
||||
}
|
||||
|
||||
void
|
||||
window_more_resize(struct window_pane *wp, u_int sx, u_int sy)
|
||||
{
|
||||
struct window_more_mode_data *data = wp->modedata;
|
||||
struct screen *s = &data->screen;
|
||||
|
||||
screen_resize(s, sx, sy);
|
||||
window_more_redraw_screen(wp);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
window_more_key(struct window_pane *wp, unused struct client *c, int key)
|
||||
{
|
||||
struct window_more_mode_data *data = wp->modedata;
|
||||
struct screen *s = &data->screen;
|
||||
|
||||
switch (mode_key_lookup(&data->mdata, key)) {
|
||||
case MODEKEYCHOICE_CANCEL:
|
||||
window_pane_reset_mode(wp);
|
||||
break;
|
||||
case MODEKEYCHOICE_UP:
|
||||
case MODEKEYCHOICE_SCROLLUP:
|
||||
window_more_scroll_up(wp);
|
||||
break;
|
||||
case MODEKEYCHOICE_DOWN:
|
||||
case MODEKEYCHOICE_SCROLLDOWN:
|
||||
window_more_scroll_down(wp);
|
||||
break;
|
||||
case MODEKEYCHOICE_PAGEUP:
|
||||
if (data->top < screen_size_y(s))
|
||||
data->top = 0;
|
||||
else
|
||||
data->top -= screen_size_y(s);
|
||||
window_more_redraw_screen(wp);
|
||||
break;
|
||||
case MODEKEYCHOICE_PAGEDOWN:
|
||||
if (data->top + screen_size_y(s) > ARRAY_LENGTH(&data->list))
|
||||
data->top = ARRAY_LENGTH(&data->list);
|
||||
else
|
||||
data->top += screen_size_y(s);
|
||||
window_more_redraw_screen(wp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
window_more_write_line(
|
||||
struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
|
||||
{
|
||||
struct window_more_mode_data *data = wp->modedata;
|
||||
struct screen *s = &data->screen;
|
||||
struct options *oo = &wp->window->options;
|
||||
struct grid_cell gc;
|
||||
char *msg, hdr[32];
|
||||
size_t size;
|
||||
int utf8flag;
|
||||
|
||||
utf8flag = options_get_number(&wp->window->options, "utf8");
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
|
||||
if (py == 0) {
|
||||
size = xsnprintf(hdr, sizeof hdr,
|
||||
"[%u/%u]", data->top, ARRAY_LENGTH(&data->list));
|
||||
screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
|
||||
colour_set_fg(&gc, options_get_number(oo, "mode-fg"));
|
||||
colour_set_bg(&gc, options_get_number(oo, "mode-bg"));
|
||||
gc.attr |= options_get_number(oo, "mode-attr");
|
||||
screen_write_puts(ctx, &gc, "%s", hdr);
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
} else
|
||||
size = 0;
|
||||
|
||||
screen_write_cursormove(ctx, 0, py);
|
||||
if (data->top + py < ARRAY_LENGTH(&data->list)) {
|
||||
msg = ARRAY_ITEM(&data->list, data->top + py);
|
||||
screen_write_nputs(
|
||||
ctx, screen_size_x(s) - size, &gc, utf8flag, "%s", msg);
|
||||
}
|
||||
while (s->cx < screen_size_x(s) - size)
|
||||
screen_write_putc(ctx, &gc, ' ');
|
||||
}
|
||||
|
||||
void
|
||||
window_more_redraw_screen(struct window_pane *wp)
|
||||
{
|
||||
struct window_more_mode_data *data = wp->modedata;
|
||||
struct screen *s = &data->screen;
|
||||
struct screen_write_ctx ctx;
|
||||
u_int i;
|
||||
|
||||
screen_write_start(&ctx, wp, NULL);
|
||||
for (i = 0; i < screen_size_y(s); i++)
|
||||
window_more_write_line(wp, &ctx, i);
|
||||
screen_write_stop(&ctx);
|
||||
}
|
||||
|
||||
void
|
||||
window_more_scroll_up(struct window_pane *wp)
|
||||
{
|
||||
struct window_more_mode_data *data = wp->modedata;
|
||||
struct screen_write_ctx ctx;
|
||||
|
||||
if (data->top == 0)
|
||||
return;
|
||||
data->top--;
|
||||
|
||||
screen_write_start(&ctx, wp, NULL);
|
||||
screen_write_cursormove(&ctx, 0, 0);
|
||||
screen_write_insertline(&ctx, 1);
|
||||
window_more_write_line(wp, &ctx, 0);
|
||||
window_more_write_line(wp, &ctx, 1);
|
||||
screen_write_stop(&ctx);
|
||||
}
|
||||
|
||||
void
|
||||
window_more_scroll_down(struct window_pane *wp)
|
||||
{
|
||||
struct window_more_mode_data *data = wp->modedata;
|
||||
struct screen *s = &data->screen;
|
||||
struct screen_write_ctx ctx;
|
||||
|
||||
if (data->top >= ARRAY_LENGTH(&data->list))
|
||||
return;
|
||||
data->top++;
|
||||
|
||||
screen_write_start(&ctx, wp, NULL);
|
||||
screen_write_cursormove(&ctx, 0, 0);
|
||||
screen_write_deleteline(&ctx, 1);
|
||||
window_more_write_line(wp, &ctx, screen_size_y(s) - 1);
|
||||
window_more_write_line(wp, &ctx, 0);
|
||||
screen_write_stop(&ctx);
|
||||
}
|
||||
335
window.c
335
window.c
@@ -1,4 +1,4 @@
|
||||
/* $Id: window.c,v 1.126 2010-02-08 18:10:07 tcunha Exp $ */
|
||||
/* $Id: window.c,v 1.142 2010-12-06 22:52:21 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <fnmatch.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
@@ -170,6 +169,28 @@ winlink_previous(struct winlink *wl)
|
||||
return (RB_PREV(winlinks, wwl, wl));
|
||||
}
|
||||
|
||||
struct winlink *
|
||||
winlink_next_by_number(struct winlink *wl, struct session *s, int n)
|
||||
{
|
||||
for (; n > 0; n--) {
|
||||
if ((wl = RB_NEXT(winlinks, wwl, wl)) == NULL)
|
||||
wl = RB_MIN(winlinks, &s->windows);
|
||||
}
|
||||
|
||||
return (wl);
|
||||
}
|
||||
|
||||
struct winlink *
|
||||
winlink_previous_by_number(struct winlink *wl, struct session *s, int n)
|
||||
{
|
||||
for (; n > 0; n--) {
|
||||
if ((wl = RB_PREV(winlinks, wwl, wl)) == NULL)
|
||||
wl = RB_MAX(winlinks, &s->windows);
|
||||
}
|
||||
|
||||
return (wl);
|
||||
}
|
||||
|
||||
void
|
||||
winlink_stack_push(struct winlink_stack *stack, struct winlink *wl)
|
||||
{
|
||||
@@ -301,6 +322,9 @@ window_resize(struct window *w, u_int sx, u_int sy)
|
||||
void
|
||||
window_set_active_pane(struct window *w, struct window_pane *wp)
|
||||
{
|
||||
if (wp == w->active)
|
||||
return;
|
||||
w->last = w->active;
|
||||
w->active = wp;
|
||||
while (!window_pane_visible(w->active)) {
|
||||
w->active = TAILQ_PREV(w->active, window_panes, entry);
|
||||
@@ -317,7 +341,7 @@ window_set_active_at(struct window *w, u_int x, u_int y)
|
||||
struct window_pane *wp;
|
||||
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (!window_pane_visible(wp))
|
||||
if (wp == w->active || !window_pane_visible(wp))
|
||||
continue;
|
||||
if (x < wp->xoff || x >= wp->xoff + wp->sx)
|
||||
continue;
|
||||
@@ -344,9 +368,16 @@ window_add_pane(struct window *w, u_int hlimit)
|
||||
void
|
||||
window_remove_pane(struct window *w, struct window_pane *wp)
|
||||
{
|
||||
w->active = TAILQ_PREV(wp, window_panes, entry);
|
||||
if (w->active == NULL)
|
||||
w->active = TAILQ_NEXT(wp, entry);
|
||||
if (wp == w->active) {
|
||||
w->active = w->last;
|
||||
w->last = NULL;
|
||||
if (w->active == NULL) {
|
||||
w->active = TAILQ_PREV(wp, window_panes, entry);
|
||||
if (w->active == NULL)
|
||||
w->active = TAILQ_NEXT(wp, entry);
|
||||
}
|
||||
} else if (wp == w->last)
|
||||
w->last = NULL;
|
||||
|
||||
TAILQ_REMOVE(&w->panes, wp, entry);
|
||||
window_pane_destroy(wp);
|
||||
@@ -367,6 +398,29 @@ window_pane_at_index(struct window *w, u_int idx)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct window_pane *
|
||||
window_pane_next_by_number(struct window *w, struct window_pane *wp, u_int n)
|
||||
{
|
||||
for (; n > 0; n--) {
|
||||
if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
|
||||
wp = TAILQ_FIRST(&w->panes);
|
||||
}
|
||||
|
||||
return (wp);
|
||||
}
|
||||
|
||||
struct window_pane *
|
||||
window_pane_previous_by_number(struct window *w, struct window_pane *wp,
|
||||
u_int n)
|
||||
{
|
||||
for (; n > 0; n--) {
|
||||
if ((wp = TAILQ_PREV(wp, window_panes, entry)) == NULL)
|
||||
wp = TAILQ_LAST(&w->panes, window_panes);
|
||||
}
|
||||
|
||||
return (wp);
|
||||
}
|
||||
|
||||
u_int
|
||||
window_pane_index(struct window *w, struct window_pane *wp)
|
||||
{
|
||||
@@ -448,6 +502,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
|
||||
void
|
||||
window_pane_destroy(struct window_pane *wp)
|
||||
{
|
||||
window_pane_reset_mode(wp);
|
||||
|
||||
if (wp->fd != -1) {
|
||||
close(wp->fd);
|
||||
bufferevent_free(wp->event);
|
||||
@@ -455,7 +511,6 @@ window_pane_destroy(struct window_pane *wp)
|
||||
|
||||
input_free(wp);
|
||||
|
||||
window_pane_reset_mode(wp);
|
||||
screen_free(&wp->base);
|
||||
if (wp->saved_grid != NULL)
|
||||
grid_destroy(wp->saved_grid);
|
||||
@@ -478,14 +533,11 @@ int
|
||||
window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
|
||||
const char *cwd, struct environ *env, struct termios *tio, char **cause)
|
||||
{
|
||||
struct winsize ws;
|
||||
int mode;
|
||||
char *argv0, **varp, *var;
|
||||
ARRAY_DECL(, char *) varlist;
|
||||
struct environ_entry *envent;
|
||||
const char *ptr;
|
||||
struct termios tio2;
|
||||
u_int i;
|
||||
struct winsize ws;
|
||||
int mode;
|
||||
char *argv0;
|
||||
const char *ptr;
|
||||
struct termios tio2;
|
||||
|
||||
if (wp->fd != -1) {
|
||||
close(wp->fd);
|
||||
@@ -528,22 +580,11 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
|
||||
if (tcsetattr(STDIN_FILENO, TCSANOW, &tio2) != 0)
|
||||
fatal("tcgetattr failed");
|
||||
|
||||
ARRAY_INIT(&varlist);
|
||||
for (varp = environ; *varp != NULL; varp++) {
|
||||
var = xstrdup(*varp);
|
||||
var[strcspn(var, "=")] = '\0';
|
||||
ARRAY_ADD(&varlist, var);
|
||||
}
|
||||
for (i = 0; i < ARRAY_LENGTH(&varlist); i++) {
|
||||
var = ARRAY_ITEM(&varlist, i);
|
||||
unsetenv(var);
|
||||
}
|
||||
RB_FOREACH(envent, environ, env) {
|
||||
if (envent->value != NULL)
|
||||
setenv(envent->name, envent->value, 1);
|
||||
}
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
|
||||
server_signal_clear();
|
||||
environ_push(env);
|
||||
|
||||
clear_signals(1);
|
||||
log_close();
|
||||
|
||||
if (*wp->cmd != '\0') {
|
||||
@@ -571,8 +612,6 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
|
||||
fatal("fcntl failed");
|
||||
if (fcntl(wp->fd, F_SETFL, mode|O_NONBLOCK) == -1)
|
||||
fatal("fcntl failed");
|
||||
if (fcntl(wp->fd, F_SETFD, FD_CLOEXEC) == -1)
|
||||
fatal("fcntl failed");
|
||||
wp->event = bufferevent_new(wp->fd,
|
||||
window_pane_read_callback, NULL, window_pane_error_callback, wp);
|
||||
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
|
||||
@@ -584,9 +623,27 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
|
||||
void
|
||||
window_pane_read_callback(unused struct bufferevent *bufev, void *data)
|
||||
{
|
||||
struct window_pane *wp = data;
|
||||
struct window_pane *wp = data;
|
||||
char *new_data;
|
||||
size_t new_size;
|
||||
|
||||
window_pane_parse(wp);
|
||||
new_size = EVBUFFER_LENGTH(wp->event->input) - wp->pipe_off;
|
||||
if (wp->pipe_fd != -1 && new_size > 0) {
|
||||
new_data = EVBUFFER_DATA(wp->event->input);
|
||||
bufferevent_write(wp->pipe_event, new_data, new_size);
|
||||
}
|
||||
|
||||
input_parse(wp);
|
||||
|
||||
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
|
||||
|
||||
/*
|
||||
* If we get here, we're not outputting anymore, so set the silence
|
||||
* flag on the window.
|
||||
*/
|
||||
wp->window->flags |= WINDOW_SILENCE;
|
||||
if (gettimeofday(&wp->window->silence_timer, NULL) != 0)
|
||||
fatal("gettimeofday failed.");
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
@@ -630,6 +687,81 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
|
||||
fatal("ioctl failed");
|
||||
}
|
||||
|
||||
/*
|
||||
* Enter alternative screen mode. A copy of the visible screen is saved and the
|
||||
* history is not updated
|
||||
*/
|
||||
void
|
||||
window_pane_alternate_on(struct window_pane *wp, struct grid_cell *gc)
|
||||
{
|
||||
struct screen *s = &wp->base;
|
||||
u_int sx, sy;
|
||||
|
||||
if (wp->saved_grid != NULL)
|
||||
return;
|
||||
if (!options_get_number(&wp->window->options, "alternate-screen"))
|
||||
return;
|
||||
sx = screen_size_x(s);
|
||||
sy = screen_size_y(s);
|
||||
|
||||
wp->saved_grid = grid_create(sx, sy, 0);
|
||||
grid_duplicate_lines(wp->saved_grid, 0, s->grid, screen_hsize(s), sy);
|
||||
wp->saved_cx = s->cx;
|
||||
wp->saved_cy = s->cy;
|
||||
memcpy(&wp->saved_cell, gc, sizeof wp->saved_cell);
|
||||
|
||||
grid_view_clear(s->grid, 0, 0, sx, sy);
|
||||
|
||||
wp->base.grid->flags &= ~GRID_HISTORY;
|
||||
|
||||
wp->flags |= PANE_REDRAW;
|
||||
}
|
||||
|
||||
/* Exit alternate screen mode and restore the copied grid. */
|
||||
void
|
||||
window_pane_alternate_off(struct window_pane *wp, struct grid_cell *gc)
|
||||
{
|
||||
struct screen *s = &wp->base;
|
||||
u_int sx, sy;
|
||||
|
||||
if (wp->saved_grid == NULL)
|
||||
return;
|
||||
if (!options_get_number(&wp->window->options, "alternate-screen"))
|
||||
return;
|
||||
sx = screen_size_x(s);
|
||||
sy = screen_size_y(s);
|
||||
|
||||
/*
|
||||
* If the current size is bigger, temporarily resize to the old size
|
||||
* before copying back.
|
||||
*/
|
||||
if (sy > wp->saved_grid->sy)
|
||||
screen_resize(s, sx, wp->saved_grid->sy);
|
||||
|
||||
/* Restore the grid, cursor position and cell. */
|
||||
grid_duplicate_lines(s->grid, screen_hsize(s), wp->saved_grid, 0, sy);
|
||||
s->cx = wp->saved_cx;
|
||||
if (s->cx > screen_size_x(s) - 1)
|
||||
s->cx = screen_size_x(s) - 1;
|
||||
s->cy = wp->saved_cy;
|
||||
if (s->cy > screen_size_y(s) - 1)
|
||||
s->cy = screen_size_y(s) - 1;
|
||||
memcpy(gc, &wp->saved_cell, sizeof *gc);
|
||||
|
||||
/*
|
||||
* Turn history back on (so resize can use it) and then resize back to
|
||||
* the current size.
|
||||
*/
|
||||
wp->base.grid->flags |= GRID_HISTORY;
|
||||
if (sy > wp->saved_grid->sy)
|
||||
screen_resize(s, sx, sy);
|
||||
|
||||
grid_destroy(wp->saved_grid);
|
||||
wp->saved_grid = NULL;
|
||||
|
||||
wp->flags |= PANE_REDRAW;
|
||||
}
|
||||
|
||||
int
|
||||
window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode)
|
||||
{
|
||||
@@ -659,24 +791,7 @@ window_pane_reset_mode(struct window_pane *wp)
|
||||
}
|
||||
|
||||
void
|
||||
window_pane_parse(struct window_pane *wp)
|
||||
{
|
||||
char *data;
|
||||
size_t new_size;
|
||||
|
||||
new_size = EVBUFFER_LENGTH(wp->event->input) - wp->pipe_off;
|
||||
if (wp->pipe_fd != -1 && new_size > 0) {
|
||||
data = EVBUFFER_DATA(wp->event->input);
|
||||
bufferevent_write(wp->pipe_event, data, new_size);
|
||||
}
|
||||
|
||||
input_parse(wp);
|
||||
|
||||
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
|
||||
}
|
||||
|
||||
void
|
||||
window_pane_key(struct window_pane *wp, struct client *c, int key)
|
||||
window_pane_key(struct window_pane *wp, struct session *sess, int key)
|
||||
{
|
||||
struct window_pane *wp2;
|
||||
|
||||
@@ -685,7 +800,7 @@ window_pane_key(struct window_pane *wp, struct client *c, int key)
|
||||
|
||||
if (wp->mode != NULL) {
|
||||
if (wp->mode->key != NULL)
|
||||
wp->mode->key(wp, c, key);
|
||||
wp->mode->key(wp, sess, key);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -704,7 +819,7 @@ window_pane_key(struct window_pane *wp, struct client *c, int key)
|
||||
|
||||
void
|
||||
window_pane_mouse(
|
||||
struct window_pane *wp, struct client *c, struct mouse_event *m)
|
||||
struct window_pane *wp, struct session *sess, struct mouse_event *m)
|
||||
{
|
||||
if (!window_pane_visible(wp))
|
||||
return;
|
||||
@@ -718,7 +833,7 @@ window_pane_mouse(
|
||||
|
||||
if (wp->mode != NULL) {
|
||||
if (wp->mode->mouse != NULL)
|
||||
wp->mode->mouse(wp, c, m);
|
||||
wp->mode->mouse(wp, sess, m);
|
||||
} else if (wp->fd != -1)
|
||||
input_mouse(wp, m);
|
||||
}
|
||||
@@ -759,3 +874,113 @@ window_pane_search(struct window_pane *wp, const char *searchstr, u_int *lineno)
|
||||
xfree(newsearchstr);
|
||||
return (msg);
|
||||
}
|
||||
|
||||
/* Find the pane directly above another. */
|
||||
struct window_pane *
|
||||
window_pane_find_up(struct window_pane *wp)
|
||||
{
|
||||
struct window_pane *wp2;
|
||||
u_int left, top;
|
||||
|
||||
if (wp == NULL || !window_pane_visible(wp))
|
||||
return (NULL);
|
||||
|
||||
top = wp->yoff;
|
||||
if (top == 0)
|
||||
top = wp->window->sy + 1;
|
||||
left = wp->xoff;
|
||||
|
||||
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
|
||||
if (!window_pane_visible(wp2))
|
||||
continue;
|
||||
if (wp2->yoff + wp2->sy + 1 != top)
|
||||
continue;
|
||||
if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx)
|
||||
return (wp2);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Find the pane directly below another. */
|
||||
struct window_pane *
|
||||
window_pane_find_down(struct window_pane *wp)
|
||||
{
|
||||
struct window_pane *wp2;
|
||||
u_int left, bottom;
|
||||
|
||||
if (wp == NULL || !window_pane_visible(wp))
|
||||
return (NULL);
|
||||
|
||||
bottom = wp->yoff + wp->sy + 1;
|
||||
if (bottom >= wp->window->sy)
|
||||
bottom = 0;
|
||||
left = wp->xoff;
|
||||
|
||||
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
|
||||
if (!window_pane_visible(wp2))
|
||||
continue;
|
||||
if (wp2->yoff != bottom)
|
||||
continue;
|
||||
if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx)
|
||||
return (wp2);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the pane directly to the left of another, adjacent to the left side and
|
||||
* containing the top edge.
|
||||
*/
|
||||
struct window_pane *
|
||||
window_pane_find_left(struct window_pane *wp)
|
||||
{
|
||||
struct window_pane *wp2;
|
||||
u_int left, top;
|
||||
|
||||
if (wp == NULL || !window_pane_visible(wp))
|
||||
return (NULL);
|
||||
|
||||
left = wp->xoff;
|
||||
if (left == 0)
|
||||
left = wp->window->sx + 1;
|
||||
top = wp->yoff;
|
||||
|
||||
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
|
||||
if (!window_pane_visible(wp2))
|
||||
continue;
|
||||
if (wp2->xoff + wp2->sx + 1 != left)
|
||||
continue;
|
||||
if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy)
|
||||
return (wp2);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the pane directly to the right of another, that is adjacent to the
|
||||
* right edge and including the top edge.
|
||||
*/
|
||||
struct window_pane *
|
||||
window_pane_find_right(struct window_pane *wp)
|
||||
{
|
||||
struct window_pane *wp2;
|
||||
u_int right, top;
|
||||
|
||||
if (wp == NULL || !window_pane_visible(wp))
|
||||
return (NULL);
|
||||
|
||||
right = wp->xoff + wp->sx + 1;
|
||||
if (right >= wp->window->sx)
|
||||
right = 0;
|
||||
top = wp->yoff;
|
||||
|
||||
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
|
||||
if (!window_pane_visible(wp2))
|
||||
continue;
|
||||
if (wp2->xoff != right)
|
||||
continue;
|
||||
if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy)
|
||||
return (wp2);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user