124 Commits
2.4 ... 2.5

Author SHA1 Message Date
Nicholas Marriott
caa90735cf 2.5. 2017-05-29 08:12:25 +01:00
Nicholas Marriott
0f26739c9f 2.5-rc2. 2017-05-13 08:17:01 +01:00
Nicholas Marriott
ae2c5ad768 Reset updated flag when restarting job so new output is detected, reported by
Gregory Pakosz in GitHub issue 922.
2017-05-13 08:16:11 +01:00
Nicholas Marriott
2bff5e7867 ECH needs to use background colour. 2017-05-12 16:16:16 +01:00
nicm
90f2a417af Need to clear tty context before using it. 2017-05-12 16:04:13 +01:00
nicm
7c07f5f640 Cannot rely on cursor position after DL and IL (some terminals move to
column 0, some do not).
2017-05-12 16:03:49 +01:00
nicm
69df38f8d8 Clear to start of screen needs to use background colour. 2017-05-11 23:28:44 +01:00
nicm
5e30b81825 Need to redraw out to cellsize (total cells used in a line) rather than
cellused (only non-space cells) because there may be cells with a
nondefault background.
2017-05-11 23:28:22 +01:00
Nicholas Marriott
3a47dec424 Fix test. 2017-05-09 23:01:10 +01:00
Nicholas Marriott
7b17618890 2.5-rc and changes. 2017-05-09 22:53:36 +01:00
Nicholas Marriott
71bc255e6f Merge branch 'master' of github.com:tmux/tmux 2017-05-09 22:34:15 +01:00
Nicholas Marriott
8f990c573c Update TODO. 2017-05-09 22:33:39 +01:00
Thomas Adam
3f1d6102f3 Merge branch 'obsd-master' 2017-05-09 20:01:10 +01:00
nicm
3712b41aba If the target pane for send-keys in in a mode with a key table (that is,
copy mode), then look the key up in the table and fire any command
instead of delivering the key to the pane directly where it will be
ignored. This makes C-b C-b (send-prefix) work in copy mode again.
2017-05-09 17:56:55 +00:00
Thomas Adam
4bcb64f8c1 Merge branch 'obsd-master' 2017-05-09 15:44:33 +01:00
Thomas Adam
a651b08a2f Merge branch 'obsd-master'
Conflicts:
	format.c
2017-05-09 15:44:13 +01:00
nicm
3b35daacf7 If the current screen was complex enough, it was possible to make redraw
itself hit the "terminal can't keep up" check. To avoid this, record how
much data we send during redraw (we know we will be starting with 0) and
skip the check until it has been flushed. GitHub issue 912.
2017-05-09 13:04:36 +00:00
nicm
18f36906a9 Set current pane in rotate-window. 2017-05-09 11:00:48 +00:00
nicm
5fee4638e0 Add a format for the name of the pane's mode, lets it be used as a
conditional for key bindings.
2017-05-07 22:27:57 +00:00
nicm
d52f579fd5 Up to now, tmux sees \033\033[OA as M-Up and since we turned on
xterm-keys by default, generates \033[1;3A instead of
\033\033[OA. Unfortunately this confuses vi, which doesn't understand
xterm keys and now sees Escape+Up pressed within escape-time as Escape
followed by A.

The issue doesn't happen in xterm itself because it gets the keys from X
and can distinguish between a genuine M-Up and Escape+Up.

Because xterm can, tmux can too: xterm will give us \033[1;3A (that is,
kUP3) for a real M-Up and \033\033OA for Escape+Up - in fact, we can be
sure any \033 preceding an xterm key is a real Escape key press because
Meta would be part of the xterm key instead of a separate \033.

So change tmux to recognise both sequences as M-Up for its own purposes,
but generate the xterm version of M-Up only if it originally received
the xterm version from the terminal.

This means we will return to sending \033\033OA instead of the xterm key
for terminals that do not support xterm keys themselves, but there is no
practical way around this because they do not allow us to distinguish
between Escape+Up and M-Up. xterm style escape sequences are now the de
facto standard for these keys in any case.

Problem reported by jsing@ and subsequently by Cecile Tonglet in GitHub
issue 907.
2017-05-07 21:25:59 +00:00
nicm
2fef10b9ac Add some formats to look at the session window stack, suggested by Scott
ROCHFORD.
2017-05-05 11:59:47 +00:00
Thomas Adam
f3221941f2 Merge branch 'obsd-master' 2017-05-04 10:01:12 +01:00
nicm
d98d316903 Some new notifications, mainly for active pane and current window and
session:

    pane-mode-changed
    window-pane-changed
    client-session-changed
    session-window-changed

From Joshua Brot.
2017-05-04 07:16:43 +00:00
Thomas Adam
97ecb4f9d8 Merge branch 'obsd-master' 2017-05-03 08:01:14 +01:00
nicm
ca6a121e63 Add a format for the last search string in copy mode and fix the prompt
so it can work when in -I, suggested by Suraj N Kurapati.
2017-05-03 05:53:34 +00:00
Thomas Adam
e354b0e40f Merge branch 'obsd-master' 2017-05-01 14:01:14 +01:00
nicm
0ccfb61bb0 In order that people can use formats like #D in #() in the status line
and not have to wait for an update when they change pane, we allow
commands to run more than once a second if the expanded form
changes. Unfortunately this can mean them being run far too often
(pretty much continually) when multiple clients exist, because some
formats (including #D) will always differ between clients.

To avoid this, give each client its own tree of jobs which means that
the same command will be different instances for each client - similar
to how we have the tag to separate commands for different panes.

GitHub issue 889; test case reported by Paul Johnson.
2017-05-01 12:20:55 +00:00
Nicholas Marriott
4b39120d22 .NOTPARALLEL. 2017-04-30 13:55:32 +01:00
Nicholas Marriott
76950a6401 Add regress/Makefile. 2017-04-30 13:47:25 +01:00
Nicholas Marriott
909d962d3a Make example match reality; Greg Hurrell. 2017-04-30 08:27:23 +01:00
Nicholas Marriott
dde53cfde1 Add to TODO. 2017-04-30 08:23:14 +01:00
Thomas Adam
0adb60b3a6 Merge branch 'obsd-master' 2017-04-30 00:01:17 +01:00
nicm
a2dd7daf4e Fix UTF-8 combining characters in column 0, based on a diff from Keith
Winstein.
2017-04-29 21:27:46 +00:00
Thomas Adam
3a8e56b282 Merge branch 'obsd-master' 2017-04-28 22:01:18 +01:00
Nicholas Marriott
36202a63e9 Merge branch 'master' of github.com:tmux/tmux 2017-04-28 20:22:31 +01:00
Nicholas Marriott
abad809e7a Test that kill-session closes the panes (processes end up dead). 2017-04-28 20:22:01 +01:00
nicm
0f2f783584 Log what is happening with window and session reference counts much more
obviously.
2017-04-28 19:13:55 +00:00
nicm
bcd6b41674 Remove a reference from the right window when removing from a winlink's
list.
2017-04-28 19:12:15 +00:00
nicm
92053cb492 Do not put the window on the alerts queue and add a reference unless the
alert is enabled and we are actually going to add the alerts event.
2017-04-28 19:10:48 +00:00
Thomas Adam
14cb489a3b Merge branch 'obsd-master' 2017-04-28 20:01:14 +01:00
nicm
54e2205e54 Konsole incorrectly ignores SU (CSI S) if the parameter is bigger than
the scroll region, so clamp it. Reported by Moritz Bunkus.
2017-04-28 17:58:44 +00:00
Thomas Adam
99b0f48b2e Merge branch 'obsd-master' 2017-04-28 16:01:12 +01:00
nicm
c12711affd Default for xterm-keys was wrong, stop documenting it. 2017-04-28 13:39:59 +00:00
Nicholas Marriott
e4b4125310 source-file too. 2017-04-27 13:14:14 +01:00
Nicholas Marriott
6b2d850e54 Tests for some new session and new window bits. 2017-04-27 13:09:08 +01:00
Thomas Adam
0daeefefdb Merge branch 'obsd-master' 2017-04-25 20:01:11 +01:00
nicm
d520dae6ac Make full width panes try to play more nicely with terminal copy and
paste by avoiding explicit line wraps if we think the terminal will wrap
anyway.
2017-04-25 18:30:29 +00:00
nicm
03d01eabb5 When we write out the grid including escape sequences, an SGR 0 needs to
cause the colours to be written again. Also treat colours separately
from attributes so that RGB colours will work.
2017-04-25 18:20:51 +00:00
Thomas Adam
65d6278f88 Merge branch 'obsd-master' 2017-04-25 18:01:11 +01:00
nicm
c48d09ec88 Do not update TERM into config file parsing has finished. 2017-04-25 15:35:10 +00:00
nicm
4a51a9d9d5 Block the initial client if there is one until the configuration file
has finished loading.
2017-04-25 14:46:23 +00:00
Nicholas Marriott
b938212563 Another test. 2017-04-25 15:40:10 +01:00
Nicholas Marriott
accaff8ac0 Remove stuff from TODO. 2017-04-25 14:31:05 +01:00
Nicholas Marriott
45965fb020 And another test. 2017-04-25 14:30:58 +01:00
Thomas Adam
6ac39d5cdb Merge branch 'obsd-master' 2017-04-25 14:01:16 +01:00
Nicholas Marriott
9794c03537 And another. 2017-04-25 13:50:44 +01:00
Nicholas Marriott
1b221a56ea Try to start writing test scripts. 2017-04-25 13:37:03 +01:00
nicm
eb6fd6ff80 if-shell doesn't need to queue its error message into a callback, and in
fact it can't do so because the item it was working with will have been
freed. Reported by Daniel Hahler.
2017-04-25 11:49:35 +00:00
Thomas Adam
9d041d8e6c Merge branch 'obsd-master' 2017-04-23 20:01:13 +01:00
nicm
5172014668 Only use ED for clear screen if at the bottom, same as earlier fix to
clear end of screen.
2017-04-23 18:13:24 +00:00
Thomas Adam
b853054e71 Merge branch 'obsd-master' 2017-04-22 16:01:19 +01:00
Thomas Adam
a6a294c8f8 Merge branch 'obsd-master' 2017-04-22 14:01:15 +01:00
nicm
1e0eb914d9 Memory leak from David CARLIER. 2017-04-22 12:55:06 +00:00
nicm
ae1a6c2fc5 Do not need getopt.h. 2017-04-22 12:08:41 +00:00
Thomas Adam
e802b683ea Merge branch 'obsd-master' 2017-04-22 12:01:19 +01:00
nicm
55cd4c7bc7 Can't collect UTF-8 characters of more than one byte at the moment. 2017-04-22 10:30:56 +00:00
nicm
a4eaac359a new -A should use the session name. 2017-04-22 10:26:44 +00:00
nicm
ee45a8a149 Get rid of the extra layer of flags and cmd_prepare() and just store the
CMD_FIND_* flags in the cmd_entry and call it for the command. Commands
with special requirements call it themselves and update the target for
hooks to use.
2017-04-22 10:22:39 +00:00
Thomas Adam
b08e451c91 Merge branch 'obsd-master' 2017-04-22 10:01:51 +01:00
nicm
2c0f826c36 Mouse bindings and hooks set up an initial current state when running a
command. This is used for the session, window and pane for all commands
in the command sequence if there is no -t or -s.

However, using it for all commands in the command sequence means that if
the active pane or current session is changed, subsequent commands still
use the previous state. So make commands which explicitly change the
current state (such as neww and selectp) update it themselves for later
commands. Commands which may invalidate the state (like killp) are
already OK because an invalid state will be ignored.

Also fill in the current state for all key bindings rather than just the
mouse, so that any omissions are easier to spot.
2017-04-22 08:56:24 +00:00
nicm
bcab77e266 We need to collect UTF-8 characters so that width != 1 characters are
correctly flushed.
2017-04-22 08:33:28 +00:00
Thomas Adam
d8398af770 Merge branch 'obsd-master' 2017-04-22 08:01:54 +01:00
nicm
30348edc7c Fix if-shell without a client (so in the config file). Reported by Theo
Buehler.
2017-04-22 06:27:15 +00:00
nicm
59ff9b8128 Typo in example. 2017-04-22 06:15:22 +00:00
nicm
2c9bdd9e32 Memory leaks, from David CARLIER. 2017-04-22 06:13:30 +00:00
Thomas Adam
21240c1a8f Merge branch 'obsd-master' 2017-04-22 00:01:11 +01:00
nicm
c8ecbf38ab Log error properly when no current state, and some other minor tweaks. 2017-04-21 22:23:24 +00:00
nicm
194a121ef6 Make sure cmd_find_from_* clear the state if they fail. 2017-04-21 22:00:06 +00:00
nicm
8867951144 Rename a variable. 2017-04-21 21:02:26 +00:00
Thomas Adam
fd13731049 Merge branch 'obsd-master' 2017-04-21 22:01:14 +01:00
nicm
c68ceca8cd Clear shared state if not filling it in. 2017-04-21 20:34:05 +00:00
nicm
efaf4c16cf Make the cmd_find_* functions more obvious when looking for a client,
rather than having it inside other functions. Should be no change to the
way targets are resolved just yet.
2017-04-21 20:26:34 +00:00
nicm
2ad09ab5af Key needs to be initialized to zero now it has flags in it. 2017-04-21 19:33:07 +00:00
Thomas Adam
1f209ed030 Merge branch 'obsd-master' 2017-04-21 20:01:18 +01:00
nicm
3c876235cc Style nits and an unused struct. 2017-04-21 18:18:17 +00:00
nicm
afa4e3ed9c Add cmd_find_from_winlink_pane and use it in a couple of places, and
make functions that can't fail void.
2017-04-21 17:22:20 +00:00
Thomas Adam
c376c5a817 Merge branch 'obsd-master' 2017-04-21 18:01:11 +01:00
nicm
92a77e7654 It is annoying that the copy mode key table (or any other key table)
will suppress root key table bindings. So change to always check the
root table if no binding is found in the current table (whether it be
the prefix table from pressing the prefix or the copy mode table from a
pane).

A root key binding can be blocked by binding the key to a command that
does nothing (like send-keys with no arguments).

Problem reported by Thomas Sattler.
2017-04-21 16:04:18 +00:00
Thomas Adam
4612419c14 Merge branch 'obsd-master' 2017-04-21 16:01:18 +01:00
nicm
c799425069 More unnecessary arguments now winlink points back to session. 2017-04-21 14:09:44 +00:00
nicm
428be9803c History needs to be loaded after config parsing is done - now that
commands are queued, that's in cfg_done not after start_cfg finishes.
2017-04-21 14:04:54 +00:00
nicm
bba588752f Store state shared between multiple commands in the queue in a shared
structure.
2017-04-21 14:01:19 +00:00
nicm
311dad8c28 Do not run the config file in the context of the first client, instead
use no client like we did before. This means commands like new-session
won't try to attach if they are in the config file.
2017-04-21 13:15:43 +00:00
Thomas Adam
93062ad099 Fix after merge 2017-04-21 09:29:22 +01:00
Thomas Adam
22e594fcea Merge branch 'obsd-master'
Conflicts:
	Makefile.am
	pty.c
2017-04-21 09:25:07 +01:00
Nicholas Marriott
02580ac134 Typo; Daniel Hahler. 2017-04-21 06:49:38 +01:00
Nicholas Marriott
b723f50e65 Do not need getopt.h for getopt, from Eric N Vander Weele. 2017-04-20 20:35:11 +01:00
Nicholas Marriott
4a2e75fc8c Merge branch 'master' of github.com:tmux/tmux 2017-04-20 19:09:36 +01:00
Nicholas Marriott
9420758127 getptmfd() and fdforkpty() compat. 2017-04-20 19:09:07 +01:00
nicm
87997efe8d Use fdforkpty() instead of our own unwrapped versions. 2017-04-20 17:49:26 +00:00
Thomas Adam
69e0f28333 Merge branch 'obsd-master' 2017-04-20 18:01:12 +01:00
nicm
51a0dbb172 Only set up a current target for mouse key bindings. Fixes:
bind q select-pane -U \; resize-pane -Z

(There is still some possible weirdness with the way we do current
targets, it should probably be done in a different way at some point.)
2017-04-20 15:16:20 +00:00
Nicholas Marriott
7934e7a6b5 Notes on target resolution. 2017-04-20 15:40:28 +01:00
Nicholas Marriott
aebbb15fe2 Turn on debug if $VERSION is master rather than commenting and uncommenting. 2017-04-20 12:06:39 +01:00
Thomas Adam
48371216df Merge branch 'obsd-master' 2017-04-20 12:01:14 +01:00
Nicholas Marriott
e30f9dc1fa Merge tag '2.4'
Version 2.4.
2017-04-20 11:59:07 +01:00
nicm
21993105e5 Now that struct winlink has a session pointer, can remove some arguments. 2017-04-20 09:43:45 +00:00
nicm
0f25ad3ca3 There is no real need for window_printable_flags to allocate, make it
return a buffer from the stack.
2017-04-20 09:39:07 +00:00
Nicholas Marriott
f9c7c50a93 Update TODO. 2017-04-20 10:20:42 +01:00
nicm
0b44ad99b5 If a #() command doesn't exit, use its most recent line of output (it
must be a full line). Don't let it redraw the status line more than once
a second.

Requested by someone about 10 years ago...
2017-04-20 09:20:22 +00:00
Nicholas Marriott
78d707dc83 Add to TODO. 2017-04-20 08:53:03 +01:00
Thomas Adam
3385159c94 Merge branch 'obsd-master' 2017-04-19 20:01:11 +01:00
nicm
f184c6f06c load_cfg returns < 0 on error, not != 0. Problem reported by Kaushal Modi. 2017-04-19 16:59:54 +00:00
Thomas Adam
5a551ac57f Merge branch 'obsd-master' 2017-04-19 16:01:14 +01:00
nicm
53fde21bb8 Add a suspend helper function, and do not allow detaching or suspending
while already doing so.
2017-04-19 14:00:28 +00:00
nicm
689f4bfac2 Style nits and a missing cast. 2017-04-19 12:44:29 +00:00
Thomas Adam
85af9c9c9d Merge branch 'obsd-master' 2017-04-19 10:01:12 +01:00
Nicholas Marriott
95c38087db Missed freezero. 2017-04-19 07:58:45 +01:00
nicm
fa6deb5866 When the data we have buffered to write to a terminal grows beyond a
reasonable amount (currently width * height * 8 bytes), discard all
output to the terminal and start trying to redraw periodically
instead. Continue with this until the amount of data we are trying to
write falls to a low level again.

This helps to prevent tmux sitting on a huge buffer of data when there
are processes with fast output running inside tmux but the outside
terminal is slow.

A new client_discarded format holds the amount of data that has been
discarded due to this mechanism.

The three variables (when to start this, when to stop, and how often to
redraw) are basically "works for me" at the moment, this is going in to
see how it goes and if it causes problems for anyone else.
2017-04-19 06:52:27 +00:00
Thomas Adam
a71c262d5f Merge branch 'obsd-master' 2017-04-19 00:01:15 +01:00
nicm
f731ae4a2d Revert use of DECSLRM on iTerm2, it doesn't help as much as we throught,
and there are some question marks about it's support.
2017-04-18 21:41:42 +00:00
nicm
8c8ce08d79 On terminals without DECSLRM, when a pane that is less than the full
with of the terminal scrolls, tmux needs to redraw the entire pane. This
results in a large amount of output data which can cause slow terminals
to struggle, particularly when many lines are scrolled together quickly.

This can be reduced by only redrawing when tmux doesn't hold any
buffered data for the terminal. If a redraw is required and data is
buffered, the redraw is deferred until all that data is consumed (it is
checked after every event loop, a timer is used to ensure this happens
at some point). While a redraw is pending, no additional data will be
written to the terminal.

The redraw still happens, now it is just pushed back if it is possible
it would just add more data on top of a terminal that is already
behind. This both gives the terminal a chance to catch up, and allows
tmux to process more scrolling (that would require additional redraws)
in the meantime.

Helps with a problem reported by Greg Hurrell.
2017-04-18 20:37:49 +00:00
Thomas Adam
de4f817bd6 Merge branch 'obsd-master' 2017-04-18 20:01:12 +01:00
nicm
623e35f594 Detect iTerm2 and use DECSLRM for it as well. 2017-04-18 18:21:37 +00:00
107 changed files with 2130 additions and 1303 deletions

89
CHANGES
View File

@@ -1,3 +1,88 @@
CHANGES FROM 2.4 to 2.5 09 May 2017
* Reset updated flag when restarting #() command so that new output is properly
recognised. GitHub issue 922.
* Fix ECH with a background colour.
* Do not rely on the terminal not moving the cursor after DL or EL.
* Fix send-keys and send-prefix in copy-mode (so C-b C-b works). GitHub issue
905.
* Set the current pane for rotate-window so it works in command sequences.
* Add pane_mode format.
* Differentiate M-Up from Escape+Up when possible (that is, in terminals with
xterm(1) style function keys). GitHub issue 907.
* Add session_stack and window_stack_index formats.
* Some new control mode notifications and corresponding hooks:
pane-mode-changed, window-pane-changed, client-session-changed,
session-window-changed.
* Format pane_search_string for last search term while in copy mode (useful
with command-prompt -I).
* Fix a problem with high CPU usage and multiple clients with #(). GitHub issue
889.
* Fix UTF-8 combining characters in column 0.
* Fix reference counting so that panes are properly destroyed and their
processes killed.
* Clamp SU (CSI S) parameter to work around a bug in Konsole.
* Tweak line wrapping in full width panes to play more nicely with terminal
copy and paste.
* Fix when we emit SGR 0 in capture-pane -e.
* Do not change TERM until after config file parsing has finished, so that
commands run inside the config file can use it to make decisions (typically
about default-terminal).
* Make the initial client wait until config file parsing has finished to avoid
racing with commands.
* Fix core when if-shell fails.
* Only use ED to clear screen if the pane is at the bottom.
* Fix multibyte UTF-8 output.
* Code improvements around target (-t) resolution.
* Change how the default target (for commands without -t) is managed across
command sequences: now it is set up at the start and commands are required
to update it if needed. Fixes binding command sequences to mouse keys.
* Make if-shell from the config file work correctly.
* Change to always check the root key table if no binding is found in the
current table (prefix table or copy-mode table or whatever). This means that
root key bindings will take effect even in copy mode, if not overridden by a
copy mode key binding.
* Fix so that the history file works again.
* Run config file without a client rather than using the first client, restores
previous behaviour.
* If a #() command doesn't exit, continue to read from it and use its last full
line of output.
* Handle slow terminals and fast output better: when the amount of data
outstanding gets too large, discard output until it is drained and we are
able to do a full redraw. Prevents tmux sitting on a huge buffer that the
terminal will take forever to consume.
* Do not redraw a client unless we realistically think it can accept the data -
defer redraws until the client has nothing else waiting to write.
CHANGES FROM 2.3 to 2.4 20 April 2017 CHANGES FROM 2.3 to 2.4 20 April 2017
Incompatible Changes Incompatible Changes
@@ -23,12 +108,12 @@ Incompatible Changes
bind -Tcopy-mode C-Up send -X scroll-up bind -Tcopy-mode C-Up send -X scroll-up
bind -Tcopy-mode WheelUpPane send -N5 -X scroll-up bind -Tcopy-mode WheelUpPane send -N5 -X scroll-up
This changes allows the full command parser (including command sequences) and These changes allows the full command parser (including command sequences) and
command set to be used - for example, the normal command prompt with editing command set to be used - for example, the normal command prompt with editing
and history is now used for searching, jumping, and so on instead of a custom and history is now used for searching, jumping, and so on instead of a custom
one. The default C-r binding is now: one. The default C-r binding is now:
bind -Tcopy-mode C-r command-prompt -p'search up' "send -X search-backward '%%'" bind -Tcopy-mode C-r command-prompt -p'search up' "send -X search-backward-incremental '%%'"
There are also some new commmands available with send -X, such as There are also some new commmands available with send -X, such as
copy-pipe-and-cancel. copy-pipe-and-cancel.

View File

@@ -8,8 +8,6 @@ CLEANFILES = tmux.1.mdoc tmux.1.man
EXTRA_DIST = \ EXTRA_DIST = \
CHANGES FAQ README TODO COPYING example_tmux.conf compat/*.[ch] \ CHANGES FAQ README TODO COPYING example_tmux.conf compat/*.[ch] \
osdep-*.c mdoc2man.awk tmux.1 osdep-*.c mdoc2man.awk tmux.1
dist-hook:
grep "^#enable_debug=" configure
# Preprocessor flags. # Preprocessor flags.
AM_CPPFLAGS += @XOPEN_DEFINES@ -DTMUX_CONF="\"$(sysconfdir)/tmux.conf\"" AM_CPPFLAGS += @XOPEN_DEFINES@ -DTMUX_CONF="\"$(sysconfdir)/tmux.conf\""
@@ -153,7 +151,6 @@ dist_tmux_SOURCES = \
options.c \ options.c \
paste.c \ paste.c \
proc.c \ proc.c \
pty.c \
resize.c \ resize.c \
screen-redraw.c \ screen-redraw.c \
screen-write.c \ screen-write.c \

24
SYNCING
View File

@@ -140,16 +140,12 @@ to compat/ as and when appropriate.
Release tmux for next version Release tmux for next version
============================= =============================
1. Comment the "enable_debug=yes" line in configure.ac, since releases 1. Update and commit README and CHANGES. The former should be checked for
don't have debugging enabled, otherwise make(1) aborts when
preparing the distribution.
2. Update and commit README and CHANGES. The former should be checked for
anything outdated and updated with a list of things that might break anything outdated and updated with a list of things that might break
upgrades and the latter should mention all the major changes since upgrades and the latter should mention all the major changes since
the last version. the last version.
3. Tag with: 2. Tag with:
% git tag -a 2.X % git tag -a 2.X
@@ -157,20 +153,20 @@ Release tmux for next version
Push the tag out with: Push the tag out with:
% git push 2.X % git push --tags
4. Build the tarball with 'make dist'. 3. Build the tarball with 'make dist'.
5. Check the tarball. If it's good, go here to select the tag just pushed: 4. Check the tarball. If it's good, go here to select the tag just pushed:
https://github.com/tmux/tmux/tags https://github.com/tmux/tmux/tags
Click the "Add release notes", upload the tarball and add a link in the Click the "Add release notes", upload the tarball and add a link in the
description field to the CHANGES file. description field to the CHANGES file.
7. Clone the tmux.github.io repository, and change the RELEASE version in 5. Clone the tmux.github.io repository, and change the RELEASE version in the
the Makefile. Commit it, and run 'make' to replace %%VERSION%%. Push Makefile. Commit it, and run 'make' to replace %%VERSION%%. Push the
the result out. result out.
8. Bump version in tmux/tmux.git configure.ac and uncomment "enable_debug=yes" to 6. Bump version in tmux/tmux.git configure.ac and uncomment "enable_debug=yes"
create a debug build by default. to create a debug build by default.

11
TODO
View File

@@ -22,6 +22,8 @@
* formats to show if a window is linked into multiple sessions, into * formats to show if a window is linked into multiple sessions, into
multiple attached sessions, and is the active window in multiple multiple attached sessions, and is the active window in multiple
attached sessions? attached sessions?
* comparison operators like < and > (for #{version}?)
* %else statement in config file
- choose mode improvements: - choose mode improvements:
* choose-pane command (augment choose-tree to do this?) * choose-pane command (augment choose-tree to do this?)
@@ -53,8 +55,9 @@
then it should be found even if it is now "foo\nbar" (if the WRAP flag then it should be found even if it is now "foo\nbar" (if the WRAP flag
is set on the line) is set on the line)
* capture-pane option to preserve spaces but not join lines * capture-pane option to preserve spaces but not join lines
* improve word and line selection in copy mode (for example when dragging * improve word and line selection in copy mode (for example when
it should select by word. compare how xterm works. GitHub issue 682) dragging it should select by word. compare how xterm works. GitHub
issue 682)
- layout stuff - layout stuff
* way to tag a layout as a number/name * way to tag a layout as a number/name
@@ -70,6 +73,8 @@
* a mode where one application can cross two panes (ie x|y, width = * a mode where one application can cross two panes (ie x|y, width =
COLUMNS/2 but height = ROWS * 2) COLUMNS/2 but height = ROWS * 2)
* separate active panes for different clients * separate active panes for different clients
* way to choose where the freed space goes when a pane is killed:
option to kill-pane? GitHub issue 918
- code cleanup - code cleanup
* instead of separate window and session options, just one master * instead of separate window and session options, just one master
@@ -100,7 +105,6 @@
client w/o a session else cmd_current_client client w/o a session else cmd_current_client
- miscellaneous - miscellaneous
* way to keep a job running just read its last line of output for #()
* link panes into multiple windows * link panes into multiple windows
* live update: server started with -U connects to server, requests * live update: server started with -U connects to server, requests
sessions and windows, receives file descriptors sessions and windows, receives file descriptors
@@ -113,6 +117,7 @@
* marks in history, automatically add (move?) one when pane is changed * marks in history, automatically add (move?) one when pane is changed
* this doesn't work, need pane reference count probably: * this doesn't work, need pane reference count probably:
bind -n DoubleClick3Status confirm-before -p "kill-window #I? (y/n)" kill-window bind -n DoubleClick3Status confirm-before -p "kill-window #I? (y/n)" kill-window
* respawn -c flag same as neww etc
- hooks - hooks
* more hooks for various things * more hooks for various things

View File

@@ -64,7 +64,7 @@ alerts_callback(__unused int fd, __unused short events, __unused void *arg)
TAILQ_REMOVE(&alerts_list, w, alerts_entry); TAILQ_REMOVE(&alerts_list, w, alerts_entry);
w->flags &= ~WINDOW_ALERTFLAGS; w->flags &= ~WINDOW_ALERTFLAGS;
window_remove_ref(w); window_remove_ref(w, __func__);
} }
alerts_fired = 0; alerts_fired = 0;
} }
@@ -144,16 +144,18 @@ alerts_queue(struct window *w, int flags)
log_debug("@%u alerts flags added %#x", w->id, flags); log_debug("@%u alerts flags added %#x", w->id, flags);
} }
if (!w->alerts_queued) { if (alerts_enabled(w, flags)) {
w->alerts_queued = 1; if (!w->alerts_queued) {
TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry); w->alerts_queued = 1;
w->references++; TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
} window_add_ref(w, __func__);
}
if (!alerts_fired && alerts_enabled(w, flags)) { if (!alerts_fired) {
log_debug("alerts check queued (by @%u)", w->id); log_debug("alerts check queued (by @%u)", w->id);
event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL); event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
alerts_fired = 1; alerts_fired = 1;
}
} }
} }
@@ -178,7 +180,7 @@ alerts_check_bell(struct window *w)
s = wl->session; s = wl->session;
if (s->curw != wl) { if (s->curw != wl) {
wl->flags |= WINLINK_BELL; wl->flags |= WINLINK_BELL;
notify_winlink("alert-bell", s, wl); notify_winlink("alert-bell", wl);
} }
if (s->flags & SESSION_ALERTED) if (s->flags & SESSION_ALERTED)
@@ -239,7 +241,7 @@ alerts_check_activity(struct window *w)
continue; continue;
wl->flags |= WINLINK_ACTIVITY; wl->flags |= WINLINK_ACTIVITY;
notify_winlink("alert-activity", s, wl); notify_winlink("alert-activity", wl);
if (s->flags & SESSION_ALERTED) if (s->flags & SESSION_ALERTED)
continue; continue;
@@ -275,7 +277,7 @@ alerts_check_silence(struct window *w)
if (s->curw == wl) if (s->curw == wl)
continue; continue;
wl->flags |= WINLINK_SILENCE; wl->flags |= WINLINK_SILENCE;
notify_winlink("alert-silence", s, wl); notify_winlink("alert-silence", wl);
if (s->flags & SESSION_ALERTED) if (s->flags & SESSION_ALERTED)
continue; continue;

54
cfg.c
View File

@@ -27,11 +27,19 @@
#include "tmux.h" #include "tmux.h"
static char *cfg_file; static char *cfg_file;
int cfg_finished; int cfg_finished;
static char **cfg_causes; static char **cfg_causes;
static u_int cfg_ncauses; static u_int cfg_ncauses;
struct client *cfg_client; static struct cmdq_item *cfg_item;
static enum cmd_retval
cfg_client_done(__unused struct cmdq_item *item, __unused void *data)
{
if (!cfg_finished)
return (CMD_RETURN_WAIT);
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval static enum cmd_retval
cfg_done(__unused struct cmdq_item *item, __unused void *data) cfg_done(__unused struct cmdq_item *item, __unused void *data)
@@ -43,8 +51,11 @@ cfg_done(__unused struct cmdq_item *item, __unused void *data)
if (!RB_EMPTY(&sessions)) if (!RB_EMPTY(&sessions))
cfg_show_causes(RB_MIN(sessions, &sessions)); cfg_show_causes(RB_MIN(sessions, &sessions));
if (cfg_client != NULL) if (cfg_item != NULL)
server_client_unref(cfg_client); cfg_item->flags &= ~CMDQ_WAITING;
status_prompt_load_history();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -60,21 +71,35 @@ start_cfg(void)
{ {
const char *home; const char *home;
int quiet = 0; int quiet = 0;
struct client *c;
cfg_client = TAILQ_FIRST(&clients); /*
if (cfg_client != NULL) * Configuration files are loaded without a client, so NULL is passed
cfg_client->references++; * into load_cfg() and commands run in the global queue with
* item->client NULL.
*
* However, we must block the initial client (but just the initial
* client) so that its command runs after the configuration is loaded.
* Because start_cfg() is called so early, we can be sure the client's
* command queue is currently empty and our callback will be at the
* front - we need to get in before MSG_COMMAND.
*/
c = TAILQ_FIRST(&clients);
if (c != NULL) {
cfg_item = cmdq_get_callback(cfg_client_done, NULL);
cmdq_append(c, cfg_item);
}
load_cfg(TMUX_CONF, cfg_client, NULL, 1); load_cfg(TMUX_CONF, NULL, NULL, 1);
if (cfg_file == NULL && (home = find_home()) != NULL) { if (cfg_file == NULL && (home = find_home()) != NULL) {
xasprintf(&cfg_file, "%s/.tmux.conf", home); xasprintf(&cfg_file, "%s/.tmux.conf", home);
quiet = 1; quiet = 1;
} }
if (cfg_file != NULL) if (cfg_file != NULL)
load_cfg(cfg_file, cfg_client, NULL, quiet); load_cfg(cfg_file, NULL, NULL, quiet);
cmdq_append(cfg_client, cmdq_get_callback(cfg_done, NULL)); cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
} }
int int
@@ -122,7 +147,8 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
line); line);
continue; continue;
} }
ft = format_create(NULL, FORMAT_NONE, FORMAT_NOJOBS); ft = format_create(NULL, NULL, FORMAT_NONE,
FORMAT_NOJOBS);
s = p + 3; s = p + 3;
while (isspace((u_char)*s)) while (isspace((u_char)*s))

View File

@@ -40,20 +40,23 @@ const struct cmd_entry cmd_attach_session_entry = {
.args = { "c:dErt:", 0, 0 }, .args = { "c:dErt:", 0, 0 },
.usage = "[-dEr] [-c working-directory] " CMD_TARGET_SESSION_USAGE, .usage = "[-dEr] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION_WITHPANE, /* -t is special */
.flags = CMD_STARTSERVER, .flags = CMD_STARTSERVER,
.exec = cmd_attach_session_exec .exec = cmd_attach_session_exec
}; };
enum cmd_retval enum cmd_retval
cmd_attach_session(struct cmdq_item *item, int dflag, int rflag, cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
const char *cflag, int Eflag) int rflag, const char *cflag, int Eflag)
{ {
struct session *s = item->state.tflag.s; struct cmd_find_state *current = &item->shared->current;
enum cmd_find_type type;
int flags;
struct client *c = item->client, *c_loop; struct client *c = item->client, *c_loop;
struct winlink *wl = item->state.tflag.wl; struct session *s;
struct window_pane *wp = item->state.tflag.wp; struct winlink *wl;
struct window_pane *wp;
char *cause; char *cause;
if (RB_EMPTY(&sessions)) { if (RB_EMPTY(&sessions)) {
@@ -69,10 +72,27 @@ cmd_attach_session(struct cmdq_item *item, int dflag, int rflag,
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (tflag != NULL && tflag[strcspn(tflag, ":.")] != '\0') {
type = CMD_FIND_PANE;
flags = 0;
} else {
type = CMD_FIND_SESSION;
flags = CMD_FIND_PREFER_UNATTACHED;
}
if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
return (CMD_RETURN_ERROR);
s = item->target.s;
wl = item->target.wl;
wp = item->target.wp;
if (wl != NULL) { if (wl != NULL) {
if (wp != NULL) if (wp != NULL)
window_set_active_pane(wp->window, wp); window_set_active_pane(wp->window, wp);
session_set_current(s, wl); session_set_current(s, wl);
if (wp != NULL)
cmd_find_from_winlink_pane(current, wl, wp);
else
cmd_find_from_winlink(current, wl);
} }
if (cflag != NULL) { if (cflag != NULL) {
@@ -92,7 +112,7 @@ cmd_attach_session(struct cmdq_item *item, int dflag, int rflag,
environ_update(s->options, c->environ, s->environ); environ_update(s->options, c->environ, s->environ);
c->session = s; c->session = s;
if (!item->repeat) if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
status_timer_start(c); status_timer_start(c);
notify_client("client-session-changed", c); notify_client("client-session-changed", c);
@@ -145,6 +165,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
return (cmd_attach_session(item, args_has(args, 'd'), return (cmd_attach_session(item, args_get(args, 't'),
args_has(args, 'r'), args_get(args, 'c'), args_has(args, 'E'))); args_has(args, 'd'), args_has(args, 'r'), args_get(args, 'c'),
args_has(args, 'E')));
} }

View File

@@ -35,10 +35,11 @@ const struct cmd_entry cmd_break_pane_entry = {
.alias = "breakp", .alias = "breakp",
.args = { "dPF:n:s:t:", 0, 0 }, .args = { "dPF:n:s:t:", 0, 0 },
.usage = "[-dP] [-F format] [-n window-name] [-s src-pane] [-t dst-window]", .usage = "[-dP] [-F format] [-n window-name] [-s src-pane] "
"[-t dst-window]",
.sflag = CMD_PANE, .source = { 's', CMD_FIND_PANE, 0 },
.tflag = CMD_WINDOW_INDEX, .target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
.flags = 0, .flags = 0,
.exec = cmd_break_pane_exec .exec = cmd_break_pane_exec
@@ -48,14 +49,15 @@ static enum cmd_retval
cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->state.sflag.wl; struct client *c = cmd_find_client(item, NULL, 1);
struct session *src_s = item->state.sflag.s; struct winlink *wl = item->source.wl;
struct session *dst_s = item->state.tflag.s; struct session *src_s = item->source.s;
struct window_pane *wp = item->state.sflag.wp; struct session *dst_s = item->target.s;
struct window_pane *wp = item->source.wp;
struct window *w = wl->window; struct window *w = wl->window;
char *name, *cause; char *name, *cause;
int idx = item->state.tflag.idx; int idx = item->target.idx;
const char *template; const char *template;
char *cp; char *cp;
@@ -93,8 +95,10 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
if (idx == -1) if (idx == -1)
idx = -1 - options_get_number(dst_s->options, "base-index"); idx = -1 - options_get_number(dst_s->options, "base-index");
wl = session_attach(dst_s, w, idx, &cause); /* can't fail */ wl = session_attach(dst_s, w, idx, &cause); /* can't fail */
if (!args_has(self->args, 'd')) if (!args_has(self->args, 'd')) {
session_select(dst_s, wl->idx); session_select(dst_s, wl->idx);
cmd_find_from_session(current, dst_s);
}
server_redraw_session(src_s); server_redraw_session(src_s);
if (src_s != dst_s) if (src_s != dst_s)

View File

@@ -43,7 +43,7 @@ const struct cmd_entry cmd_capture_pane_entry = {
.usage = "[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] " .usage = "[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] "
"[-S start-line]" CMD_TARGET_PANE_USAGE, "[-S start-line]" CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_capture_pane_exec .exec = cmd_capture_pane_exec
@@ -56,7 +56,7 @@ const struct cmd_entry cmd_clear_history_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE, .usage = CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_capture_pane_exec .exec = cmd_capture_pane_exec
@@ -193,7 +193,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c;
struct window_pane *wp = item->state.tflag.wp; struct window_pane *wp = item->target.wp;
char *buf, *cause; char *buf, *cause;
const char *bufname; const char *bufname;
size_t len; size_t len;

View File

@@ -40,7 +40,7 @@ const struct cmd_entry cmd_choose_buffer_entry = {
.args = { "F:t:", 0, 1 }, .args = { "F:t:", 0, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]", .usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_choose_buffer_exec .exec = cmd_choose_buffer_exec
@@ -50,8 +50,8 @@ static enum cmd_retval
cmd_choose_buffer_exec(struct cmd *self, struct cmdq_item *item) cmd_choose_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct client *c = cmd_find_client(item, NULL, 1);
struct winlink *wl = item->state.tflag.wl; struct winlink *wl = item->target.wl;
struct window_choose_data *cdata; struct window_choose_data *cdata;
struct paste_buffer *pb; struct paste_buffer *pb;
char *action, *action_data; char *action, *action_data;

View File

@@ -45,7 +45,7 @@ const struct cmd_entry cmd_choose_client_entry = {
.args = { "F:t:", 0, 1 }, .args = { "F:t:", 0, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]", .usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_choose_client_exec .exec = cmd_choose_client_exec
@@ -59,10 +59,10 @@ static enum cmd_retval
cmd_choose_client_exec(struct cmd *self, struct cmdq_item *item) cmd_choose_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct client *c = cmd_find_client(item, NULL, 1);
struct client *c1; struct client *c1;
struct window_choose_data *cdata; struct window_choose_data *cdata;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl = item->target.wl;
const char *template; const char *template;
char *action; char *action;
u_int idx, cur; u_int idx, cur;

View File

@@ -51,7 +51,7 @@ const struct cmd_entry cmd_choose_tree_entry = {
.usage = "[-suw] [-b session-template] [-c window template] " .usage = "[-suw] [-b session-template] [-c window template] "
"[-S format] [-W format] " CMD_TARGET_WINDOW_USAGE, "[-S format] [-W format] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_choose_tree_exec .exec = cmd_choose_tree_exec
@@ -64,7 +64,7 @@ const struct cmd_entry cmd_choose_session_entry = {
.args = { "F:t:", 0, 1 }, .args = { "F:t:", 0, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]", .usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_choose_tree_exec .exec = cmd_choose_tree_exec
@@ -77,7 +77,7 @@ const struct cmd_entry cmd_choose_window_entry = {
.args = { "F:t:", 0, 1 }, .args = { "F:t:", 0, 1 },
.usage = CMD_TARGET_WINDOW_USAGE "[-F format] [template]", .usage = CMD_TARGET_WINDOW_USAGE "[-F format] [template]",
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_choose_tree_exec .exec = cmd_choose_tree_exec
@@ -87,9 +87,9 @@ static enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item) cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct client *c = cmd_find_client(item, NULL, 1);
struct winlink *wl = item->state.tflag.wl, *wm; struct winlink *wl = item->target.wl, *wm;
struct session *s = item->state.tflag.s, *s2; struct session *s = item->target.s, *s2;
struct window_choose_data *wcd = NULL; struct window_choose_data *wcd = NULL;
const char *ses_template, *win_template; const char *ses_template, *win_template;
char *final_win_action, *cur_win_template; char *final_win_action, *cur_win_template;

View File

@@ -43,8 +43,6 @@ const struct cmd_entry cmd_command_prompt_entry = {
.usage = "[-1Ni] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " " .usage = "[-1Ni] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
"[template]", "[template]",
.tflag = CMD_CLIENT,
.flags = 0, .flags = 0,
.exec = cmd_command_prompt_exec .exec = cmd_command_prompt_exec
}; };
@@ -69,10 +67,13 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
struct args *args = self->args; struct args *args = self->args;
const char *inputs, *prompts; const char *inputs, *prompts;
struct cmd_command_prompt_cdata *cdata; struct cmd_command_prompt_cdata *cdata;
struct client *c = item->state.c; struct client *c;
char *prompt, *ptr, *input = NULL; char *prompt, *ptr, *input = NULL;
size_t n; size_t n;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (c->prompt_string != NULL) if (c->prompt_string != NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@@ -192,7 +193,7 @@ cmd_command_prompt_callback(void *data, const char *s, int done)
if (!done) if (!done)
free(new_template); free(new_template);
if (c->prompt_callbackfn != (void *)&cmd_command_prompt_callback) if (c->prompt_callbackfn != cmd_command_prompt_callback)
return (1); return (1);
return (0); return (0);
} }

View File

@@ -41,8 +41,6 @@ const struct cmd_entry cmd_confirm_before_entry = {
.args = { "p:t:", 1, 1 }, .args = { "p:t:", 1, 1 },
.usage = "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command", .usage = "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
.tflag = CMD_CLIENT,
.flags = 0, .flags = 0,
.exec = cmd_confirm_before_exec .exec = cmd_confirm_before_exec
}; };
@@ -57,10 +55,13 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_confirm_before_data *cdata; struct cmd_confirm_before_data *cdata;
struct client *c = item->state.c; struct client *c;
char *cmd, *copy, *new_prompt, *ptr; char *cmd, *copy, *new_prompt, *ptr;
const char *prompt; const char *prompt;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if ((prompt = args_get(args, 'p')) != NULL) if ((prompt = args_get(args, 'p')) != NULL)
xasprintf(&new_prompt, "%s ", prompt); xasprintf(&new_prompt, "%s ", prompt);
else { else {

View File

@@ -33,7 +33,7 @@ const struct cmd_entry cmd_copy_mode_entry = {
.args = { "Met:u", 0, 0 }, .args = { "Met:u", 0, 0 },
.usage = "[-Mu] " CMD_TARGET_PANE_USAGE, .usage = "[-Mu] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_copy_mode_exec .exec = cmd_copy_mode_exec
@@ -46,7 +46,7 @@ const struct cmd_entry cmd_clock_mode_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE, .usage = CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_copy_mode_exec .exec = cmd_copy_mode_exec
@@ -56,12 +56,13 @@ static enum cmd_retval
cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item) cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmdq_shared *shared = item->shared;
struct client *c = item->client; struct client *c = item->client;
struct session *s; struct session *s;
struct window_pane *wp = item->state.tflag.wp; struct window_pane *wp = item->target.wp;
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
if ((wp = cmd_mouse_pane(&item->mouse, &s, NULL)) == NULL) if ((wp = cmd_mouse_pane(&shared->mouse, &s, NULL)) == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s) if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@@ -80,7 +81,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
if (wp->mode != NULL && wp->mode != &window_copy_mode) if (wp->mode != NULL && wp->mode != &window_copy_mode)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
window_copy_start_drag(c, &item->mouse); window_copy_start_drag(c, &shared->mouse);
} }
if (wp->mode == &window_copy_mode && args_has(self->args, 'u')) if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
window_copy_pageup(wp, 0); window_copy_pageup(wp, 0);

View File

@@ -37,8 +37,7 @@ const struct cmd_entry cmd_detach_client_entry = {
.usage = "[-aP] [-E shell-command] " .usage = "[-aP] [-E shell-command] "
"[-s target-session] " CMD_TARGET_CLIENT_USAGE, "[-s target-session] " CMD_TARGET_CLIENT_USAGE,
.sflag = CMD_SESSION, .source = { 's', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.tflag = CMD_CLIENT,
.flags = CMD_READONLY, .flags = CMD_READONLY,
.exec = cmd_detach_client_exec .exec = cmd_detach_client_exec
@@ -51,8 +50,6 @@ const struct cmd_entry cmd_suspend_client_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE, .usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = 0, .flags = 0,
.exec = cmd_detach_client_exec .exec = cmd_detach_client_exec
}; };
@@ -61,15 +58,16 @@ static enum cmd_retval
cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item) cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c, *cloop; struct client *c, *cloop;
struct session *s; struct session *s;
enum msgtype msgtype; enum msgtype msgtype;
const char *cmd = args_get(args, 'E'); const char *cmd = args_get(args, 'E');
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (self->entry == &cmd_suspend_client_entry) { if (self->entry == &cmd_suspend_client_entry) {
tty_stop_tty(&c->tty); server_client_suspend(c);
c->flags |= CLIENT_SUSPENDED;
proc_send(c->peer, MSG_SUSPEND, -1, NULL, 0);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -79,7 +77,9 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
msgtype = MSG_DETACH; msgtype = MSG_DETACH;
if (args_has(args, 's')) { if (args_has(args, 's')) {
s = item->state.sflag.s; s = item->source.s;
if (s == NULL)
return (CMD_RETURN_NORMAL);
TAILQ_FOREACH(cloop, &clients, entry) { TAILQ_FOREACH(cloop, &clients, entry) {
if (cloop->session == s) { if (cloop->session == s) {
if (cmd != NULL) if (cmd != NULL)

View File

@@ -43,8 +43,7 @@ const struct cmd_entry cmd_display_message_entry = {
.usage = "[-p] [-c target-client] [-F format] " .usage = "[-p] [-c target-client] [-F format] "
CMD_TARGET_PANE_USAGE " [message]", CMD_TARGET_PANE_USAGE " [message]",
.cflag = CMD_CLIENT_CANFAIL, .target = { 't', CMD_FIND_PANE, 0 },
.tflag = CMD_PANE,
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_display_message_exec .exec = cmd_display_message_exec
@@ -54,10 +53,10 @@ static enum cmd_retval
cmd_display_message_exec(struct cmd *self, struct cmdq_item *item) cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct client *c;
struct session *s = item->state.tflag.s; struct session *s = item->target.s;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl = item->target.wl;
struct window_pane *wp = item->state.tflag.wp; struct window_pane *wp = item->target.wp;
const char *template; const char *template;
char *msg; char *msg;
struct format_tree *ft; struct format_tree *ft;
@@ -66,6 +65,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "only one of -F or argument must be given"); cmdq_error(item, "only one of -F or argument must be given");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
c = cmd_find_client(item, args_get(args, 'c'), 1);
template = args_get(args, 'F'); template = args_get(args, 'F');
if (args->argc != 0) if (args->argc != 0)
@@ -73,7 +73,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
if (template == NULL) if (template == NULL)
template = DISPLAY_MESSAGE_TEMPLATE; template = DISPLAY_MESSAGE_TEMPLATE;
ft = format_create(item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, c, s, wl, wp); format_defaults(ft, c, s, wl, wp);
msg = format_expand_time(ft, template, time(NULL)); msg = format_expand_time(ft, template, time(NULL));

View File

@@ -40,8 +40,6 @@ const struct cmd_entry cmd_display_panes_entry = {
.args = { "t:", 0, 1 }, .args = { "t:", 0, 1 },
.usage = CMD_TARGET_CLIENT_USAGE, .usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_display_panes_exec .exec = cmd_display_panes_exec
}; };
@@ -50,7 +48,10 @@ static enum cmd_retval
cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item) cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct client *c;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (c->identify_callback != NULL) if (c->identify_callback != NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -54,7 +54,7 @@ const struct cmd_entry cmd_find_window_entry = {
.args = { "F:CNt:T", 1, 4 }, .args = { "F:CNt:T", 1, 4 },
.usage = "[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string", .usage = "[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string",
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_find_window_exec .exec = cmd_find_window_exec
@@ -142,10 +142,11 @@ static enum cmd_retval
cmd_find_window_exec(struct cmd *self, struct cmdq_item *item) cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct cmd_find_state *current = &item->shared->current;
struct client *c = cmd_find_client(item, NULL, 1);
struct window_choose_data *cdata; struct window_choose_data *cdata;
struct session *s = item->state.tflag.s; struct session *s = item->target.s;
struct winlink *wl = item->state.tflag.wl, *wm; struct winlink *wl = item->target.wl, *wm;
struct cmd_find_window_list find_list; struct cmd_find_window_list find_list;
struct cmd_find_window_data *find_data; struct cmd_find_window_data *find_data;
struct cmd_find_window_data *find_data1; struct cmd_find_window_data *find_data1;
@@ -177,8 +178,10 @@ cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
} }
if (TAILQ_NEXT(TAILQ_FIRST(&find_list), entry) == NULL) { if (TAILQ_NEXT(TAILQ_FIRST(&find_list), entry) == NULL) {
if (session_select(s, TAILQ_FIRST(&find_list)->wl->idx) == 0) if (session_select(s, TAILQ_FIRST(&find_list)->wl->idx) == 0) {
cmd_find_from_session(current, s);
server_redraw_session(s); server_redraw_session(s);
}
recalculate_sizes(); recalculate_sizes();
goto out; goto out;
} }

View File

@@ -26,19 +26,12 @@
#include "tmux.h" #include "tmux.h"
static struct session *cmd_find_try_TMUX(struct client *, struct window *);
static int cmd_find_client_better(struct client *, struct client *);
static struct client *cmd_find_best_client(struct client **, u_int);
static int cmd_find_session_better(struct session *, struct session *, static int cmd_find_session_better(struct session *, struct session *,
int); int);
static struct session *cmd_find_best_session(struct session **, u_int, int); static struct session *cmd_find_best_session(struct session **, u_int, int);
static int cmd_find_best_session_with_window(struct cmd_find_state *); static int cmd_find_best_session_with_window(struct cmd_find_state *);
static int cmd_find_best_winlink_with_window(struct cmd_find_state *); static int cmd_find_best_winlink_with_window(struct cmd_find_state *);
static int cmd_find_current_session_with_client(struct cmd_find_state *);
static int cmd_find_current_session(struct cmd_find_state *);
static struct client *cmd_find_current_client(struct cmdq_item *);
static const char *cmd_find_map_table(const char *[][2], const char *); static const char *cmd_find_map_table(const char *[][2], const char *);
static int cmd_find_get_session(struct cmd_find_state *, const char *); static int cmd_find_get_session(struct cmd_find_state *, const char *);
@@ -83,13 +76,12 @@ static const char *cmd_find_pane_table[][2] = {
/* Get session from TMUX if present. */ /* Get session from TMUX if present. */
static struct session * static struct session *
cmd_find_try_TMUX(struct client *c, struct window *w) cmd_find_try_TMUX(struct client *c)
{ {
struct environ_entry *envent; struct environ_entry *envent;
char tmp[256]; char tmp[256];
long long pid; long long pid;
u_int session; u_int session;
struct session *s;
envent = environ_find(c->environ, "TMUX"); envent = environ_find(c->environ, "TMUX");
if (envent == NULL) if (envent == NULL)
@@ -99,13 +91,8 @@ cmd_find_try_TMUX(struct client *c, struct window *w)
return (NULL); return (NULL);
if (pid != getpid()) if (pid != getpid())
return (NULL); return (NULL);
log_debug("client %p TMUX is %s (session @%u)", c, envent->value, log_debug("client %p TMUX %s (session @%u)", c, envent->value, session);
session); return (session_find_by_id(session));
s = session_find_by_id(session);
if (s == NULL || (w != NULL && !session_has(s, w)))
return (NULL);
return (s);
} }
/* Is this client better? */ /* Is this client better? */
@@ -117,28 +104,23 @@ cmd_find_client_better(struct client *c, struct client *than)
return (timercmp(&c->activity_time, &than->activity_time, >)); return (timercmp(&c->activity_time, &than->activity_time, >));
} }
/* Find best client from a list, or all if list is NULL. */ /* Find best client for session. */
static struct client * static struct client *
cmd_find_best_client(struct client **clist, u_int csize) cmd_find_best_client(struct session *s)
{ {
struct client *c_loop, *c; struct client *c_loop, *c;
u_int i;
if (s->flags & SESSION_UNATTACHED)
s = NULL;
c = NULL; c = NULL;
if (clist != NULL) { TAILQ_FOREACH(c_loop, &clients, entry) {
for (i = 0; i < csize; i++) { if (c_loop->session == NULL)
if (clist[i]->session == NULL) continue;
continue; if (s != NULL && c_loop->session != s)
if (cmd_find_client_better(clist[i], c)) continue;
c = clist[i]; if (cmd_find_client_better(c_loop, c))
} c = c_loop;
} else {
TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session == NULL)
continue;
if (cmd_find_client_better(c_loop, c))
c = c_loop;
}
} }
return (c); return (c);
} }
@@ -191,12 +173,6 @@ cmd_find_best_session_with_window(struct cmd_find_state *fs)
u_int ssize; u_int ssize;
struct session *s; struct session *s;
if (fs->item != NULL && fs->item->client != NULL) {
fs->s = cmd_find_try_TMUX(fs->item->client, fs->w);
if (fs->s != NULL)
return (cmd_find_best_winlink_with_window(fs));
}
ssize = 0; ssize = 0;
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
if (!session_has(s, fs->w)) if (!session_has(s, fs->w))
@@ -244,146 +220,6 @@ cmd_find_best_winlink_with_window(struct cmd_find_state *fs)
return (0); return (0);
} }
/* Find current session when we have an unattached client. */
static int
cmd_find_current_session_with_client(struct cmd_find_state *fs)
{
struct window_pane *wp;
/*
* If this is running in a pane, we can use that to limit the list of
* sessions to those containing that pane (we still use the current
* window in the best session).
*/
if (fs->item != NULL) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
if (strcmp(wp->tty, fs->item->client->ttyname) == 0)
break;
}
} else
wp = NULL;
/* Not running in a pane. We know nothing. Find the best session. */
if (wp == NULL)
goto unknown_pane;
/* Find the best session and winlink containing this pane. */
fs->w = wp->window;
if (cmd_find_best_session_with_window(fs) != 0) {
if (wp != NULL) {
/*
* The window may have been destroyed but the pane
* still on all_window_panes due to something else
* holding a reference.
*/
goto unknown_pane;
}
return (-1);
}
/* Use the current window and pane from this session. */
fs->wl = fs->s->curw;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = fs->w->active;
return (0);
unknown_pane:
fs->s = NULL;
if (fs->item != NULL)
fs->s = cmd_find_try_TMUX(fs->item->client, NULL);
if (fs->s == NULL)
fs->s = cmd_find_best_session(NULL, 0, fs->flags);
if (fs->s == NULL)
return (-1);
fs->wl = fs->s->curw;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = fs->w->active;
return (0);
}
/*
* Work out the best current state. If this function succeeds, the state is
* guaranteed to be completely filled in.
*/
static int
cmd_find_current_session(struct cmd_find_state *fs)
{
/* If we know the current client, use it. */
if (fs->item != NULL && fs->item->client != NULL) {
log_debug("%s: have client %p%s", __func__, fs->item->client,
fs->item->client->session == NULL ? "" : " (with session)");
if (fs->item->client->session == NULL)
return (cmd_find_current_session_with_client(fs));
fs->s = fs->item->client->session;
fs->wl = fs->s->curw;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = fs->w->active;
return (0);
}
/* We know nothing, find the best session and client. */
fs->s = cmd_find_best_session(NULL, 0, fs->flags);
if (fs->s == NULL)
return (-1);
fs->wl = fs->s->curw;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = fs->w->active;
return (0);
}
/* Work out the best current client. */
static struct client *
cmd_find_current_client(struct cmdq_item *item)
{
struct cmd_find_state current;
struct session *s;
struct client *c, **clist = NULL;
u_int csize;
/* If the queue client has a session, use it. */
if (item->client != NULL && item->client->session != NULL) {
log_debug("%s: using item %p client %p", __func__, item,
item->client);
return (item->client);
}
/* Otherwise find the current session. */
cmd_find_clear_state(&current, item, 0);
if (cmd_find_current_session(&current) != 0)
return (NULL);
/* If it is attached, find the best of it's clients. */
s = current.s;
log_debug("%s: current session $%u %s", __func__, s->id, s->name);
if (~s->flags & SESSION_UNATTACHED) {
csize = 0;
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != s)
continue;
clist = xreallocarray(clist, csize + 1, sizeof *clist);
clist[csize++] = c;
}
if (csize != 0) {
c = cmd_find_best_client(clist, csize);
if (c != NULL) {
free(clist);
return (c);
}
}
free(clist);
}
/* Otherwise pick best of all clients. */
return (cmd_find_best_client(NULL, 0));
}
/* Maps string in table. */ /* Maps string in table. */
static const char * static const char *
cmd_find_map_table(const char *table[][2], const char *s) cmd_find_map_table(const char *table[][2], const char *s)
@@ -796,18 +632,16 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
/* Clear state. */ /* Clear state. */
void void
cmd_find_clear_state(struct cmd_find_state *fs, struct cmdq_item *item, cmd_find_clear_state(struct cmd_find_state *fs, int flags)
int flags)
{ {
memset(fs, 0, sizeof *fs); memset(fs, 0, sizeof *fs);
fs->item = item;
fs->flags = flags; fs->flags = flags;
fs->idx = -1; fs->idx = -1;
} }
/* Check if state is empty/ */ /* Check if state is empty. */
int int
cmd_find_empty_state(struct cmd_find_state *fs) cmd_find_empty_state(struct cmd_find_state *fs)
{ {
@@ -878,10 +712,10 @@ cmd_find_log_state(const char *prefix, struct cmd_find_state *fs)
} }
/* Find state from a session. */ /* Find state from a session. */
int void
cmd_find_from_session(struct cmd_find_state *fs, struct session *s) cmd_find_from_session(struct cmd_find_state *fs, struct session *s)
{ {
cmd_find_clear_state(fs, NULL, 0); cmd_find_clear_state(fs, 0);
fs->s = s; fs->s = s;
fs->wl = fs->s->curw; fs->wl = fs->s->curw;
@@ -889,23 +723,20 @@ cmd_find_from_session(struct cmd_find_state *fs, struct session *s)
fs->wp = fs->w->active; fs->wp = fs->w->active;
cmd_find_log_state(__func__, fs); cmd_find_log_state(__func__, fs);
return (0);
} }
/* Find state from a winlink. */ /* Find state from a winlink. */
int void
cmd_find_from_winlink(struct cmd_find_state *fs, struct session *s, cmd_find_from_winlink(struct cmd_find_state *fs, struct winlink *wl)
struct winlink *wl)
{ {
cmd_find_clear_state(fs, NULL, 0); cmd_find_clear_state(fs, 0);
fs->s = s; fs->s = wl->session;
fs->wl = wl; fs->wl = wl;
fs->w = wl->window; fs->w = wl->window;
fs->wp = wl->window->active; fs->wp = wl->window->active;
cmd_find_log_state(__func__, fs); cmd_find_log_state(__func__, fs);
return (0);
} }
/* Find state from a session and window. */ /* Find state from a session and window. */
@@ -913,12 +744,14 @@ int
cmd_find_from_session_window(struct cmd_find_state *fs, struct session *s, cmd_find_from_session_window(struct cmd_find_state *fs, struct session *s,
struct window *w) struct window *w)
{ {
cmd_find_clear_state(fs, NULL, 0); cmd_find_clear_state(fs, 0);
fs->s = s; fs->s = s;
fs->w = w; fs->w = w;
if (cmd_find_best_winlink_with_window(fs) != 0) if (cmd_find_best_winlink_with_window(fs) != 0) {
cmd_find_clear_state(fs, 0);
return (-1); return (-1);
}
fs->wp = fs->w->active; fs->wp = fs->w->active;
cmd_find_log_state(__func__, fs); cmd_find_log_state(__func__, fs);
@@ -929,60 +762,200 @@ cmd_find_from_session_window(struct cmd_find_state *fs, struct session *s,
int int
cmd_find_from_window(struct cmd_find_state *fs, struct window *w) cmd_find_from_window(struct cmd_find_state *fs, struct window *w)
{ {
cmd_find_clear_state(fs, NULL, 0); cmd_find_clear_state(fs, 0);
fs->w = w; fs->w = w;
if (cmd_find_best_session_with_window(fs) != 0) if (cmd_find_best_session_with_window(fs) != 0) {
cmd_find_clear_state(fs, 0);
return (-1); return (-1);
if (cmd_find_best_winlink_with_window(fs) != 0) }
if (cmd_find_best_winlink_with_window(fs) != 0) {
cmd_find_clear_state(fs, 0);
return (-1); return (-1);
}
fs->wp = fs->w->active; fs->wp = fs->w->active;
cmd_find_log_state(__func__, fs); cmd_find_log_state(__func__, fs);
return (0); return (0);
} }
/* Find state from a winlink and pane. */
void
cmd_find_from_winlink_pane(struct cmd_find_state *fs, struct winlink *wl,
struct window_pane *wp)
{
cmd_find_clear_state(fs, 0);
fs->s = wl->session;
fs->wl = wl;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = wp;
cmd_find_log_state(__func__, fs);
}
/* Find state from a pane. */ /* Find state from a pane. */
int int
cmd_find_from_pane(struct cmd_find_state *fs, struct window_pane *wp) cmd_find_from_pane(struct cmd_find_state *fs, struct window_pane *wp)
{ {
if (cmd_find_from_window(fs, wp->window) != 0) if (cmd_find_from_window(fs, wp->window) != 0)
return (-1); return (-1);
if (window_pane_outside(wp)) if (window_pane_outside(wp)) {
cmd_find_clear_state(fs, 0);
return (-1); return (-1);
}
fs->wp = wp; fs->wp = wp;
cmd_find_log_state(__func__, fs); cmd_find_log_state(__func__, fs);
return (0); return (0);
} }
/* Find current state. */ /* Find state from nothing. */
int int
cmd_find_current(struct cmd_find_state *fs, struct cmdq_item *item, int flags) cmd_find_from_nothing(struct cmd_find_state *fs)
{ {
cmd_find_clear_state(fs, item, flags); cmd_find_clear_state(fs, 0);
if (cmd_find_current_session(fs) != 0) {
if (~flags & CMD_FIND_QUIET) fs->s = cmd_find_best_session(NULL, 0, fs->flags);
cmdq_error(item, "no current session"); if (fs->s == NULL) {
cmd_find_clear_state(fs, 0);
return (-1); return (-1);
} }
fs->wl = fs->s->curw;
fs->idx = fs->wl->idx;
fs->w = fs->wl->window;
fs->wp = fs->w->active;
cmd_find_log_state(__func__, fs);
return (0); return (0);
} }
/* Find state from mouse. */
int
cmd_find_from_mouse(struct cmd_find_state *fs, struct mouse_event *m)
{
cmd_find_clear_state(fs, 0);
if (!m->valid)
return (-1);
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
if (fs->wp == NULL) {
cmd_find_clear_state(fs, 0);
return (-1);
}
fs->w = fs->wl->window;
cmd_find_log_state(__func__, fs);
return (0);
}
/* Find state from client. */
int
cmd_find_from_client(struct cmd_find_state *fs, struct client *c)
{
struct session *s;
struct winlink *wl;
struct window_pane *wp;
/* If no client, treat as from nothing. */
if (c == NULL)
return (cmd_find_from_nothing(fs));
/* If this is an attached client, all done. */
if (c->session != NULL) {
cmd_find_from_session(fs, c->session);
return (0);
}
cmd_find_clear_state(fs, 0);
/*
* If this is an unattached client running in a pane, we can use that
* to limit the list of sessions to those containing that pane.
*/
RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
if (strcmp(wp->tty, c->ttyname) == 0)
break;
}
if (wp == NULL)
goto unknown_pane;
/* If we have a session in TMUX, see if it has this pane. */
s = cmd_find_try_TMUX(c);
if (s != NULL) {
RB_FOREACH(wl, winlinks, &s->windows) {
if (window_has_pane(wl->window, wp))
break;
}
if (wl != NULL) {
fs->s = s;
fs->wl = s->curw; /* use current session */
fs->w = fs->wl->window;
fs->wp = fs->w->active; /* use active pane */
cmd_find_log_state(__func__, fs);
return (0);
}
}
/*
* Don't have a session, or it doesn't have this pane. Try all
* sessions.
*/
fs->w = wp->window;
if (cmd_find_best_session_with_window(fs) != 0) {
if (wp != NULL) {
/*
* The window may have been destroyed but the pane
* still on all_window_panes due to something else
* holding a reference.
*/
goto unknown_pane;
}
cmd_find_clear_state(fs, 0);
return (-1);
}
fs->wl = fs->s->curw;
fs->w = fs->wl->window;
fs->wp = fs->w->active; /* use active pane */
cmd_find_log_state(__func__, fs);
return (0);
unknown_pane:
/*
* We're not running in a known pane, but maybe this client has TMUX
* in the environment. That'd give us a session.
*/
s = cmd_find_try_TMUX(c);
if (s != NULL) {
cmd_find_from_session(fs, s);
return (0);
}
/* Otherwise we need to guess. */
return (cmd_find_from_nothing(fs));
}
/* /*
* Split target into pieces and resolve for the given type. Fills in the given * Split target into pieces and resolve for the given type. Fills in the given
* state. Returns 0 on success or -1 on error. * state. Returns 0 on success or -1 on error.
*/ */
int int
cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current, cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
struct cmdq_item *item, const char *target, enum cmd_find_type type, const char *target, enum cmd_find_type type, int flags)
int flags)
{ {
struct mouse_event *m; struct mouse_event *m;
struct cmd_find_state current;
char *colon, *period, *copy = NULL; char *colon, *period, *copy = NULL;
const char *session, *window, *pane; const char *session, *window, *pane;
int window_only = 0, pane_only = 0; int window_only = 0, pane_only = 0;
/* Can fail flag implies quiet. */
if (flags & CMD_FIND_CANFAIL)
flags |= CMD_FIND_QUIET;
/* Log the arguments. */ /* Log the arguments. */
if (target == NULL) if (target == NULL)
log_debug("%s: target none, type %d", __func__, type); log_debug("%s: target none, type %d", __func__, type);
@@ -991,21 +964,21 @@ cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
log_debug("%s: item %p, flags %#x", __func__, item, flags); log_debug("%s: item %p, flags %#x", __func__, item, flags);
/* Clear new state. */ /* Clear new state. */
cmd_find_clear_state(fs, item, flags); cmd_find_clear_state(fs, flags);
/* Find current state. */ /* Find current state. */
if (server_check_marked() && (flags & CMD_FIND_DEFAULT_MARKED)) { if (server_check_marked() && (flags & CMD_FIND_DEFAULT_MARKED)) {
fs->current = &marked_pane; fs->current = &marked_pane;
log_debug("%s: current is marked pane", __func__); log_debug("%s: current is marked pane", __func__);
} else if (cmd_find_valid_state(&item->current)) { } else if (cmd_find_valid_state(&item->shared->current)) {
fs->current = &item->current; fs->current = &item->shared->current;
log_debug("%s: current is from queue", __func__); log_debug("%s: current is from queue", __func__);
} else { } else if (cmd_find_from_client(&current, item->client) == 0) {
fs->current = current; fs->current = &current;
log_debug("%s: current is from argument", __func__); log_debug("%s: current is from client", __func__);
} } else
if (!cmd_find_empty_state(fs->current) && goto error;
!cmd_find_valid_state(fs->current)) if (!cmd_find_valid_state(fs->current))
fatalx("invalid current find state"); fatalx("invalid current find state");
/* An empty or NULL target is the current. */ /* An empty or NULL target is the current. */
@@ -1014,7 +987,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
/* Mouse target is a plain = or {mouse}. */ /* Mouse target is a plain = or {mouse}. */
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) { if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
m = &item->mouse; m = &item->shared->mouse;
switch (type) { switch (type) {
case CMD_FIND_PANE: case CMD_FIND_PANE:
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl); fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
@@ -1125,8 +1098,8 @@ cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
if (pane != NULL) if (pane != NULL)
pane = cmd_find_map_table(cmd_find_pane_table, pane); pane = cmd_find_map_table(cmd_find_pane_table, pane);
log_debug("target %s (flags %#x): session=%s, window=%s, pane=%s", log_debug("%s: target %s (flags %#x): session=%s, window=%s, pane=%s",
target, flags, session == NULL ? "none" : session, __func__, target, flags, session == NULL ? "none" : session,
window == NULL ? "none" : window, pane == NULL ? "none" : pane); window == NULL ? "none" : window, pane == NULL ? "none" : pane);
/* No pane is allowed if want an index. */ /* No pane is allowed if want an index. */
@@ -1220,6 +1193,8 @@ error:
log_debug("%s: error", __func__); log_debug("%s: error", __func__);
free(copy); free(copy);
if (flags & CMD_FIND_CANFAIL)
return (0);
return (-1); return (-1);
found: found:
@@ -1250,12 +1225,20 @@ struct client *
cmd_find_client(struct cmdq_item *item, const char *target, int quiet) cmd_find_client(struct cmdq_item *item, const char *target, int quiet)
{ {
struct client *c; struct client *c;
struct session *s;
char *copy; char *copy;
size_t size; size_t size;
/* A NULL argument means the current client. */ /* A NULL argument means the current client. */
if (item != NULL && target == NULL) { if (target == NULL) {
c = cmd_find_current_client(item); c = NULL;
if (item->client != NULL && item->client->session != NULL)
c = item->client;
else {
s = cmd_find_best_session(NULL, 0, CMD_FIND_QUIET);
if (s != NULL)
c = cmd_find_best_client(s);
}
if (c == NULL && !quiet) if (c == NULL && !quiet)
cmdq_error(item, "no current client"); cmdq_error(item, "no current client");
log_debug("%s: no target, return %p", __func__, c); log_debug("%s: no target, return %p", __func__, c);

View File

@@ -31,7 +31,6 @@
static enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmdq_item *); static enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmdq_item *);
static enum cmd_retval cmd_if_shell_error(struct cmdq_item *, void *);
static void cmd_if_shell_callback(struct job *); static void cmd_if_shell_callback(struct job *);
static void cmd_if_shell_free(void *); static void cmd_if_shell_free(void *);
@@ -43,7 +42,7 @@ const struct cmd_entry cmd_if_shell_entry = {
.usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command " .usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command "
"[command]", "[command]",
.tflag = CMD_PANE_CANFAIL, .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = 0, .flags = 0,
.exec = cmd_if_shell_exec .exec = cmd_if_shell_exec
@@ -65,14 +64,15 @@ static enum cmd_retval
cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item) cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmdq_shared *shared = item->shared;
struct cmd_if_shell_data *cdata; struct cmd_if_shell_data *cdata;
char *shellcmd, *cmd, *cause; char *shellcmd, *cmd, *cause;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmdq_item *new_item; struct cmdq_item *new_item;
struct client *c = item->state.c; struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->state.tflag.s; struct session *s = item->target.s;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl = item->target.wl;
struct window_pane *wp = item->state.tflag.wp; struct window_pane *wp = item->target.wp;
const char *cwd; const char *cwd;
if (item->client != NULL && item->client->session == NULL) if (item->client != NULL && item->client->session == NULL)
@@ -100,7 +100,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
} }
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
new_item = cmdq_get_command(cmdlist, NULL, &item->mouse, 0); new_item = cmdq_get_command(cmdlist, NULL, &shared->mouse, 0);
cmdq_insert_after(item, new_item); cmdq_insert_after(item, new_item);
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@@ -119,16 +119,17 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->cmd_else = NULL; cdata->cmd_else = NULL;
cdata->client = item->client; cdata->client = item->client;
cdata->client->references++; if (cdata->client != NULL)
cdata->client->references++;
if (!args_has(args, 'b')) if (!args_has(args, 'b'))
cdata->item = item; cdata->item = item;
else else
cdata->item = NULL; cdata->item = NULL;
memcpy(&cdata->mouse, &item->mouse, sizeof cdata->mouse); memcpy(&cdata->mouse, &shared->mouse, sizeof cdata->mouse);
job_run(shellcmd, s, cwd, cmd_if_shell_callback, cmd_if_shell_free, job_run(shellcmd, s, cwd, NULL, cmd_if_shell_callback,
cdata); cmd_if_shell_free, cdata);
free(shellcmd); free(shellcmd);
if (args_has(args, 'b')) if (args_has(args, 'b'))
@@ -136,17 +137,6 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
static enum cmd_retval
cmd_if_shell_error(struct cmdq_item *item, void *data)
{
char *error = data;
cmdq_error(item, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static void static void
cmd_if_shell_callback(struct job *job) cmd_if_shell_callback(struct job *job)
{ {
@@ -166,10 +156,10 @@ cmd_if_shell_callback(struct job *job)
cmdlist = cmd_string_parse(cmd, file, line, &cause); cmdlist = cmd_string_parse(cmd, file, line, &cause);
if (cmdlist == NULL) { if (cmdlist == NULL) {
if (cause != NULL) if (cause != NULL && cdata->item != NULL)
new_item = cmdq_get_callback(cmd_if_shell_error, cause); cmdq_error(cdata->item, "%s", cause);
else free(cause);
new_item = NULL; new_item = NULL;
} else { } else {
new_item = cmdq_get_command(cmdlist, NULL, &cdata->mouse, 0); new_item = cmdq_get_command(cmdlist, NULL, &cdata->mouse, 0);
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
@@ -192,7 +182,8 @@ cmd_if_shell_free(void *data)
{ {
struct cmd_if_shell_data *cdata = data; struct cmd_if_shell_data *cdata = data;
server_client_unref(cdata->client); if (cdata->client != NULL)
server_client_unref(cdata->client);
free(cdata->cmd_else); free(cdata->cmd_else);
free(cdata->cmd_if); free(cdata->cmd_if);

View File

@@ -37,8 +37,8 @@ const struct cmd_entry cmd_join_pane_entry = {
.args = { "bdhvp:l:s:t:", 0, 0 }, .args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE, .usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.sflag = CMD_PANE_MARKED, .source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_join_pane_exec .exec = cmd_join_pane_exec
@@ -51,8 +51,8 @@ const struct cmd_entry cmd_move_pane_entry = {
.args = { "bdhvp:l:s:t:", 0, 0 }, .args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE, .usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.sflag = CMD_PANE, .source = { 's', CMD_FIND_PANE, 0 },
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_join_pane_exec .exec = cmd_join_pane_exec
@@ -62,6 +62,7 @@ static enum cmd_retval
cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
struct session *dst_s; struct session *dst_s;
struct winlink *src_wl, *dst_wl; struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w; struct window *src_w, *dst_w;
@@ -77,15 +78,15 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
else else
not_same_window = 0; not_same_window = 0;
dst_s = item->state.tflag.s; dst_s = item->target.s;
dst_wl = item->state.tflag.wl; dst_wl = item->target.wl;
dst_wp = item->state.tflag.wp; dst_wp = item->target.wp;
dst_w = dst_wl->window; dst_w = dst_wl->window;
dst_idx = dst_wl->idx; dst_idx = dst_wl->idx;
server_unzoom_window(dst_w); server_unzoom_window(dst_w);
src_wl = item->state.sflag.wl; src_wl = item->source.wl;
src_wp = item->state.sflag.wp; src_wp = item->source.wp;
src_w = src_wl->window; src_w = src_wl->window;
server_unzoom_window(src_w); server_unzoom_window(src_w);
@@ -145,6 +146,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 'd')) { if (!args_has(args, 'd')) {
window_set_active_pane(dst_w, src_wp); window_set_active_pane(dst_w, src_wp);
session_select(dst_s, dst_idx); session_select(dst_s, dst_idx);
cmd_find_from_session(current, dst_s);
server_redraw_session(dst_s); server_redraw_session(dst_s);
} else } else
server_status_session(dst_s); server_status_session(dst_s);

View File

@@ -35,7 +35,7 @@ const struct cmd_entry cmd_kill_pane_entry = {
.args = { "at:", 0, 0 }, .args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_PANE_USAGE, .usage = "[-a] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_kill_pane_exec .exec = cmd_kill_pane_exec
@@ -44,8 +44,8 @@ const struct cmd_entry cmd_kill_pane_entry = {
static enum cmd_retval static enum cmd_retval
cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct winlink *wl = item->state.tflag.wl; struct winlink *wl = item->target.wl;
struct window_pane *loopwp, *tmpwp, *wp = item->state.tflag.wp; struct window_pane *loopwp, *tmpwp, *wp = item->target.wp;
server_unzoom_window(wl->window); server_unzoom_window(wl->window);

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_kill_session_entry = {
.args = { "aCt:", 0, 0 }, .args = { "aCt:", 0, 0 },
.usage = "[-aC] " CMD_TARGET_SESSION_USAGE, .usage = "[-aC] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0, .flags = 0,
.exec = cmd_kill_session_exec .exec = cmd_kill_session_exec
@@ -49,7 +49,7 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
struct session *s, *sloop, *stmp; struct session *s, *sloop, *stmp;
struct winlink *wl; struct winlink *wl;
s = item->state.tflag.s; s = item->target.s;
if (args_has(args, 'C')) { if (args_has(args, 'C')) {
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {

View File

@@ -33,7 +33,7 @@ const struct cmd_entry cmd_kill_window_entry = {
.args = { "at:", 0, 0 }, .args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_WINDOW_USAGE, .usage = "[-a] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_kill_window_exec .exec = cmd_kill_window_exec
@@ -46,7 +46,7 @@ const struct cmd_entry cmd_unlink_window_entry = {
.args = { "kt:", 0, 0 }, .args = { "kt:", 0, 0 },
.usage = "[-k] " CMD_TARGET_WINDOW_USAGE, .usage = "[-k] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_kill_window_exec .exec = cmd_kill_window_exec
@@ -56,9 +56,9 @@ static enum cmd_retval
cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item) cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl, *wl2, *wl3; struct winlink *wl = item->target.wl, *wl2, *wl3;
struct window *w = wl->window; struct window *w = wl->window;
struct session *s = item->state.tflag.s; struct session *s = item->target.s;
if (self->entry == &cmd_unlink_window_entry) { if (self->entry == &cmd_unlink_window_entry) {
if (!args_has(self->args, 'k') && !session_is_linked(s, w)) { if (!args_has(self->args, 'k') && !session_is_linked(s, w)) {

View File

@@ -57,7 +57,7 @@ cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item)
pb = NULL; pb = NULL;
while ((pb = paste_walk(pb)) != NULL) { while ((pb = paste_walk(pb)) != NULL) {
ft = format_create(item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults_paste_buffer(ft, pb); format_defaults_paste_buffer(ft, pb);
line = format_expand(ft, template); line = format_expand(ft, template);

View File

@@ -42,7 +42,7 @@ const struct cmd_entry cmd_list_clients_entry = {
.args = { "F:t:", 0, 0 }, .args = { "F:t:", 0, 0 },
.usage = "[-F format] " CMD_TARGET_SESSION_USAGE, .usage = "[-F format] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_READONLY|CMD_AFTERHOOK, .flags = CMD_READONLY|CMD_AFTERHOOK,
.exec = cmd_list_clients_exec .exec = cmd_list_clients_exec
@@ -60,7 +60,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
char *line; char *line;
if (args_has(args, 't')) if (args_has(args, 't'))
s = item->state.tflag.s; s = item->target.s;
else else
s = NULL; s = NULL;
@@ -72,7 +72,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
if (c->session == NULL || (s != NULL && s != c->session)) if (c->session == NULL || (s != NULL && s != c->session))
continue; continue;
ft = format_create(item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", idx); format_add(ft, "line", "%u", idx);
format_defaults(ft, c, NULL, NULL, NULL); format_defaults(ft, c, NULL, NULL, NULL);

View File

@@ -81,7 +81,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
RB_FOREACH(bd, key_bindings, &table->key_bindings) { RB_FOREACH(bd, key_bindings, &table->key_bindings) {
key = key_string_lookup_key(bd->key); key = key_string_lookup_key(bd->key);
if (bd->can_repeat) if (bd->flags & KEY_BINDING_REPEAT)
repeat = 1; repeat = 1;
width = utf8_cstrwidth(table->name); width = utf8_cstrwidth(table->name);
@@ -101,7 +101,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
if (!repeat) if (!repeat)
r = ""; r = "";
else if (bd->can_repeat) else if (bd->flags & KEY_BINDING_REPEAT)
r = "-r "; r = "-r ";
else else
r = " "; r = " ";
@@ -144,7 +144,7 @@ cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
"#{command_list_usage}"; "#{command_list_usage}";
} }
ft = format_create(item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, NULL, NULL, NULL, NULL); format_defaults(ft, NULL, NULL, NULL, NULL);
for (entryp = cmd_table; *entryp != NULL; entryp++) { for (entryp = cmd_table; *entryp != NULL; entryp++) {

View File

@@ -41,7 +41,7 @@ const struct cmd_entry cmd_list_panes_entry = {
.args = { "asF:t:", 0, 0 }, .args = { "asF:t:", 0, 0 },
.usage = "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE, .usage = "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_list_panes_exec .exec = cmd_list_panes_exec
@@ -51,8 +51,8 @@ static enum cmd_retval
cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item) cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s = item->state.tflag.s; struct session *s = item->target.s;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl = item->target.wl;
if (args_has(args, 'a')) if (args_has(args, 'a'))
cmd_list_panes_server(self, item); cmd_list_panes_server(self, item);
@@ -123,7 +123,7 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
n = 0; n = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) { TAILQ_FOREACH(wp, &wl->window->panes, entry) {
ft = format_create(item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, wp); format_defaults(ft, NULL, s, wl, wp);

View File

@@ -65,7 +65,7 @@ cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
n = 0; n = 0;
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
ft = format_create(item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, NULL, NULL); format_defaults(ft, NULL, s, NULL, NULL);

View File

@@ -52,7 +52,7 @@ const struct cmd_entry cmd_list_windows_entry = {
.args = { "F:at:", 0, 0 }, .args = { "F:at:", 0, 0 },
.usage = "[-a] [-F format] " CMD_TARGET_SESSION_USAGE, .usage = "[-a] [-F format] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_list_windows_exec .exec = cmd_list_windows_exec
@@ -66,7 +66,7 @@ cmd_list_windows_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'a')) if (args_has(args, 'a'))
cmd_list_windows_server(self, item); cmd_list_windows_server(self, item);
else else
cmd_list_windows_session(self, item->state.tflag.s, item, 0); cmd_list_windows_session(self, item->target.s, item, 0);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -86,7 +86,7 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl;
u_int n; u_int n;
struct format_tree *ft; struct format_tree *ft;
const char *template; const char *template;
char *line; char *line;
@@ -105,7 +105,7 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
n = 0; n = 0;
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
ft = format_create(item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, NULL); format_defaults(ft, NULL, s, wl, NULL);

View File

@@ -127,6 +127,7 @@ error:
free(pdata); free(pdata);
if (f != NULL) if (f != NULL)
fclose(f); fclose(f);
free(file);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }

View File

@@ -44,7 +44,7 @@ const struct cmd_entry cmd_lock_session_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE, .usage = CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_lock_server_exec .exec = cmd_lock_server_exec
@@ -57,22 +57,25 @@ const struct cmd_entry cmd_lock_client_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE, .usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_lock_server_exec .exec = cmd_lock_server_exec
}; };
static enum cmd_retval static enum cmd_retval
cmd_lock_server_exec(struct cmd *self, __unused struct cmdq_item *item) cmd_lock_server_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args;
struct client *c;
if (self->entry == &cmd_lock_server_entry) if (self->entry == &cmd_lock_server_entry)
server_lock(); server_lock();
else if (self->entry == &cmd_lock_session_entry) else if (self->entry == &cmd_lock_session_entry)
server_lock_session(item->state.tflag.s); server_lock_session(item->target.s);
else else {
server_lock_client(item->state.c); if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
server_lock_client(c);
}
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -35,8 +35,8 @@ const struct cmd_entry cmd_move_window_entry = {
.args = { "adkrs:t:", 0, 0 }, .args = { "adkrs:t:", 0, 0 },
.usage = "[-dkr] " CMD_SRCDST_WINDOW_USAGE, .usage = "[-dkr] " CMD_SRCDST_WINDOW_USAGE,
.sflag = CMD_WINDOW, .source = { 's', CMD_FIND_WINDOW, 0 },
.tflag = CMD_MOVEW_R, /* -t is special */
.flags = 0, .flags = 0,
.exec = cmd_move_window_exec .exec = cmd_move_window_exec
@@ -49,8 +49,8 @@ const struct cmd_entry cmd_link_window_entry = {
.args = { "adks:t:", 0, 0 }, .args = { "adks:t:", 0, 0 },
.usage = "[-dk] " CMD_SRCDST_WINDOW_USAGE, .usage = "[-dk] " CMD_SRCDST_WINDOW_USAGE,
.sflag = CMD_WINDOW, .source = { 's', CMD_FIND_WINDOW, 0 },
.tflag = CMD_WINDOW_INDEX, /* -t is special */
.flags = 0, .flags = 0,
.exec = cmd_move_window_exec .exec = cmd_move_window_exec
@@ -60,18 +60,31 @@ static enum cmd_retval
cmd_move_window_exec(struct cmd *self, struct cmdq_item *item) cmd_move_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *src = item->state.sflag.s; const char *tflag = args_get(args, 't');
struct session *dst = item->state.tflag.s; struct session *src;
struct winlink *wl = item->state.sflag.wl; struct session *dst;
struct winlink *wl;
char *cause; char *cause;
int idx = item->state.tflag.idx, kflag, dflag, sflag; int idx, kflag, dflag, sflag;
if (args_has(args, 'r')) { if (args_has(args, 'r')) {
session_renumber_windows(dst); if (cmd_find_target(&item->target, item, tflag,
CMD_FIND_SESSION, CMD_FIND_QUIET) != 0)
return (CMD_RETURN_ERROR);
session_renumber_windows(item->target.s);
recalculate_sizes(); recalculate_sizes();
server_status_session(item->target.s);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (cmd_find_target(&item->target, item, tflag, CMD_FIND_WINDOW,
CMD_FIND_WINDOW_INDEX) != 0)
return (CMD_RETURN_ERROR);
src = item->source.s;
dst = item->target.s;
wl = item->source.wl;
idx = item->target.idx;
kflag = args_has(self->args, 'k'); kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd'); dflag = args_has(self->args, 'd');

View File

@@ -44,7 +44,7 @@ const struct cmd_entry cmd_new_session_entry = {
"[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] " "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
"[-y height] [command]", "[-y height] [command]",
.tflag = CMD_SESSION_CANFAIL, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_STARTSERVER, .flags = CMD_STARTSERVER,
.exec = cmd_new_session_exec .exec = cmd_new_session_exec
@@ -57,7 +57,7 @@ const struct cmd_entry cmd_has_session_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE, .usage = CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0, .flags = 0,
.exec = cmd_new_session_exec .exec = cmd_new_session_exec
@@ -83,8 +83,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (self->entry == &cmd_has_session_entry) { if (self->entry == &cmd_has_session_entry) {
/* /*
* cmd_prepare() will fail if the session cannot be found, * cmd_find_target() will fail if the session cannot be found,
* hence always return success here. * so always return success here.
*/ */
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -102,16 +102,9 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
} }
if ((as = session_find(newname)) != NULL) { if ((as = session_find(newname)) != NULL) {
if (args_has(args, 'A')) { if (args_has(args, 'A')) {
/*
* This item is now destined for
* attach-session. Because attach-session will
* have already been prepared, copy this
* session into its tflag so it can be used.
*/
cmd_find_from_session(&item->state.tflag, as);
return (cmd_attach_session(item, return (cmd_attach_session(item,
args_has(args, 'D'), 0, NULL, newname, args_has(args, 'D'),
args_has(args, 'E'))); 0, NULL, args_has(args, 'E')));
} }
cmdq_error(item, "duplicate session: %s", newname); cmdq_error(item, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@@ -121,7 +114,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
/* Is this going to be part of a session group? */ /* Is this going to be part of a session group? */
group = args_get(args, 't'); group = args_get(args, 't');
if (group != NULL) { if (group != NULL) {
groupwith = item->state.tflag.s; groupwith = item->target.s;
if (groupwith == NULL) { if (groupwith == NULL) {
if (!session_check_name(group)) { if (!session_check_name(group)) {
cmdq_error(item, "bad group name: %s", group); cmdq_error(item, "bad group name: %s", group);
@@ -297,7 +290,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
} else if (c->session != NULL) } else if (c->session != NULL)
c->last_session = c->session; c->last_session = c->session;
c->session = s; c->session = s;
if (!item->repeat) if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
status_timer_start(c); status_timer_start(c);
notify_client("client-session-changed", c); notify_client("client-session-changed", c);
@@ -324,8 +317,10 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
free(cp); free(cp);
} }
if (!detached) if (!detached) {
c->flags |= CLIENT_ATTACHED; c->flags |= CLIENT_ATTACHED;
cmd_find_from_session(&item->shared->current, s);
}
if (to_free != NULL) if (to_free != NULL)
free((void *)to_free); free((void *)to_free);

View File

@@ -42,7 +42,7 @@ const struct cmd_entry cmd_new_window_entry = {
.usage = "[-adkP] [-c start-directory] [-F format] [-n window-name] " .usage = "[-adkP] [-c start-directory] [-F format] [-n window-name] "
CMD_TARGET_WINDOW_USAGE " [command]", CMD_TARGET_WINDOW_USAGE " [command]",
.tflag = CMD_WINDOW_INDEX, .target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
.flags = 0, .flags = 0,
.exec = cmd_new_window_exec .exec = cmd_new_window_exec
@@ -52,10 +52,11 @@ static enum cmd_retval
cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s = item->state.tflag.s; struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->state.tflag.wl; struct session *s = item->target.s;
struct client *c = item->state.c; struct winlink *wl = item->target.wl;
int idx = item->state.tflag.idx; struct client *c = cmd_find_client(item, NULL, 1);
int idx = item->target.idx;
const char *cmd, *path, *template, *cwd, *to_free; const char *cmd, *path, *template, *cwd, *to_free;
char **argv, *cause, *cp; char **argv, *cause, *cp;
int argc, detached; int argc, detached;
@@ -132,6 +133,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
} }
if (!detached) { if (!detached) {
session_select(s, wl->idx); session_select(s, wl->idx);
cmd_find_from_winlink(current, wl);
server_redraw_session_group(s); server_redraw_session_group(s);
} else } else
server_status_session_group(s); server_status_session_group(s);
@@ -147,7 +149,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
if (to_free != NULL) if (to_free != NULL)
free((void *)to_free); free((void *)to_free);
cmd_find_from_winlink(&fs, s, wl); cmd_find_from_winlink(&fs, wl);
hooks_insert(s->hooks, item, &fs, "after-new-window"); hooks_insert(s->hooks, item, &fs, "after-new-window");
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -37,7 +37,7 @@ const struct cmd_entry cmd_paste_buffer_entry = {
.usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " " .usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " "
CMD_TARGET_PANE_USAGE, CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_paste_buffer_exec .exec = cmd_paste_buffer_exec
@@ -47,7 +47,7 @@ static enum cmd_retval
cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item) cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp = item->state.tflag.wp; struct window_pane *wp = item->target.wp;
struct paste_buffer *pb; struct paste_buffer *pb;
const char *sepstr, *bufname, *bufdata, *bufend, *line; const char *sepstr, *bufname, *bufdata, *bufend, *line;
size_t seplen, bufsize; size_t seplen, bufsize;

View File

@@ -43,7 +43,7 @@ const struct cmd_entry cmd_pipe_pane_entry = {
.args = { "ot:", 0, 1 }, .args = { "ot:", 0, 1 },
.usage = "[-o] " CMD_TARGET_PANE_USAGE " [command]", .usage = "[-o] " CMD_TARGET_PANE_USAGE " [command]",
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_pipe_pane_exec .exec = cmd_pipe_pane_exec
@@ -53,10 +53,10 @@ static enum cmd_retval
cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct client *c = cmd_find_client(item, NULL, 1);
struct window_pane *wp = item->state.tflag.wp; struct window_pane *wp = item->target.wp;
struct session *s = item->state.tflag.s; struct session *s = item->target.s;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl = item->target.wl;
char *cmd; char *cmd;
int old_fd, pipe_fd[2], null_fd; int old_fd, pipe_fd[2], null_fd;
struct format_tree *ft; struct format_tree *ft;
@@ -89,7 +89,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
} }
/* Expand the command. */ /* Expand the command. */
ft = format_create(item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, c, s, wl, wp); format_defaults(ft, c, s, wl, wp);
cmd = format_expand_time(ft, args->argv[0], time(NULL)); cmd = format_expand_time(ft, args->argv[0], time(NULL));
format_free(ft); format_free(ft);

View File

@@ -102,8 +102,11 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
static void static void
cmdq_remove(struct cmdq_item *item) cmdq_remove(struct cmdq_item *item)
{ {
if (item->formats != NULL) if (item->shared != NULL && --item->shared->references == 0) {
format_free(item->formats); if (item->shared->formats != NULL)
format_free(item->shared->formats);
free(item->shared);
}
if (item->client != NULL) if (item->client != NULL)
server_client_unref(item->client); server_client_unref(item->client);
@@ -150,6 +153,15 @@ cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
struct cmd *cmd; struct cmd *cmd;
u_int group = cmdq_next_group(); u_int group = cmdq_next_group();
char *tmp; char *tmp;
struct cmdq_shared *shared;
shared = xcalloc(1, sizeof *shared);
if (current != NULL)
cmd_find_copy_state(&shared->current, current);
else
cmd_find_clear_state(&shared->current, 0);
if (m != NULL)
memcpy(&shared->mouse, m, sizeof shared->mouse);
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
xasprintf(&tmp, "command[%s]", cmd->entry->name); xasprintf(&tmp, "command[%s]", cmd->entry->name);
@@ -161,13 +173,11 @@ cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
item->group = group; item->group = group;
item->flags = flags; item->flags = flags;
item->shared = shared;
item->cmdlist = cmdlist; item->cmdlist = cmdlist;
item->cmd = cmd; item->cmd = cmd;
if (current != NULL) shared->references++;
cmd_find_copy_state(&item->current, current);
if (m != NULL)
memcpy(&item->mouse, m, sizeof item->mouse);
cmdlist->references++; cmdlist->references++;
if (first == NULL) if (first == NULL)
@@ -179,41 +189,63 @@ cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
return (first); return (first);
} }
/* Fill in flag for a command. */
static enum cmd_retval
cmdq_find_flag(struct cmdq_item *item, struct cmd_find_state *fs,
const struct cmd_entry_flag *flag)
{
const char *value;
if (flag->flag == 0) {
cmd_find_clear_state(fs, 0);
return (CMD_RETURN_NORMAL);
}
value = args_get(item->cmd->args, flag->flag);
if (cmd_find_target(fs, item, value, flag->type, flag->flags) != 0) {
cmd_find_clear_state(fs, 0);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
/* Fire command on command queue. */ /* Fire command on command queue. */
static enum cmd_retval static enum cmd_retval
cmdq_fire_command(struct cmdq_item *item) cmdq_fire_command(struct cmdq_item *item)
{ {
struct client *c = item->client; struct client *c = item->client;
struct cmd *cmd = item->cmd; struct cmd *cmd = item->cmd;
const struct cmd_entry *entry = cmd->entry;
enum cmd_retval retval; enum cmd_retval retval;
const char *name;
struct cmd_find_state *fsp, fs; struct cmd_find_state *fsp, fs;
int flags; int flags;
flags = !!(cmd->flags & CMD_CONTROL); flags = !!(cmd->flags & CMD_CONTROL);
cmdq_guard(item, "begin", flags); cmdq_guard(item, "begin", flags);
if (cmd_prepare_state(cmd, item) != 0) {
retval = CMD_RETURN_ERROR;
goto out;
}
if (item->client == NULL) if (item->client == NULL)
item->client = cmd_find_client(item, NULL, CMD_FIND_QUIET); item->client = cmd_find_client(item, NULL, 1);
retval = cmdq_find_flag(item, &item->source, &entry->source);
retval = cmd->entry->exec(cmd, item); if (retval == CMD_RETURN_ERROR)
goto out;
retval = cmdq_find_flag(item, &item->target, &entry->target);
if (retval == CMD_RETURN_ERROR) if (retval == CMD_RETURN_ERROR)
goto out; goto out;
if (cmd->entry->flags & CMD_AFTERHOOK) { retval = entry->exec(cmd, item);
name = cmd->entry->name; if (retval == CMD_RETURN_ERROR)
if (cmd_find_valid_state(&item->state.tflag)) goto out;
fsp = &item->state.tflag;
else { if (entry->flags & CMD_AFTERHOOK) {
if (cmd_find_current(&fs, item, CMD_FIND_QUIET) != 0) if (cmd_find_valid_state(&item->target))
goto out; fsp = &item->target;
else if (cmd_find_valid_state(&item->shared->current))
fsp = &item->shared->current;
else if (cmd_find_from_client(&fs, item->client) == 0)
fsp = &fs; fsp = &fs;
} else
hooks_insert(fsp->s->hooks, item, fsp, "after-%s", name); goto out;
hooks_insert(fsp->s->hooks, item, fsp, "after-%s", entry->name);
} }
out: out:
@@ -258,19 +290,17 @@ cmdq_fire_callback(struct cmdq_item *item)
void void
cmdq_format(struct cmdq_item *item, const char *key, const char *fmt, ...) cmdq_format(struct cmdq_item *item, const char *key, const char *fmt, ...)
{ {
struct cmdq_shared *shared = item->shared;
va_list ap; va_list ap;
struct cmdq_item *loop;
char *value; char *value;
va_start(ap, fmt); va_start(ap, fmt);
xvasprintf(&value, fmt, ap); xvasprintf(&value, fmt, ap);
va_end(ap); va_end(ap);
for (loop = item; loop != NULL; loop = item->next) { if (shared->formats == NULL)
if (loop->formats == NULL) shared->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
loop->formats = format_create(NULL, FORMAT_NONE, 0); format_add(shared->formats, key, "%s", value);
format_add(loop->formats, key, "%s", value);
}
free(value); free(value);
} }
@@ -319,8 +349,7 @@ cmdq_next(struct client *c)
item->time = time(NULL); item->time = time(NULL);
item->number = ++number; item->number = ++number;
switch (item->type) switch (item->type) {
{
case CMDQ_COMMAND: case CMDQ_COMMAND:
retval = cmdq_fire_command(item); retval = cmdq_fire_command(item);

View File

@@ -34,8 +34,6 @@ const struct cmd_entry cmd_refresh_client_entry = {
.args = { "C:St:", 0, 0 }, .args = { "C:St:", 0, 0 },
.usage = "[-S] [-C size] " CMD_TARGET_CLIENT_USAGE, .usage = "[-S] [-C size] " CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_refresh_client_exec .exec = cmd_refresh_client_exec
}; };
@@ -44,10 +42,13 @@ static enum cmd_retval
cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct client *c;
const char *size; const char *size;
u_int w, h; u_int w, h;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (args_has(args, 'C')) { if (args_has(args, 'C')) {
if ((size = args_get(args, 'C')) == NULL) { if ((size = args_get(args, 'C')) == NULL) {
cmdq_error(item, "missing size"); cmdq_error(item, "missing size");

View File

@@ -37,7 +37,7 @@ const struct cmd_entry cmd_rename_session_entry = {
.args = { "t:", 1, 1 }, .args = { "t:", 1, 1 },
.usage = CMD_TARGET_SESSION_USAGE " new-name", .usage = CMD_TARGET_SESSION_USAGE " new-name",
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_rename_session_exec .exec = cmd_rename_session_exec
@@ -47,7 +47,7 @@ static enum cmd_retval
cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item) cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s = item->state.tflag.s; struct session *s = item->target.s;
const char *newname; const char *newname;
newname = args->argv[0]; newname = args->argv[0];

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_rename_window_entry = {
.args = { "t:", 1, 1 }, .args = { "t:", 1, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " new-name", .usage = CMD_TARGET_WINDOW_USAGE " new-name",
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_rename_window_exec .exec = cmd_rename_window_exec
@@ -46,7 +46,7 @@ static enum cmd_retval
cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item) cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl = item->target.wl;
window_set_name(wl->window, args->argv[0]); window_set_name(wl->window, args->argv[0]);
options_set_number(wl->window->options, "automatic-rename", 0); options_set_number(wl->window->options, "automatic-rename", 0);

View File

@@ -39,7 +39,7 @@ const struct cmd_entry cmd_resize_pane_entry = {
.usage = "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " " .usage = "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
"[adjustment]", "[adjustment]",
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_resize_pane_exec .exec = cmd_resize_pane_exec
@@ -49,23 +49,24 @@ static enum cmd_retval
cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp = item->state.tflag.wp; struct cmdq_shared *shared = item->shared;
struct winlink *wl = item->state.tflag.wl; struct window_pane *wp = item->target.wp;
struct winlink *wl = item->target.wl;
struct window *w = wl->window; struct window *w = wl->window;
struct client *c = item->client; struct client *c = item->client;
struct session *s = item->state.tflag.s; struct session *s = item->target.s;
const char *errstr; const char *errstr;
char *cause; char *cause;
u_int adjust; u_int adjust;
int x, y; int x, y;
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
if (cmd_mouse_window(&item->mouse, &s) == NULL) if (cmd_mouse_window(&shared->mouse, &s) == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s) if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update; c->tty.mouse_drag_update = cmd_resize_pane_mouse_update;
cmd_resize_pane_mouse_update(c, &item->mouse); cmd_resize_pane_mouse_update(c, &shared->mouse);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -37,7 +37,7 @@ const struct cmd_entry cmd_respawn_pane_entry = {
.args = { "kt:", 0, -1 }, .args = { "kt:", 0, -1 },
.usage = "[-k] " CMD_TARGET_PANE_USAGE " [command]", .usage = "[-k] " CMD_TARGET_PANE_USAGE " [command]",
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_respawn_pane_exec .exec = cmd_respawn_pane_exec
@@ -47,10 +47,10 @@ static enum cmd_retval
cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl = item->target.wl;
struct window *w = wl->window; struct window *w = wl->window;
struct window_pane *wp = item->state.tflag.wp; struct window_pane *wp = item->target.wp;
struct session *s = item->state.tflag.s; struct session *s = item->target.s;
struct environ *env; struct environ *env;
const char *path; const char *path;
char *cause; char *cause;
@@ -77,7 +77,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
if (envent != NULL) if (envent != NULL)
path = envent->value; path = envent->value;
env = environ_for_session(s); env = environ_for_session(s, 0);
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env, if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env,
s->tio, &cause) != 0) { s->tio, &cause) != 0) {
cmdq_error(item, "respawn pane failed: %s", cause); cmdq_error(item, "respawn pane failed: %s", cause);

View File

@@ -37,7 +37,7 @@ const struct cmd_entry cmd_respawn_window_entry = {
.args = { "kt:", 0, -1 }, .args = { "kt:", 0, -1 },
.usage = "[-k] " CMD_TARGET_WINDOW_USAGE " [command]", .usage = "[-k] " CMD_TARGET_WINDOW_USAGE " [command]",
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_respawn_window_exec .exec = cmd_respawn_window_exec
@@ -47,8 +47,8 @@ static enum cmd_retval
cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item) cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s = item->state.tflag.s; struct session *s = item->target.s;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl = item->target.wl;
struct window *w = wl->window; struct window *w = wl->window;
struct window_pane *wp; struct window_pane *wp;
struct environ *env; struct environ *env;
@@ -81,7 +81,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
if (envent != NULL) if (envent != NULL)
path = envent->value; path = envent->value;
env = environ_for_session(s); env = environ_for_session(s, 0);
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env, if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env,
s->tio, &cause) != 0) { s->tio, &cause) != 0) {
cmdq_error(item, "respawn window failed: %s", cause); cmdq_error(item, "respawn window failed: %s", cause);

View File

@@ -34,7 +34,7 @@ const struct cmd_entry cmd_rotate_window_entry = {
.args = { "Dt:U", 0, 0 }, .args = { "Dt:U", 0, 0 },
.usage = "[-DU] " CMD_TARGET_WINDOW_USAGE, .usage = "[-DU] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_rotate_window_exec .exec = cmd_rotate_window_exec
@@ -43,7 +43,8 @@ const struct cmd_entry cmd_rotate_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item) cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct winlink *wl = item->state.tflag.wl; struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->target.wl;
struct window *w = wl->window; struct window *w = wl->window;
struct window_pane *wp, *wp2; struct window_pane *wp, *wp2;
struct layout_cell *lc; struct layout_cell *lc;
@@ -77,6 +78,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL) if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL)
wp = TAILQ_LAST(&w->panes, window_panes); wp = TAILQ_LAST(&w->panes, window_panes);
window_set_active_pane(w, wp); window_set_active_pane(w, wp);
cmd_find_from_winlink_pane(current, wl, wp);
server_redraw_window(w); server_redraw_window(w);
} else { } else {
wp = TAILQ_FIRST(&w->panes); wp = TAILQ_FIRST(&w->panes);
@@ -104,6 +106,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_NEXT(w->active, entry)) == NULL) if ((wp = TAILQ_NEXT(w->active, entry)) == NULL)
wp = TAILQ_FIRST(&w->panes); wp = TAILQ_FIRST(&w->panes);
window_set_active_pane(w, wp); window_set_active_pane(w, wp);
cmd_find_from_winlink_pane(current, wl, wp);
server_redraw_window(w); server_redraw_window(w);
} }

View File

@@ -42,7 +42,7 @@ const struct cmd_entry cmd_run_shell_entry = {
.args = { "bt:", 1, 1 }, .args = { "bt:", 1, 1 },
.usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command", .usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
.tflag = CMD_PANE_CANFAIL, .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = 0, .flags = 0,
.exec = cmd_run_shell_exec .exec = cmd_run_shell_exec
@@ -68,7 +68,7 @@ cmd_run_shell_print(struct job *job, const char *msg)
cmdq_print(cdata->item, "%s", msg); cmdq_print(cdata->item, "%s", msg);
return; return;
} }
if (cmd_find_current (&fs, NULL, CMD_FIND_QUIET) != 0) if (cmd_find_from_nothing(&fs) != 0)
return; return;
wp = fs.wp; wp = fs.wp;
if (wp == NULL) if (wp == NULL)
@@ -86,10 +86,10 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_run_shell_data *cdata; struct cmd_run_shell_data *cdata;
struct client *c = item->state.c; struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->state.tflag.s; struct session *s = item->target.s;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl = item->target.wl;
struct window_pane *wp = item->state.tflag.wp; struct window_pane *wp = item->target.wp;
const char *cwd; const char *cwd;
if (item->client != NULL && item->client->session == NULL) if (item->client != NULL && item->client->session == NULL)
@@ -110,8 +110,8 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 'b')) if (!args_has(args, 'b'))
cdata->item = item; cdata->item = item;
job_run(cdata->cmd, s, cwd, cmd_run_shell_callback, cmd_run_shell_free, job_run(cdata->cmd, s, cwd, NULL, cmd_run_shell_callback,
cdata); cmd_run_shell_free, cdata);
if (args_has(args, 'b')) if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -111,6 +111,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
if (fwrite(bufdata, 1, bufsize, f) != bufsize) { if (fwrite(bufdata, 1, bufsize, f) != bufsize) {
cmdq_error(item, "%s: write error", file); cmdq_error(item, "%s: write error", file);
fclose(f); fclose(f);
free(file);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_select_layout_entry = {
.args = { "nopt:", 0, 1 }, .args = { "nopt:", 0, 1 },
.usage = "[-nop] " CMD_TARGET_WINDOW_USAGE " [layout-name]", .usage = "[-nop] " CMD_TARGET_WINDOW_USAGE " [layout-name]",
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec .exec = cmd_select_layout_exec
@@ -49,7 +49,7 @@ const struct cmd_entry cmd_next_layout_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE, .usage = CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec .exec = cmd_select_layout_exec
@@ -62,7 +62,7 @@ const struct cmd_entry cmd_previous_layout_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE, .usage = CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec .exec = cmd_select_layout_exec
@@ -72,7 +72,7 @@ static enum cmd_retval
cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item) cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl = item->target.wl;
struct window *w; struct window *w;
const char *layoutname; const char *layoutname;
char *oldlayout; char *oldlayout;

View File

@@ -33,7 +33,7 @@ const struct cmd_entry cmd_select_pane_entry = {
.args = { "DdegLlMmP:Rt:U", 0, 0 }, .args = { "DdegLlMmP:Rt:U", 0, 0 },
.usage = "[-DdegLlMmRU] [-P style] " CMD_TARGET_PANE_USAGE, .usage = "[-DdegLlMmRU] [-P style] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_select_pane_exec .exec = cmd_select_pane_exec
@@ -46,7 +46,7 @@ const struct cmd_entry cmd_last_pane_entry = {
.args = { "det:", 0, 0 }, .args = { "det:", 0, 0 },
.usage = "[-de] " CMD_TARGET_WINDOW_USAGE, .usage = "[-de] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_select_pane_exec .exec = cmd_select_pane_exec
@@ -56,31 +56,32 @@ static enum cmd_retval
cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl; struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->target.wl;
struct window *w = wl->window; struct window *w = wl->window;
struct session *s = item->state.tflag.s; struct session *s = item->target.s;
struct window_pane *wp = item->state.tflag.wp, *lastwp, *markedwp; struct window_pane *wp = item->target.wp, *lastwp, *markedwp;
const char *style; const char *style;
if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) { if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
if (wl->window->last == NULL) { lastwp = w->last;
if (lastwp == NULL) {
cmdq_error(item, "no last pane"); cmdq_error(item, "no last pane");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(self->args, 'e')) if (args_has(self->args, 'e'))
w->last->flags &= ~PANE_INPUTOFF; lastwp->flags &= ~PANE_INPUTOFF;
else if (args_has(self->args, 'd')) else if (args_has(self->args, 'd'))
w->last->flags |= PANE_INPUTOFF; lastwp->flags |= PANE_INPUTOFF;
else { else {
server_unzoom_window(w); server_unzoom_window(w);
window_redraw_active_switch(w, w->last); window_redraw_active_switch(w, lastwp);
if (window_set_active_pane(w, w->last)) { if (window_set_active_pane(w, lastwp)) {
cmd_find_from_winlink(current, wl);
server_status_window(w); server_status_window(w);
server_redraw_window_borders(w); server_redraw_window_borders(w);
} }
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -155,6 +156,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
} }
window_redraw_active_switch(w, wp); window_redraw_active_switch(w, wp);
if (window_set_active_pane(w, wp)) { if (window_set_active_pane(w, wp)) {
cmd_find_from_winlink(current, wl);
server_status_window(w); server_status_window(w);
server_redraw_window_borders(w); server_redraw_window_borders(w);
} }

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_select_window_entry = {
.args = { "lnpTt:", 0, 0 }, .args = { "lnpTt:", 0, 0 },
.usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE, .usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_select_window_exec .exec = cmd_select_window_exec
@@ -49,7 +49,7 @@ const struct cmd_entry cmd_next_window_entry = {
.args = { "at:", 0, 0 }, .args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE, .usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0, .flags = 0,
.exec = cmd_select_window_exec .exec = cmd_select_window_exec
@@ -62,7 +62,7 @@ const struct cmd_entry cmd_previous_window_entry = {
.args = { "at:", 0, 0 }, .args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE, .usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0, .flags = 0,
.exec = cmd_select_window_exec .exec = cmd_select_window_exec
@@ -75,7 +75,7 @@ const struct cmd_entry cmd_last_window_entry = {
.args = { "t:", 0, 0 }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE, .usage = CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0, .flags = 0,
.exec = cmd_select_window_exec .exec = cmd_select_window_exec
@@ -84,9 +84,10 @@ const struct cmd_entry cmd_last_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_select_window_exec(struct cmd *self, struct cmdq_item *item) cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct winlink *wl = item->state.tflag.wl; struct cmd_find_state *current = &item->shared->current;
struct session *s = item->state.tflag.s; struct winlink *wl = item->target.wl;
int next, previous, last, activity; struct session *s = item->target.s;
int next, previous, last, activity;
next = self->entry == &cmd_next_window_entry; next = self->entry == &cmd_next_window_entry;
if (args_has(self->args, 'n')) if (args_has(self->args, 'n'))
@@ -116,7 +117,7 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
cmd_find_from_session(&item->shared->current, s);
server_redraw_session(s); server_redraw_session(s);
} else { } else {
/* /*
@@ -128,9 +129,13 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no last window"); cmdq_error(item, "no last window");
return (-1); return (-1);
} }
if (current->s == s)
cmd_find_from_session(current, s);
server_redraw_session(s); server_redraw_session(s);
} else if (session_select(s, wl->idx) == 0) } else if (session_select(s, wl->idx) == 0) {
cmd_find_from_session(current, s);
server_redraw_session(s); server_redraw_session(s);
}
} }
recalculate_sizes(); recalculate_sizes();

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_send_keys_entry = {
.args = { "lXRMN:t:", 0, -1 }, .args = { "lXRMN:t:", 0, -1 },
.usage = "[-lXRM] [-N repeat-count] " CMD_TARGET_PANE_USAGE " key ...", .usage = "[-lXRM] [-N repeat-count] " CMD_TARGET_PANE_USAGE " key ...",
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_send_keys_exec .exec = cmd_send_keys_exec
@@ -49,20 +49,43 @@ const struct cmd_entry cmd_send_prefix_entry = {
.args = { "2t:", 0, 0 }, .args = { "2t:", 0, 0 },
.usage = "[-2] " CMD_TARGET_PANE_USAGE, .usage = "[-2] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_send_keys_exec .exec = cmd_send_keys_exec
}; };
static void
cmd_send_keys_inject(struct client *c, struct cmdq_item *item, key_code key)
{
struct window_pane *wp = item->target.wp;
struct session *s = item->target.s;
struct key_table *table;
struct key_binding *bd, bd_find;
if (wp->mode == NULL || wp->mode->key_table == NULL) {
window_pane_key(wp, NULL, s, key, NULL);
return;
}
table = key_bindings_get_table(wp->mode->key_table(wp), 1);
bd_find.key = (key & ~KEYC_XTERM);
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
if (bd != NULL) {
table->references++;
key_bindings_dispatch(bd, c, NULL, &item->target);
key_bindings_unref_table(table);
}
}
static enum cmd_retval static enum cmd_retval
cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct client *c = cmd_find_client(item, NULL, 1);
struct window_pane *wp = item->state.tflag.wp; struct window_pane *wp = item->target.wp;
struct session *s = item->state.tflag.s; struct session *s = item->target.s;
struct mouse_event *m = &item->mouse; struct mouse_event *m = &item->shared->mouse;
struct utf8_data *ud, *uc; struct utf8_data *ud, *uc;
wchar_t wc; wchar_t wc;
int i, literal; int i, literal;
@@ -108,7 +131,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
key = options_get_number(s->options, "prefix2"); key = options_get_number(s->options, "prefix2");
else else
key = options_get_number(s->options, "prefix"); key = options_get_number(s->options, "prefix");
window_pane_key(wp, NULL, s, key, NULL); cmd_send_keys_inject(c, item, key);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -123,7 +146,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
if (!literal) { if (!literal) {
key = key_string_lookup_string(args->argv[i]); key = key_string_lookup_string(args->argv[i]);
if (key != KEYC_NONE && key != KEYC_UNKNOWN) if (key != KEYC_NONE && key != KEYC_UNKNOWN)
window_pane_key(wp, NULL, s, key, NULL); cmd_send_keys_inject(c, item, key);
else else
literal = 1; literal = 1;
} }
@@ -132,7 +155,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
for (uc = ud; uc->size != 0; uc++) { for (uc = ud; uc->size != 0; uc++) {
if (utf8_combine(uc, &wc) != UTF8_DONE) if (utf8_combine(uc, &wc) != UTF8_DONE)
continue; continue;
window_pane_key(wp, NULL, s, wc, NULL); cmd_send_keys_inject(c, item, wc);
} }
free(ud); free(ud);
} }

View File

@@ -37,7 +37,7 @@ const struct cmd_entry cmd_set_environment_entry = {
.args = { "grt:u", 1, 2 }, .args = { "grt:u", 1, 2 },
.usage = "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]", .usage = "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
.tflag = CMD_SESSION_CANFAIL, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_set_environment_exec .exec = cmd_set_environment_exec
@@ -68,7 +68,7 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(self->args, 'g')) if (args_has(self->args, 'g'))
env = global_environ; env = global_environ;
else { else {
if (item->state.tflag.s == NULL) { if (item->target.s == NULL) {
target = args_get(args, 't'); target = args_get(args, 't');
if (target != NULL) if (target != NULL)
cmdq_error(item, "no such session: %s", target); cmdq_error(item, "no such session: %s", target);
@@ -76,7 +76,7 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no current session"); cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
env = item->state.tflag.s->environ; env = item->target.s->environ;
} }
if (args_has(self->args, 'u')) { if (args_has(self->args, 'u')) {

View File

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_set_hook_entry = {
.args = { "gt:u", 1, 2 }, .args = { "gt:u", 1, 2 },
.usage = "[-gu] " CMD_TARGET_SESSION_USAGE " hook-name [command]", .usage = "[-gu] " CMD_TARGET_SESSION_USAGE " hook-name [command]",
.tflag = CMD_SESSION_CANFAIL, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_set_hook_exec .exec = cmd_set_hook_exec
@@ -49,7 +49,7 @@ const struct cmd_entry cmd_show_hooks_entry = {
.args = { "gt:", 0, 1 }, .args = { "gt:", 0, 1 },
.usage = "[-g] " CMD_TARGET_SESSION_USAGE, .usage = "[-g] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_set_hook_exec .exec = cmd_set_hook_exec
@@ -68,7 +68,7 @@ cmd_set_hook_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'g')) if (args_has(args, 'g'))
hooks = global_hooks; hooks = global_hooks;
else { else {
if (item->state.tflag.s == NULL) { if (item->target.s == NULL) {
target = args_get(args, 't'); target = args_get(args, 't');
if (target != NULL) if (target != NULL)
cmdq_error(item, "no such session: %s", target); cmdq_error(item, "no such session: %s", target);
@@ -76,7 +76,7 @@ cmd_set_hook_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no current session"); cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
hooks = item->state.tflag.s->hooks; hooks = item->target.s->hooks;
} }
if (self->entry == &cmd_show_hooks_entry) { if (self->entry == &cmd_show_hooks_entry) {

View File

@@ -45,7 +45,7 @@ const struct cmd_entry cmd_set_option_entry = {
.args = { "agoqst:uw", 1, 2 }, .args = { "agoqst:uw", 1, 2 },
.usage = "[-agosquw] [-t target-window] option [value]", .usage = "[-agosquw] [-t target-window] option [value]",
.tflag = CMD_WINDOW_CANFAIL, .target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec .exec = cmd_set_option_exec
@@ -58,7 +58,7 @@ const struct cmd_entry cmd_set_window_option_entry = {
.args = { "agoqt:u", 1, 2 }, .args = { "agoqt:u", 1, 2 },
.usage = "[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]", .usage = "[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
.tflag = CMD_WINDOW_CANFAIL, .target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec .exec = cmd_set_option_exec
@@ -69,7 +69,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
int append = args_has(args, 'a'); int append = args_has(args, 'a');
struct cmd_find_state *fs = &item->state.tflag; struct cmd_find_state *fs = &item->target;
struct session *s = fs->s; struct session *s = fs->s;
struct winlink *wl = fs->wl; struct winlink *wl = fs->wl;
struct window *w; struct window *w;
@@ -77,7 +77,8 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
enum options_table_scope scope; enum options_table_scope scope;
struct options *oo; struct options *oo;
struct options_entry *parent, *o; struct options_entry *parent, *o;
const char *name, *value, *target; char *name;
const char *value, *target;
int window, idx, already, error, ambiguous; int window, idx, already, error, ambiguous;
char *cause; char *cause;
@@ -121,7 +122,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
cmdq_error(item, "%s", cause); cmdq_error(item, "%s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); goto fail;
} }
/* Which table should this option go into? */ /* Which table should this option go into? */
@@ -136,7 +137,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no such session: %s", target); cmdq_error(item, "no such session: %s", target);
else else
cmdq_error(item, "no current session"); cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR); goto fail;
} else } else
oo = s->options; oo = s->options;
} else if (scope == OPTIONS_TABLE_WINDOW) { } else if (scope == OPTIONS_TABLE_WINDOW) {
@@ -148,7 +149,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no such window: %s", target); cmdq_error(item, "no such window: %s", target);
else else
cmdq_error(item, "no current window"); cmdq_error(item, "no current window");
return (CMD_RETURN_ERROR); goto fail;
} else } else
oo = wl->window->options; oo = wl->window->options;
} }
@@ -159,7 +160,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
if (idx != -1) { if (idx != -1) {
if (*name == '@' || options_array_size(parent, NULL) == -1) { if (*name == '@' || options_array_size(parent, NULL) == -1) {
cmdq_error(item, "not an array: %s", args->argv[0]); cmdq_error(item, "not an array: %s", args->argv[0]);
return (CMD_RETURN_ERROR); goto fail;
} }
} }
@@ -177,14 +178,14 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'q')) if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
cmdq_error(item, "already set: %s", args->argv[0]); cmdq_error(item, "already set: %s", args->argv[0]);
return (CMD_RETURN_ERROR); goto fail;
} }
} }
/* Change the option. */ /* Change the option. */
if (args_has(args, 'u')) { if (args_has(args, 'u')) {
if (o == NULL) if (o == NULL)
return (CMD_RETURN_NORMAL); goto fail;
if (idx == -1) { if (idx == -1) {
if (oo == global_options || if (oo == global_options ||
oo == global_s_options || oo == global_s_options ||
@@ -197,17 +198,17 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
} else if (*name == '@') { } else if (*name == '@') {
if (value == NULL) { if (value == NULL) {
cmdq_error(item, "empty value"); cmdq_error(item, "empty value");
return (CMD_RETURN_ERROR); goto fail;
} }
options_set_string(oo, name, append, "%s", value); options_set_string(oo, name, append, "%s", value);
} else if (idx == -1 && options_array_size(parent, NULL) == -1) { } else if (idx == -1 && options_array_size(parent, NULL) == -1) {
error = cmd_set_option_set(self, item, oo, parent, value); error = cmd_set_option_set(self, item, oo, parent, value);
if (error != 0) if (error != 0)
return (CMD_RETURN_ERROR); goto fail;
} else { } else {
if (value == NULL) { if (value == NULL) {
cmdq_error(item, "empty value"); cmdq_error(item, "empty value");
return (CMD_RETURN_ERROR); goto fail;
} }
if (o == NULL) if (o == NULL)
o = options_empty(oo, options_table_entry(parent)); o = options_empty(oo, options_table_entry(parent));
@@ -217,7 +218,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
options_array_assign(o, value); options_array_assign(o, value);
} else if (options_array_set(o, idx, value, append) != 0) { } else if (options_array_set(o, idx, value, append) != 0) {
cmdq_error(item, "invalid index: %s", args->argv[0]); cmdq_error(item, "invalid index: %s", args->argv[0]);
return (CMD_RETURN_ERROR); goto fail;
} }
} }
@@ -261,7 +262,12 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
server_redraw_client(c); server_redraw_client(c);
} }
free(name);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
fail:
free(name);
return (CMD_RETURN_ERROR);
} }
static int static int

View File

@@ -41,7 +41,7 @@ const struct cmd_entry cmd_show_environment_entry = {
.args = { "gst:", 0, 1 }, .args = { "gst:", 0, 1 },
.usage = "[-gs] " CMD_TARGET_SESSION_USAGE " [name]", .usage = "[-gs] " CMD_TARGET_SESSION_USAGE " [name]",
.tflag = CMD_SESSION_CANFAIL, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_show_environment_exec .exec = cmd_show_environment_exec
@@ -97,7 +97,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
const char *target; const char *target;
if ((target = args_get(args, 't')) != NULL) { if ((target = args_get(args, 't')) != NULL) {
if (item->state.tflag.s == NULL) { if (item->target.s == NULL) {
cmdq_error(item, "no such session: %s", target); cmdq_error(item, "no such session: %s", target);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -106,7 +106,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(self->args, 'g')) if (args_has(self->args, 'g'))
env = global_environ; env = global_environ;
else { else {
if (item->state.tflag.s == NULL) { if (item->target.s == NULL) {
target = args_get(args, 't'); target = args_get(args, 't');
if (target != NULL) if (target != NULL)
cmdq_error(item, "no such session: %s", target); cmdq_error(item, "no such session: %s", target);
@@ -114,7 +114,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no current session"); cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
env = item->state.tflag.s->environ; env = item->target.s->environ;
} }
if (args->argc != 0) { if (args->argc != 0) {

View File

@@ -38,8 +38,6 @@ const struct cmd_entry cmd_show_messages_entry = {
.args = { "JTt:", 0, 0 }, .args = { "JTt:", 0, 0 },
.usage = "[-JT] " CMD_TARGET_CLIENT_USAGE, .usage = "[-JT] " CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_show_messages_exec .exec = cmd_show_messages_exec
}; };
@@ -75,7 +73,7 @@ cmd_show_messages_jobs(struct cmdq_item *item, int blank)
u_int n; u_int n;
n = 0; n = 0;
LIST_FOREACH(job, &all_jobs, lentry) { LIST_FOREACH(job, &all_jobs, entry) {
if (blank) { if (blank) {
cmdq_print(item, "%s", ""); cmdq_print(item, "%s", "");
blank = 0; blank = 0;
@@ -91,11 +89,14 @@ static enum cmd_retval
cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item) cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct client *c;
struct message_entry *msg; struct message_entry *msg;
char *tim; char *tim;
int done, blank; int done, blank;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
done = blank = 0; done = blank = 0;
if (args_has(args, 'T')) { if (args_has(args, 'T')) {
blank = cmd_show_messages_terminals(item, blank); blank = cmd_show_messages_terminals(item, blank);

View File

@@ -41,7 +41,7 @@ const struct cmd_entry cmd_show_options_entry = {
.args = { "gqst:vw", 0, 1 }, .args = { "gqst:vw", 0, 1 },
.usage = "[-gqsvw] [-t target-session|target-window] [option]", .usage = "[-gqsvw] [-t target-session|target-window] [option]",
.tflag = CMD_WINDOW_CANFAIL, .target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec .exec = cmd_show_options_exec
@@ -54,7 +54,7 @@ const struct cmd_entry cmd_show_window_options_entry = {
.args = { "gvt:", 0, 1 }, .args = { "gvt:", 0, 1 },
.usage = "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]", .usage = "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]",
.tflag = CMD_WINDOW_CANFAIL, .target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec .exec = cmd_show_options_exec
@@ -64,7 +64,7 @@ static enum cmd_retval
cmd_show_options_exec(struct cmd *self, struct cmdq_item *item) cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_find_state *fs = &item->state.tflag; struct cmd_find_state *fs = &item->target;
struct options *oo; struct options *oo;
enum options_table_scope scope; enum options_table_scope scope;
char *cause; char *cause;

View File

@@ -43,7 +43,7 @@ const struct cmd_entry cmd_split_window_entry = {
.usage = "[-bdfhvP] [-c start-directory] [-F format] " .usage = "[-bdfhvP] [-c start-directory] [-F format] "
"[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]", "[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]",
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_split_window_exec .exec = cmd_split_window_exec
@@ -52,12 +52,13 @@ const struct cmd_entry cmd_split_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct cmd_find_state *current = &item->shared->current;
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->state.tflag.s; struct session *s = item->target.s;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl = item->target.wl;
struct window *w = wl->window; struct window *w = wl->window;
struct window_pane *wp = item->state.tflag.wp, *new_wp = NULL; struct window_pane *wp = item->target.wp, *new_wp = NULL;
struct environ *env; struct environ *env;
const char *cmd, *path, *shell, *template, *cwd, *to_free; const char *cmd, *path, *shell, *template, *cwd, *to_free;
char **argv, *cause, *new_cause, *cp; char **argv, *cause, *new_cause, *cp;
@@ -142,7 +143,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if (envent != NULL) if (envent != NULL)
path = envent->value; path = envent->value;
env = environ_for_session(s); env = environ_for_session(s, 0);
if (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, env, if (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, env,
s->tio, &cause) != 0) { s->tio, &cause) != 0) {
environ_free(env); environ_free(env);
@@ -155,6 +156,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 'd')) { if (!args_has(args, 'd')) {
window_set_active_pane(w, new_wp); window_set_active_pane(w, new_wp);
session_select(s, wl->idx); session_select(s, wl->idx);
cmd_find_from_session(current, s);
server_redraw_session(s); server_redraw_session(s);
} else } else
server_status_session(s); server_status_session(s);
@@ -171,12 +173,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if (to_free != NULL) if (to_free != NULL)
free((void *)to_free); free((void *)to_free);
cmd_find_clear_state(&fs, NULL, 0); cmd_find_from_winlink_pane(&fs, wl, new_wp);
fs.s = s;
fs.wl = wl;
fs.w = w;
fs.wp = new_wp;
cmd_find_log_state(__func__, &fs);
hooks_insert(s->hooks, item, &fs, "after-split-window"); hooks_insert(s->hooks, item, &fs, "after-split-window");
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -35,8 +35,8 @@ const struct cmd_entry cmd_swap_pane_entry = {
.args = { "dDs:t:U", 0, 0 }, .args = { "dDs:t:U", 0, 0 },
.usage = "[-dDU] " CMD_SRCDST_PANE_USAGE, .usage = "[-dDU] " CMD_SRCDST_PANE_USAGE,
.sflag = CMD_PANE_MARKED, .source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.tflag = CMD_PANE, .target = { 't', CMD_FIND_PANE, 0 },
.flags = 0, .flags = 0,
.exec = cmd_swap_pane_exec .exec = cmd_swap_pane_exec
@@ -50,10 +50,10 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
struct layout_cell *src_lc, *dst_lc; struct layout_cell *src_lc, *dst_lc;
u_int sx, sy, xoff, yoff; u_int sx, sy, xoff, yoff;
dst_w = item->state.tflag.wl->window; dst_w = item->target.wl->window;
dst_wp = item->state.tflag.wp; dst_wp = item->target.wp;
src_w = item->state.sflag.wl->window; src_w = item->source.wl->window;
src_wp = item->state.sflag.wp; src_wp = item->source.wp;
server_unzoom_window(dst_w); server_unzoom_window(dst_w);
if (args_has(self->args, 'D')) { if (args_has(self->args, 'D')) {

View File

@@ -35,8 +35,8 @@ const struct cmd_entry cmd_swap_window_entry = {
.args = { "ds:t:", 0, 0 }, .args = { "ds:t:", 0, 0 },
.usage = "[-d] " CMD_SRCDST_WINDOW_USAGE, .usage = "[-d] " CMD_SRCDST_WINDOW_USAGE,
.sflag = CMD_WINDOW_MARKED, .source = { 's', CMD_FIND_WINDOW, CMD_FIND_DEFAULT_MARKED },
.tflag = CMD_WINDOW, .target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0, .flags = 0,
.exec = cmd_swap_window_exec .exec = cmd_swap_window_exec
@@ -50,12 +50,12 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
struct winlink *wl_src, *wl_dst; struct winlink *wl_src, *wl_dst;
struct window *w_src, *w_dst; struct window *w_src, *w_dst;
wl_src = item->state.sflag.wl; wl_src = item->source.wl;
src = item->state.sflag.s; src = item->source.s;
sg_src = session_group_contains(src); sg_src = session_group_contains(src);
wl_dst = item->state.tflag.wl; wl_dst = item->target.wl;
dst = item->state.tflag.s; dst = item->target.s;
sg_dst = session_group_contains(dst); sg_dst = session_group_contains(dst);
if (src != dst && sg_src != NULL && sg_dst != NULL && if (src != dst && sg_src != NULL && sg_dst != NULL &&

View File

@@ -38,8 +38,7 @@ const struct cmd_entry cmd_switch_client_entry = {
.usage = "[-Elnpr] [-c target-client] [-t target-session] " .usage = "[-Elnpr] [-c target-client] [-t target-session] "
"[-T key-table]", "[-T key-table]",
.cflag = CMD_CLIENT, /* -t is special */
.tflag = CMD_SESSION_WITHPANE,
.flags = CMD_READONLY, .flags = CMD_READONLY,
.exec = cmd_switch_client_exec .exec = cmd_switch_client_exec
@@ -49,13 +48,32 @@ static enum cmd_retval
cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item) cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_state *state = &item->state; const char *tflag = args_get(args, 't');
struct client *c = state->c; enum cmd_find_type type;
struct session *s = item->state.tflag.s; int flags;
struct client *c;
struct session *s;
struct winlink *wl;
struct window_pane *wp; struct window_pane *wp;
const char *tablename; const char *tablename;
struct key_table *table; struct key_table *table;
if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (tflag != NULL && tflag[strcspn(tflag, ":.")] != '\0') {
type = CMD_FIND_PANE;
flags = 0;
} else {
type = CMD_FIND_SESSION;
flags = CMD_FIND_PREFER_UNATTACHED;
}
if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
return (CMD_RETURN_ERROR);
s = item->target.s;
wl = item->target.wl;
wp = item->target.wp;
if (args_has(args, 'r')) if (args_has(args, 'r'))
c->flags ^= CLIENT_READONLY; c->flags ^= CLIENT_READONLY;
@@ -94,11 +112,11 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
} else { } else {
if (item->client == NULL) if (item->client == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (state->tflag.wl != NULL) { if (wl != NULL) {
wp = state->tflag.wp;
if (wp != NULL) if (wp != NULL)
window_set_active_pane(wp->window, wp); window_set_active_pane(wp->window, wp);
session_set_current(s, state->tflag.wl); session_set_current(s, wl);
cmd_find_from_session(&item->shared->current, s);
} }
} }
@@ -108,9 +126,10 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
if (c->session != NULL && c->session != s) if (c->session != NULL && c->session != s)
c->last_session = c->session; c->last_session = c->session;
c->session = s; c->session = s;
if (!item->repeat) if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
status_timer_start(c); status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL); session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL); gettimeofday(&s->last_attached_time, NULL);

184
cmd.c
View File

@@ -447,190 +447,6 @@ usage:
return (NULL); return (NULL);
} }
static int
cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
struct cmdq_item *item)
{
int targetflags, error;
struct cmd_find_state *fs = NULL;
struct cmd_find_state current;
if (flag == CMD_NONE ||
flag == CMD_CLIENT ||
flag == CMD_CLIENT_CANFAIL)
return (0);
if (c == 't')
fs = &item->state.tflag;
else if (c == 's')
fs = &item->state.sflag;
if (flag == CMD_SESSION_WITHPANE) {
if (target != NULL && target[strcspn(target, ":.")] != '\0')
flag = CMD_PANE;
else
flag = CMD_SESSION_PREFERUNATTACHED;
}
targetflags = 0;
switch (flag) {
case CMD_SESSION:
case CMD_SESSION_CANFAIL:
case CMD_SESSION_PREFERUNATTACHED:
case CMD_SESSION_WITHPANE:
if (flag == CMD_SESSION_CANFAIL)
targetflags |= CMD_FIND_QUIET;
if (flag == CMD_SESSION_PREFERUNATTACHED)
targetflags |= CMD_FIND_PREFER_UNATTACHED;
break;
case CMD_MOVEW_R:
flag = CMD_WINDOW_INDEX;
/* FALLTHROUGH */
case CMD_WINDOW:
case CMD_WINDOW_CANFAIL:
case CMD_WINDOW_MARKED:
case CMD_WINDOW_INDEX:
if (flag == CMD_WINDOW_CANFAIL)
targetflags |= CMD_FIND_QUIET;
if (flag == CMD_WINDOW_MARKED)
targetflags |= CMD_FIND_DEFAULT_MARKED;
if (flag == CMD_WINDOW_INDEX)
targetflags |= CMD_FIND_WINDOW_INDEX;
break;
case CMD_PANE:
case CMD_PANE_CANFAIL:
case CMD_PANE_MARKED:
if (flag == CMD_PANE_CANFAIL)
targetflags |= CMD_FIND_QUIET;
if (flag == CMD_PANE_MARKED)
targetflags |= CMD_FIND_DEFAULT_MARKED;
break;
default:
fatalx("unknown %cflag %d", c, flag);
}
log_debug("%s: flag %c %d %#x", __func__, c, flag, targetflags);
error = cmd_find_current(&current, item, targetflags);
if (error != 0) {
if (~targetflags & CMD_FIND_QUIET)
return (-1);
cmd_find_clear_state(&current, NULL, 0);
}
if (!cmd_find_empty_state(&current) && !cmd_find_valid_state(&current))
fatalx("invalid current state");
switch (flag) {
case CMD_NONE:
case CMD_CLIENT:
case CMD_CLIENT_CANFAIL:
return (0);
case CMD_SESSION:
case CMD_SESSION_CANFAIL:
case CMD_SESSION_PREFERUNATTACHED:
case CMD_SESSION_WITHPANE:
error = cmd_find_target(fs, &current, item, target,
CMD_FIND_SESSION, targetflags);
if (error != 0)
goto error;
break;
case CMD_MOVEW_R:
error = cmd_find_target(fs, &current, item, target,
CMD_FIND_SESSION, CMD_FIND_QUIET);
if (error == 0)
break;
/* FALLTHROUGH */
case CMD_WINDOW:
case CMD_WINDOW_CANFAIL:
case CMD_WINDOW_MARKED:
case CMD_WINDOW_INDEX:
error = cmd_find_target(fs, &current, item, target,
CMD_FIND_WINDOW, targetflags);
if (error != 0)
goto error;
break;
case CMD_PANE:
case CMD_PANE_CANFAIL:
case CMD_PANE_MARKED:
error = cmd_find_target(fs, &current, item, target,
CMD_FIND_PANE, targetflags);
if (error != 0)
goto error;
break;
default:
fatalx("unknown %cflag %d", c, flag);
}
return (0);
error:
if (~targetflags & CMD_FIND_QUIET)
return (-1);
cmd_find_clear_state(fs, NULL, 0);
return (0);
}
int
cmd_prepare_state(struct cmd *cmd, struct cmdq_item *item)
{
const struct cmd_entry *entry = cmd->entry;
struct cmd_state *state = &item->state;
char *tmp;
enum cmd_entry_flag flag;
const char *s;
int error;
tmp = cmd_print(cmd);
log_debug("preparing state for %s (client %p)", tmp, item->client);
free(tmp);
state->c = NULL;
cmd_find_clear_state(&state->tflag, NULL, 0);
cmd_find_clear_state(&state->sflag, NULL, 0);
flag = cmd->entry->cflag;
if (flag == CMD_NONE) {
flag = cmd->entry->tflag;
if (flag == CMD_CLIENT || flag == CMD_CLIENT_CANFAIL)
s = args_get(cmd->args, 't');
else
s = NULL;
} else
s = args_get(cmd->args, 'c');
switch (flag) {
case CMD_CLIENT:
state->c = cmd_find_client(item, s, 0);
if (state->c == NULL)
return (-1);
break;
default:
state->c = cmd_find_client(item, s, 1);
break;
}
log_debug("using client %p", state->c);
s = args_get(cmd->args, 't');
log_debug("preparing -t state: target %s", s == NULL ? "none" : s);
error = cmd_prepare_state_flag('t', s, entry->tflag, item);
if (error != 0)
return (error);
s = args_get(cmd->args, 's');
log_debug("preparing -s state: target %s", s == NULL ? "none" : s);
error = cmd_prepare_state_flag('s', s, entry->sflag, item);
if (error != 0)
return (error);
if (!cmd_find_empty_state(&state->tflag) &&
!cmd_find_valid_state(&state->tflag))
fatalx("invalid -t state");
if (!cmd_find_empty_state(&state->sflag) &&
!cmd_find_valid_state(&state->sflag))
fatalx("invalid -s state");
return (0);
}
char * char *
cmd_print(struct cmd *cmd) cmd_print(struct cmd *cmd)
{ {

View File

@@ -18,6 +18,7 @@
#define COMPAT_H #define COMPAT_H
#include <sys/types.h> #include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <limits.h> #include <limits.h>
@@ -283,9 +284,15 @@ int b64_ntop(const char *, size_t, char *, size_t);
int b64_pton(const char *, u_char *, size_t); int b64_pton(const char *, u_char *, size_t);
#endif #endif
#ifndef HAVE_FDFORKPTY
/* fdforkpty.c */
int getptmfd(void);
pid_t fdforkpty(int, int *, char *, struct termios *,
struct winsize *);
#endif
#ifndef HAVE_FORKPTY #ifndef HAVE_FORKPTY
/* forkpty.c */ /* forkpty.c */
#include <sys/ioctl.h>
pid_t forkpty(int *, char *, struct termios *, struct winsize *); pid_t forkpty(int *, char *, struct termios *, struct winsize *);
#endif #endif
@@ -337,9 +344,7 @@ int utf8proc_mbtowc(wchar_t *, const char *, size_t);
int utf8proc_wctomb(char *, wchar_t); int utf8proc_wctomb(char *, wchar_t);
#endif #endif
#ifdef HAVE_GETOPT #ifndef HAVE_GETOPT
#include <getopt.h>
#else
/* getopt.c */ /* getopt.c */
extern int BSDopterr; extern int BSDopterr;
extern int BSDoptind; extern int BSDoptind;

34
compat/fdforkpty.c Normal file
View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <limits.h>
#include "compat.h"
int
getptmfd(void)
{
return (INT_MAX);
}
pid_t
fdforkpty(__unused int ptmfd, int *master, char *name, struct termios *tio,
struct winsize *ws)
{
return (forkpty(master, name, tio, ws));
}

View File

@@ -29,7 +29,8 @@ void fatal(const char *, ...);
void fatalx(const char *, ...); void fatalx(const char *, ...);
pid_t pid_t
forkpty(int *master, unused char *name, struct termios *tio, struct winsize *ws) forkpty(int *master, __unused char *name, struct termios *tio,
struct winsize *ws)
{ {
int slave = -1, fd, pipe_fd[2]; int slave = -1, fd, pipe_fd[2];
char *path, dummy; char *path, dummy;

View File

@@ -15,13 +15,15 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <sys/types.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "compat.h" #include "compat.h"
int int
setenv(const char *name, const char *value, unused int overwrite) setenv(const char *name, const char *value, __unused int overwrite)
{ {
char *newval; char *newval;

View File

@@ -1,6 +1,6 @@
# configure.ac # configure.ac
AC_INIT(tmux, 2.4) AC_INIT(tmux, 2.5)
AC_PREREQ([2.60]) AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc) AC_CONFIG_AUX_DIR(etc)
@@ -35,6 +35,7 @@ AC_USE_SYSTEM_EXTENSIONS
test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc
# Is this --enable-debug? # Is this --enable-debug?
test "x$VERSION" = xmaster && enable_debug=yes
AC_ARG_ENABLE( AC_ARG_ENABLE(
debug, debug,
AC_HELP_STRING(--enable-debug, enable debug build flags), AC_HELP_STRING(--enable-debug, enable debug build flags),
@@ -453,7 +454,13 @@ else
AC_LIBOBJ(getopt) AC_LIBOBJ(getopt)
fi fi
# Look for forkpty in libutil. compat/forkpty-*.c is linked if not found. # Look for fdforkpty and forkpty in libutil.
AC_SEARCH_LIBS(fdforkpty, util, found_fdforkpty=yes, found_fdforkpty=no)
if test "x$found_fdforkpty" = xyes; then
AC_DEFINE(HAVE_FDFORKPTY)
else
AC_LIBOBJ(fdforkpty)
fi
AC_SEARCH_LIBS(forkpty, util, found_forkpty=yes, found_forkpty=no) AC_SEARCH_LIBS(forkpty, util, found_forkpty=yes, found_forkpty=no)
if test "x$found_forkpty" = xyes; then if test "x$found_forkpty" = xyes; then
AC_DEFINE(HAVE_FORKPTY) AC_DEFINE(HAVE_FORKPTY)

View File

@@ -59,14 +59,27 @@ control_notify_input(struct client *c, struct window_pane *wp,
} }
} }
void
control_notify_pane_mode_changed(int pane)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue;
control_write(c, "%%pane-mode-changed %%%u", pane);
}
}
void void
control_notify_window_layout_changed(struct window *w) control_notify_window_layout_changed(struct window *w)
{ {
struct client *c; struct client *c;
struct session *s; struct session *s;
struct winlink *wl; struct winlink *wl;
const char *template; const char *template;
char *cp; char *cp;
template = "%layout-change #{window_id} #{window_layout} " template = "%layout-change #{window_id} #{window_layout} "
"#{window_visible_layout} #{window_flags}"; "#{window_visible_layout} #{window_flags}";
@@ -96,6 +109,20 @@ control_notify_window_layout_changed(struct window *w)
} }
} }
void
control_notify_window_pane_changed(struct window *w)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue;
control_write(c, "%%window-pane-changed @%u %%%u", w->id,
w->active->id);
}
}
void void
control_notify_window_unlinked(__unused struct session *s, struct window *w) control_notify_window_unlinked(__unused struct session *s, struct window *w)
{ {
@@ -154,15 +181,27 @@ control_notify_window_renamed(struct window *w)
} }
void void
control_notify_client_session_changed(struct client *c) control_notify_client_session_changed(struct client *cc)
{ {
struct client *c;
struct session *s; struct session *s;
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) if (cc->session == NULL)
return; return;
s = c->session; s = cc->session;
control_write(c, "%%session-changed $%u %s", s->id, s->name); TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
continue;
if (cc == c) {
control_write(c, "%%session-changed $%u %s", s->id,
s->name);
} else {
control_write(c, "%%client-session-changed %s $%u %s",
cc->name, s->id, s->name);
}
}
} }
void void
@@ -203,3 +242,17 @@ control_notify_session_closed(__unused struct session *s)
control_write(c, "%%sessions-changed"); control_write(c, "%%sessions-changed");
} }
} }
void
control_notify_session_window_changed(struct session *s)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue;
control_write(c, "%%session-window-changed $%u @%u", s->id,
s->curw->window->id);
}
}

View File

@@ -222,7 +222,7 @@ environ_log(struct environ *env, const char *prefix)
/* Create initial environment for new child. */ /* Create initial environment for new child. */
struct environ * struct environ *
environ_for_session(struct session *s) environ_for_session(struct session *s, int no_TERM)
{ {
struct environ *env; struct environ *env;
const char *value; const char *value;
@@ -233,8 +233,10 @@ environ_for_session(struct session *s)
if (s != NULL) if (s != NULL)
environ_copy(s->environ, env); environ_copy(s->environ, env);
value = options_get_string(global_options, "default-terminal"); if (!no_TERM) {
environ_set(env, "TERM", "%s", value); value = options_get_string(global_options, "default-terminal");
environ_set(env, "TERM", "%s", value);
}
if (s != NULL) if (s != NULL)
idx = s->id; idx = s->id;

200
format.c
View File

@@ -40,7 +40,6 @@
struct format_entry; struct format_entry;
typedef void (*format_cb)(struct format_tree *, struct format_entry *); typedef void (*format_cb)(struct format_tree *, struct format_entry *);
static void format_job_callback(struct job *);
static char *format_job_get(struct format_tree *, const char *); static char *format_job_get(struct format_tree *, const char *);
static void format_job_timer(int, short, void *); static void format_job_timer(int, short, void *);
@@ -76,17 +75,19 @@ static int format_replace(struct format_tree *, const char *, size_t,
static void format_defaults_session(struct format_tree *, static void format_defaults_session(struct format_tree *,
struct session *); struct session *);
static void format_defaults_client(struct format_tree *, struct client *); static void format_defaults_client(struct format_tree *, struct client *);
static void format_defaults_winlink(struct format_tree *, struct session *, static void format_defaults_winlink(struct format_tree *,
struct winlink *); struct winlink *);
/* Entry in format job tree. */ /* Entry in format job tree. */
struct format_job { struct format_job {
struct client *client;
u_int tag; u_int tag;
const char *cmd; const char *cmd;
const char *expanded; const char *expanded;
time_t last; time_t last;
char *out; char *out;
int updated;
struct job *job; struct job *job;
int status; int status;
@@ -129,9 +130,11 @@ struct format_entry {
/* Format entry tree. */ /* Format entry tree. */
struct format_tree { struct format_tree {
struct window *w; struct window *w;
struct winlink *wl;
struct session *s; struct session *s;
struct window_pane *wp; struct window_pane *wp;
struct client *client;
u_int tag; u_int tag;
int flags; int flags;
@@ -207,17 +210,41 @@ static const char *format_lower[] = {
NULL /* z */ NULL /* z */
}; };
/* Format job callback. */ /* Format job update callback. */
static void static void
format_job_callback(struct job *job) format_job_update(struct job *job)
{
struct format_job *fj = job->data;
char *line;
time_t t;
struct client *c;
if ((line = evbuffer_readline(job->event->input)) == NULL)
return;
fj->updated = 1;
free(fj->out);
fj->out = line;
log_debug("%s: %s: %s", __func__, fj->cmd, fj->out);
t = time (NULL);
if (fj->status && fj->last != t) {
TAILQ_FOREACH(c, &clients, entry)
server_status_client(c);
fj->last = t;
}
}
/* Format job complete callback. */
static void
format_job_complete(struct job *job)
{ {
struct format_job *fj = job->data; struct format_job *fj = job->data;
char *line, *buf; char *line, *buf;
size_t len; size_t len;
struct client *c;
fj->job = NULL; fj->job = NULL;
free(fj->out);
buf = NULL; buf = NULL;
if ((line = evbuffer_readline(job->event->input)) == NULL) { if ((line = evbuffer_readline(job->event->input)) == NULL) {
@@ -228,37 +255,52 @@ format_job_callback(struct job *job)
buf[len] = '\0'; buf[len] = '\0';
} else } else
buf = line; buf = line;
fj->out = buf;
if (*buf != '\0' || !fj->updated) {
free(fj->out);
fj->out = buf;
log_debug("%s: %s: %s", __func__, fj->cmd, fj->out);
} else
free(buf);
if (fj->status) { if (fj->status) {
TAILQ_FOREACH(c, &clients, entry) if (fj->client != NULL)
server_status_client(c); server_status_client(fj->client);
fj->status = 0; fj->status = 0;
} }
log_debug("%s: %s: %s", __func__, fj->cmd, fj->out);
} }
/* Find a job. */ /* Find a job. */
static char * static char *
format_job_get(struct format_tree *ft, const char *cmd) format_job_get(struct format_tree *ft, const char *cmd)
{ {
struct format_job_tree *jobs;
struct format_job fj0, *fj; struct format_job fj0, *fj;
time_t t; time_t t;
char *expanded; char *expanded;
int force; int force;
if (ft->client == NULL)
jobs = &format_jobs;
else if (ft->client->jobs != NULL)
jobs = ft->client->jobs;
else {
jobs = ft->client->jobs = xmalloc(sizeof *ft->client->jobs);
RB_INIT(jobs);
}
fj0.tag = ft->tag; fj0.tag = ft->tag;
fj0.cmd = cmd; fj0.cmd = cmd;
if ((fj = RB_FIND(format_job_tree, &format_jobs, &fj0)) == NULL) { if ((fj = RB_FIND(format_job_tree, jobs, &fj0)) == NULL) {
fj = xcalloc(1, sizeof *fj); fj = xcalloc(1, sizeof *fj);
fj->client = ft->client;
fj->tag = ft->tag; fj->tag = ft->tag;
fj->cmd = xstrdup(cmd); fj->cmd = xstrdup(cmd);
fj->expanded = NULL; fj->expanded = NULL;
xasprintf(&fj->out, "<'%s' not ready>", fj->cmd); xasprintf(&fj->out, "<'%s' not ready>", fj->cmd);
RB_INSERT(format_job_tree, &format_jobs, fj); RB_INSERT(format_job_tree, jobs, fj);
} }
expanded = format_expand(ft, cmd); expanded = format_expand(ft, cmd);
@@ -271,13 +313,14 @@ format_job_get(struct format_tree *ft, const char *cmd)
t = time(NULL); t = time(NULL);
if (fj->job == NULL && (force || fj->last != t)) { if (fj->job == NULL && (force || fj->last != t)) {
fj->job = job_run(expanded, NULL, NULL, format_job_callback, fj->job = job_run(expanded, NULL, NULL, format_job_update,
NULL, fj); format_job_complete, NULL, fj);
if (fj->job == NULL) { if (fj->job == NULL) {
free(fj->out); free(fj->out);
xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd); xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd);
} }
fj->last = t; fj->last = t;
fj->updated = 0;
} }
if (ft->flags & FORMAT_STATUS) if (ft->flags & FORMAT_STATUS)
@@ -289,17 +332,16 @@ format_job_get(struct format_tree *ft, const char *cmd)
/* Remove old jobs. */ /* Remove old jobs. */
static void static void
format_job_timer(__unused int fd, __unused short events, __unused void *arg) format_job_tidy(struct format_job_tree *jobs, int force)
{ {
struct format_job *fj, *fj1; struct format_job *fj, *fj1;
time_t now; time_t now;
struct timeval tv = { .tv_sec = 60 };
now = time(NULL); now = time(NULL);
RB_FOREACH_SAFE(fj, format_job_tree, &format_jobs, fj1) { RB_FOREACH_SAFE(fj, format_job_tree, jobs, fj1) {
if (fj->last > now || now - fj->last < 3600) if (!force && (fj->last > now || now - fj->last < 3600))
continue; continue;
RB_REMOVE(format_job_tree, &format_jobs, fj); RB_REMOVE(format_job_tree, jobs, fj);
log_debug("%s: %s", __func__, fj->cmd); log_debug("%s: %s", __func__, fj->cmd);
@@ -312,6 +354,29 @@ format_job_timer(__unused int fd, __unused short events, __unused void *arg)
free(fj); free(fj);
} }
}
/* Remove old jobs for client. */
void
format_lost_client(struct client *c)
{
if (c->jobs != NULL)
format_job_tidy(c->jobs, 1);
free(c->jobs);
}
/* Remove old jobs periodically. */
static void
format_job_timer(__unused int fd, __unused short events, __unused void *arg)
{
struct client *c;
struct timeval tv = { .tv_sec = 60 };
format_job_tidy(&format_jobs, 0);
TAILQ_FOREACH(c, &clients, entry) {
if (c->jobs != NULL)
format_job_tidy(c->jobs, 0);
}
evtimer_del(&format_job_event); evtimer_del(&format_job_event);
evtimer_add(&format_job_event, &tv); evtimer_add(&format_job_event, &tv);
@@ -357,7 +422,7 @@ format_cb_session_alerts(struct format_tree *ft, struct format_entry *fe)
{ {
struct session *s = ft->s; struct session *s = ft->s;
struct winlink *wl; struct winlink *wl;
char alerts[256], tmp[16]; char alerts[1024], tmp[16];
if (s == NULL) if (s == NULL)
return; return;
@@ -381,6 +446,48 @@ format_cb_session_alerts(struct format_tree *ft, struct format_entry *fe)
fe->value = xstrdup(alerts); fe->value = xstrdup(alerts);
} }
/* Callback for session_stack. */
static void
format_cb_session_stack(struct format_tree *ft, struct format_entry *fe)
{
struct session *s = ft->s;
struct winlink *wl;
char result[1024], tmp[16];
if (s == NULL)
return;
xsnprintf(result, sizeof result, "%u", s->curw->idx);
TAILQ_FOREACH(wl, &s->lastw, sentry) {
xsnprintf(tmp, sizeof tmp, "%u", wl->idx);
if (*result != '\0')
strlcat(result, ",", sizeof result);
strlcat(result, tmp, sizeof result);
}
fe->value = xstrdup(result);
}
/* Callback for window_stack_index. */
static void
format_cb_window_stack_index(struct format_tree *ft, struct format_entry *fe)
{
struct session *s = ft->wl->session;
struct winlink *wl;
u_int idx;
idx = 0;
TAILQ_FOREACH(wl, &s->lastw, sentry) {
idx++;
if (wl == ft->wl)
break;
}
if (wl != NULL)
xasprintf(&fe->value, "%u", idx);
else
fe->value = xstrdup("0");
}
/* Callback for window_layout. */ /* Callback for window_layout. */
static void static void
format_cb_window_layout(struct format_tree *ft, struct format_entry *fe) format_cb_window_layout(struct format_tree *ft, struct format_entry *fe)
@@ -523,7 +630,7 @@ format_merge(struct format_tree *ft, struct format_tree *from)
/* Create a new tree. */ /* Create a new tree. */
struct format_tree * struct format_tree *
format_create(struct cmdq_item *item, int tag, int flags) format_create(struct client *c, struct cmdq_item *item, int tag, int flags)
{ {
struct format_tree *ft; struct format_tree *ft;
@@ -535,6 +642,11 @@ format_create(struct cmdq_item *item, int tag, int flags)
ft = xcalloc(1, sizeof *ft); ft = xcalloc(1, sizeof *ft);
RB_INIT(&ft->tree); RB_INIT(&ft->tree);
if (c != NULL) {
ft->client = c;
ft->client->references++;
}
ft->tag = tag; ft->tag = tag;
ft->flags = flags; ft->flags = flags;
@@ -545,10 +657,12 @@ format_create(struct cmdq_item *item, int tag, int flags)
format_add(ft, "socket_path", "%s", socket_path); format_add(ft, "socket_path", "%s", socket_path);
format_add_tv(ft, "start_time", &start_time); format_add_tv(ft, "start_time", &start_time);
if (item != NULL && item->cmd != NULL) if (item != NULL) {
format_add(ft, "command", "%s", item->cmd->entry->name); if (item->cmd != NULL)
if (item != NULL && item->formats != NULL) format_add(ft, "command", "%s", item->cmd->entry->name);
format_merge(ft, item->formats); if (item->shared != NULL && item->shared->formats != NULL)
format_merge(ft, item->shared->formats);
}
return (ft); return (ft);
} }
@@ -566,6 +680,8 @@ format_free(struct format_tree *ft)
free(fe); free(fe);
} }
if (ft->client != NULL)
server_client_unref(ft->client);
free(ft); free(ft);
} }
@@ -1088,7 +1204,10 @@ format_single(struct cmdq_item *item, const char *fmt, struct client *c,
struct format_tree *ft; struct format_tree *ft;
char *expanded; char *expanded;
ft = format_create(item, FORMAT_NONE, 0); if (item != NULL)
ft = format_create(item->client, item, FORMAT_NONE, 0);
else
ft = format_create(NULL, item, FORMAT_NONE, 0);
format_defaults(ft, c, s, wl, wp); format_defaults(ft, c, s, wl, wp);
expanded = format_expand(ft, fmt); expanded = format_expand(ft, fmt);
@@ -1112,8 +1231,8 @@ format_defaults(struct format_tree *ft, struct client *c, struct session *s,
format_defaults_client(ft, c); format_defaults_client(ft, c);
if (s != NULL) if (s != NULL)
format_defaults_session(ft, s); format_defaults_session(ft, s);
if (s != NULL && wl != NULL) if (wl != NULL)
format_defaults_winlink(ft, s, wl); format_defaults_winlink(ft, wl);
if (wp != NULL) if (wp != NULL)
format_defaults_pane(ft, wp); format_defaults_pane(ft, wp);
} }
@@ -1145,6 +1264,7 @@ format_defaults_session(struct format_tree *ft, struct session *s)
format_add(ft, "session_many_attached", "%d", s->attached > 1); format_add(ft, "session_many_attached", "%d", s->attached > 1);
format_add_cb(ft, "session_alerts", format_cb_session_alerts); format_add_cb(ft, "session_alerts", format_cb_session_alerts);
format_add_cb(ft, "session_stack", format_cb_session_stack);
} }
/* Set default format keys for a client. */ /* Set default format keys for a client. */
@@ -1174,7 +1294,9 @@ format_defaults_client(struct format_tree *ft, struct client *c)
format_add_tv(ft, "client_created", &c->creation_time); format_add_tv(ft, "client_created", &c->creation_time);
format_add_tv(ft, "client_activity", &c->activity_time); format_add_tv(ft, "client_activity", &c->activity_time);
format_add(ft, "client_written", "%zu", tty->written);
format_add(ft, "client_written", "%zu", c->written);
format_add(ft, "client_discarded", "%zu", c->discarded);
name = server_client_get_key_table(c); name = server_client_get_key_table(c);
if (strcmp(c->keytable->name, name) == 0) if (strcmp(c->keytable->name, name) == 0)
@@ -1222,21 +1344,20 @@ format_defaults_window(struct format_tree *ft, struct window *w)
/* Set default format keys for a winlink. */ /* Set default format keys for a winlink. */
static void static void
format_defaults_winlink(struct format_tree *ft, struct session *s, format_defaults_winlink(struct format_tree *ft, struct winlink *wl)
struct winlink *wl)
{ {
struct session *s = wl->session;
struct window *w = wl->window; struct window *w = wl->window;
char *flags;
if (ft->w == NULL) if (ft->w == NULL)
ft->w = wl->window; ft->w = wl->window;
ft->wl = wl;
flags = window_printable_flags(s, wl);
format_defaults_window(ft, w); format_defaults_window(ft, w);
format_add(ft, "window_index", "%d", wl->idx); format_add(ft, "window_index", "%d", wl->idx);
format_add(ft, "window_flags", "%s", flags); format_add_cb(ft, "window_stack_index", format_cb_window_stack_index);
format_add(ft, "window_flags", "%s", window_printable_flags(wl));
format_add(ft, "window_active", "%d", wl == s->curw); format_add(ft, "window_active", "%d", wl == s->curw);
format_add(ft, "window_bell_flag", "%d", format_add(ft, "window_bell_flag", "%d",
@@ -1248,8 +1369,6 @@ format_defaults_winlink(struct format_tree *ft, struct session *s,
format_add(ft, "window_last_flag", "%d", format_add(ft, "window_last_flag", "%d",
!!(wl == TAILQ_FIRST(&s->lastw))); !!(wl == TAILQ_FIRST(&s->lastw)));
format_add(ft, "window_linked", "%d", session_is_linked(s, wl->window)); format_add(ft, "window_linked", "%d", session_is_linked(s, wl->window));
free(flags);
} }
/* Set default format keys for a window pane. */ /* Set default format keys for a window pane. */
@@ -1292,8 +1411,13 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
} }
format_add(ft, "pane_in_mode", "%d", wp->screen != &wp->base); format_add(ft, "pane_in_mode", "%d", wp->screen != &wp->base);
if (wp->mode != NULL)
format_add(ft, "pane_mode", "%s", wp->mode->name);
format_add(ft, "pane_synchronized", "%d", format_add(ft, "pane_synchronized", "%d",
!!options_get_number(wp->window->options, "synchronize-panes")); !!options_get_number(wp->window->options, "synchronize-panes"));
format_add(ft, "pane_search_string", "%s",
window_copy_search_string(wp));
format_add(ft, "pane_tty", "%s", wp->tty); format_add(ft, "pane_tty", "%s", wp->tty);
format_add(ft, "pane_pid", "%ld", (long) wp->pid); format_add(ft, "pane_pid", "%ld", (long) wp->pid);

69
grid.c
View File

@@ -89,7 +89,7 @@ grid_need_extended_cell(const struct grid_cell_entry *gce,
return (1); return (1);
if (gc->data.size != 1 || gc->data.width != 1) if (gc->data.size != 1 || gc->data.width != 1)
return (1); return (1);
if ((gc->fg & COLOUR_FLAG_RGB) ||(gc->bg & COLOUR_FLAG_RGB)) if ((gc->fg & COLOUR_FLAG_RGB) || (gc->bg & COLOUR_FLAG_RGB))
return (1); return (1);
return (0); return (0);
} }
@@ -472,7 +472,7 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, u_int bg)
gd->linedata[yy].cellsize = px; gd->linedata[yy].cellsize = px;
continue; continue;
} }
grid_expand_line(gd, yy, px + nx, bg); grid_expand_line(gd, yy, px + nx, 8); /* default bg first */
for (xx = px; xx < px + nx; xx++) for (xx = px; xx < px + nx; xx++)
grid_clear_cell(gd, xx, yy, bg); grid_clear_cell(gd, xx, yy, bg);
} }
@@ -675,8 +675,7 @@ grid_string_cells_code(const struct grid_cell *lastgc,
{ {
int oldc[64], newc[64], s[128]; int oldc[64], newc[64], s[128];
size_t noldc, nnewc, n, i; size_t noldc, nnewc, n, i;
u_int attr = gc->attr; u_int attr = gc->attr, lastattr = lastgc->attr;
u_int lastattr = lastgc->attr;
char tmp[64]; char tmp[64];
struct { struct {
@@ -708,23 +707,7 @@ grid_string_cells_code(const struct grid_cell *lastgc,
s[n++] = attrs[i].code; s[n++] = attrs[i].code;
} }
/* If the foreground colour changed, append its parameters. */ /* Write the attributes. */
nnewc = grid_string_cells_fg(gc, newc);
noldc = grid_string_cells_fg(lastgc, oldc);
if (nnewc != noldc || memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0) {
for (i = 0; i < nnewc; i++)
s[n++] = newc[i];
}
/* If the background colour changed, append its parameters. */
nnewc = grid_string_cells_bg(gc, newc);
noldc = grid_string_cells_bg(lastgc, oldc);
if (nnewc != noldc || memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0) {
for (i = 0; i < nnewc; i++)
s[n++] = newc[i];
}
/* If there are any parameters, append an SGR code. */
*buf = '\0'; *buf = '\0';
if (n > 0) { if (n > 0) {
if (escape_c0) if (escape_c0)
@@ -741,16 +724,56 @@ grid_string_cells_code(const struct grid_cell *lastgc,
strlcat(buf, "m", len); strlcat(buf, "m", len);
} }
/* If the foreground colour changed, write its parameters. */
nnewc = grid_string_cells_fg(gc, newc);
noldc = grid_string_cells_fg(lastgc, oldc);
if (nnewc != noldc ||
memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0 ||
(n != 0 && s[0] == 0)) {
if (escape_c0)
strlcat(buf, "\\033[", len);
else
strlcat(buf, "\033[", len);
for (i = 0; i < nnewc; i++) {
if (i + 1 < nnewc)
xsnprintf(tmp, sizeof tmp, "%d;", newc[i]);
else
xsnprintf(tmp, sizeof tmp, "%d", newc[i]);
strlcat(buf, tmp, len);
}
strlcat(buf, "m", len);
}
/* If the background colour changed, append its parameters. */
nnewc = grid_string_cells_bg(gc, newc);
noldc = grid_string_cells_bg(lastgc, oldc);
if (nnewc != noldc ||
memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0 ||
(n != 0 && s[0] == 0)) {
if (escape_c0)
strlcat(buf, "\\033[", len);
else
strlcat(buf, "\033[", len);
for (i = 0; i < nnewc; i++) {
if (i + 1 < nnewc)
xsnprintf(tmp, sizeof tmp, "%d;", newc[i]);
else
xsnprintf(tmp, sizeof tmp, "%d", newc[i]);
strlcat(buf, tmp, len);
}
strlcat(buf, "m", len);
}
/* Append shift in/shift out if needed. */ /* Append shift in/shift out if needed. */
if ((attr & GRID_ATTR_CHARSET) && !(lastattr & GRID_ATTR_CHARSET)) { if ((attr & GRID_ATTR_CHARSET) && !(lastattr & GRID_ATTR_CHARSET)) {
if (escape_c0) if (escape_c0)
strlcat(buf, "\\016", len); /* SO */ strlcat(buf, "\\016", len); /* SO */
else else
strlcat(buf, "\016", len); /* SO */ strlcat(buf, "\016", len); /* SO */
} }
if (!(attr & GRID_ATTR_CHARSET) && (lastattr & GRID_ATTR_CHARSET)) { if (!(attr & GRID_ATTR_CHARSET) && (lastattr & GRID_ATTR_CHARSET)) {
if (escape_c0) if (escape_c0)
strlcat(buf, "\\017", len); /* SI */ strlcat(buf, "\\017", len); /* SI */
else else
strlcat(buf, "\017", len); /* SI */ strlcat(buf, "\017", len); /* SI */
} }

View File

@@ -200,6 +200,7 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
return; return;
} }
} }
key &= ~KEYC_XTERM;
/* Otherwise look the key up in the table. */ /* Otherwise look the key up in the table. */
for (i = 0; i < nitems(input_keys); i++) { for (i = 0; i < nitems(input_keys); i++) {

View File

@@ -1308,7 +1308,8 @@ input_csi_dispatch(struct input_ctx *ictx)
} }
break; break;
case INPUT_CSI_ECH: case INPUT_CSI_ECH:
screen_write_clearcharacter(sctx, input_get(ictx, 0, 1, 1)); screen_write_clearcharacter(sctx, input_get(ictx, 0, 1, 1),
ictx->cell.cell.bg);
break; break;
case INPUT_CSI_DCH: case INPUT_CSI_DCH:
screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1), screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1),
@@ -2011,7 +2012,7 @@ input_utf8_close(struct input_ctx *ictx)
(int)ud->size, ud->data, ud->width); (int)ud->size, ud->data, ud->width);
utf8_copy(&ictx->cell.cell.data, ud); utf8_copy(&ictx->cell.cell.data, ud);
screen_write_cell(&ictx->ctx, &ictx->cell.cell); screen_write_collect_add(&ictx->ctx, &ictx->cell.cell);
return (0); return (0);
} }

56
job.c
View File

@@ -32,8 +32,9 @@
* output. * output.
*/ */
static void job_callback(struct bufferevent *, short, void *); static void job_read_callback(struct bufferevent *, void *);
static void job_write_callback(struct bufferevent *, void *); static void job_write_callback(struct bufferevent *, void *);
static void job_error_callback(struct bufferevent *, short, void *);
/* All jobs list. */ /* All jobs list. */
struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs); struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
@@ -41,7 +42,8 @@ struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
/* Start a job running, if it isn't already. */ /* Start a job running, if it isn't already. */
struct job * struct job *
job_run(const char *cmd, struct session *s, const char *cwd, job_run(const char *cmd, struct session *s, const char *cwd,
void (*callbackfn)(struct job *), void (*freefn)(void *), void *data) job_update_cb updatecb, job_complete_cb completecb, job_free_cb freecb,
void *data)
{ {
struct job *job; struct job *job;
struct environ *env; struct environ *env;
@@ -52,7 +54,12 @@ job_run(const char *cmd, struct session *s, const char *cwd,
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0) if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0)
return (NULL); return (NULL);
env = environ_for_session(s); /*
* Do not set TERM during .tmux.conf, it is nice to be able to use
* if-shell to decide on default-terminal based on outside TERM.
*/
env = environ_for_session(s, !cfg_finished);
switch (pid = fork()) { switch (pid = fork()) {
case -1: case -1:
environ_free(env); environ_free(env);
@@ -103,17 +110,18 @@ job_run(const char *cmd, struct session *s, const char *cwd,
job->pid = pid; job->pid = pid;
job->status = 0; job->status = 0;
LIST_INSERT_HEAD(&all_jobs, job, lentry); LIST_INSERT_HEAD(&all_jobs, job, entry);
job->callbackfn = callbackfn; job->updatecb = updatecb;
job->freefn = freefn; job->completecb = completecb;
job->freecb = freecb;
job->data = data; job->data = data;
job->fd = out[0]; job->fd = out[0];
setblocking(job->fd, 0); setblocking(job->fd, 0);
job->event = bufferevent_new(job->fd, NULL, job_write_callback, job->event = bufferevent_new(job->fd, job_read_callback,
job_callback, job); job_write_callback, job_error_callback, job);
bufferevent_enable(job->event, EV_READ|EV_WRITE); bufferevent_enable(job->event, EV_READ|EV_WRITE);
log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid); log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid);
@@ -126,11 +134,11 @@ job_free(struct job *job)
{ {
log_debug("free job %p: %s", job, job->cmd); log_debug("free job %p: %s", job, job->cmd);
LIST_REMOVE(job, lentry); LIST_REMOVE(job, entry);
free(job->cmd); free(job->cmd);
if (job->freefn != NULL && job->data != NULL) if (job->freecb != NULL && job->data != NULL)
job->freefn(job->data); job->freecb(job->data);
if (job->pid != -1) if (job->pid != -1)
kill(job->pid, SIGTERM); kill(job->pid, SIGTERM);
@@ -142,7 +150,21 @@ job_free(struct job *job)
free(job); free(job);
} }
/* Called when output buffer falls below low watermark (default is 0). */ /* Job buffer read callback. */
static void
job_read_callback(__unused struct bufferevent *bufev, void *data)
{
struct job *job = data;
if (job->updatecb != NULL)
job->updatecb (job);
}
/*
* Job buffer write callback. Fired when the buffer falls below watermark
* (default is empty). If all the data has been written, disable the write
* event.
*/
static void static void
job_write_callback(__unused struct bufferevent *bufev, void *data) job_write_callback(__unused struct bufferevent *bufev, void *data)
{ {
@@ -160,7 +182,7 @@ job_write_callback(__unused struct bufferevent *bufev, void *data)
/* Job buffer error callback. */ /* Job buffer error callback. */
static void static void
job_callback(__unused struct bufferevent *bufev, __unused short events, job_error_callback(__unused struct bufferevent *bufev, __unused short events,
void *data) void *data)
{ {
struct job *job = data; struct job *job = data;
@@ -168,8 +190,8 @@ job_callback(__unused struct bufferevent *bufev, __unused short events,
log_debug("job error %p: %s, pid %ld", job, job->cmd, (long) job->pid); log_debug("job error %p: %s, pid %ld", job, job->cmd, (long) job->pid);
if (job->state == JOB_DEAD) { if (job->state == JOB_DEAD) {
if (job->callbackfn != NULL) if (job->completecb != NULL)
job->callbackfn(job); job->completecb(job);
job_free(job); job_free(job);
} else { } else {
bufferevent_disable(job->event, EV_READ); bufferevent_disable(job->event, EV_READ);
@@ -186,8 +208,8 @@ job_died(struct job *job, int status)
job->status = status; job->status = status;
if (job->state == JOB_CLOSED) { if (job->state == JOB_CLOSED) {
if (job->callbackfn != NULL) if (job->completecb != NULL)
job->callbackfn(job); job->completecb(job);
job_free(job); job_free(job);
} else { } else {
job->pid = -1; job->pid = -1;

View File

@@ -84,7 +84,7 @@ key_bindings_unref_table(struct key_table *table)
} }
void void
key_bindings_add(const char *name, key_code key, int can_repeat, key_bindings_add(const char *name, key_code key, int repeat,
struct cmd_list *cmdlist) struct cmd_list *cmdlist)
{ {
struct key_table *table; struct key_table *table;
@@ -92,7 +92,7 @@ key_bindings_add(const char *name, key_code key, int can_repeat,
table = key_bindings_get_table(name, 1); table = key_bindings_get_table(name, 1);
bd_find.key = key; bd_find.key = (key & ~KEYC_XTERM);
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find); bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
if (bd != NULL) { if (bd != NULL) {
RB_REMOVE(key_bindings, &table->key_bindings, bd); RB_REMOVE(key_bindings, &table->key_bindings, bd);
@@ -100,11 +100,12 @@ key_bindings_add(const char *name, key_code key, int can_repeat,
free(bd); free(bd);
} }
bd = xmalloc(sizeof *bd); bd = xcalloc(1, sizeof *bd);
bd->key = key; bd->key = key;
RB_INSERT(key_bindings, &table->key_bindings, bd); RB_INSERT(key_bindings, &table->key_bindings, bd);
bd->can_repeat = can_repeat; if (repeat)
bd->flags |= KEY_BINDING_REPEAT;
bd->cmdlist = cmdlist; bd->cmdlist = cmdlist;
} }
@@ -118,7 +119,7 @@ key_bindings_remove(const char *name, key_code key)
if (table == NULL) if (table == NULL)
return; return;
bd_find.key = key; bd_find.key = (key & ~KEYC_XTERM);
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find); bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
if (bd == NULL) if (bd == NULL)
return; return;
@@ -415,7 +416,8 @@ key_bindings_dispatch(struct key_binding *bd, struct client *c,
cmdq_append(c, cmdq_get_callback(key_bindings_read_only, NULL)); cmdq_append(c, cmdq_get_callback(key_bindings_read_only, NULL));
else { else {
item = cmdq_get_command(bd->cmdlist, fs, m, 0); item = cmdq_get_command(bd->cmdlist, fs, m, 0);
item->repeat = bd->can_repeat; if (bd->flags & KEY_BINDING_REPEAT)
item->shared->flags |= CMDQ_SHARED_REPEAT;
cmdq_append(c, item); cmdq_append(c, item);
} }
} }

View File

@@ -124,7 +124,7 @@ format_window_name(struct window *w)
const char *fmt; const char *fmt;
char *name; char *name;
ft = format_create(NULL, FORMAT_WINDOW|w->id, 0); ft = format_create(NULL, NULL, FORMAT_WINDOW|w->id, 0);
format_defaults_window(ft, w); format_defaults_window(ft, w);
format_defaults_pane(ft, w->active); format_defaults_pane(ft, w->active);

View File

@@ -43,9 +43,9 @@ notify_hook(struct cmdq_item *item, struct notify_entry *ne)
struct session *s = ne->session; struct session *s = ne->session;
struct window *w = ne->window; struct window *w = ne->window;
cmd_find_clear_state(&fs, NULL, 0); cmd_find_clear_state(&fs, 0);
if (cmd_find_empty_state(&ne->fs) || !cmd_find_valid_state(&ne->fs)) if (cmd_find_empty_state(&ne->fs) || !cmd_find_valid_state(&ne->fs))
cmd_find_current(&fs, item, CMD_FIND_QUIET); cmd_find_from_nothing(&fs);
else else
cmd_find_copy_state(&fs, &ne->fs); cmd_find_copy_state(&fs, &ne->fs);
@@ -78,8 +78,12 @@ notify_callback(struct cmdq_item *item, void *data)
log_debug("%s: %s", __func__, ne->name); log_debug("%s: %s", __func__, ne->name);
if (strcmp(ne->name, "pane-mode-changed") == 0)
control_notify_pane_mode_changed(ne->pane);
if (strcmp(ne->name, "window-layout-changed") == 0) if (strcmp(ne->name, "window-layout-changed") == 0)
control_notify_window_layout_changed(ne->window); control_notify_window_layout_changed(ne->window);
if (strcmp(ne->name, "window-pane-changed") == 0)
control_notify_window_pane_changed(ne->window);
if (strcmp(ne->name, "window-unlinked") == 0) if (strcmp(ne->name, "window-unlinked") == 0)
control_notify_window_unlinked(ne->session, ne->window); control_notify_window_unlinked(ne->session, ne->window);
if (strcmp(ne->name, "window-linked") == 0) if (strcmp(ne->name, "window-linked") == 0)
@@ -94,18 +98,20 @@ notify_callback(struct cmdq_item *item, void *data)
control_notify_session_created(ne->session); control_notify_session_created(ne->session);
if (strcmp(ne->name, "session-closed") == 0) if (strcmp(ne->name, "session-closed") == 0)
control_notify_session_closed(ne->session); control_notify_session_closed(ne->session);
if (strcmp(ne->name, "session-window-changed") == 0)
control_notify_session_window_changed(ne->session);
notify_hook(item, ne); notify_hook(item, ne);
if (ne->client != NULL) if (ne->client != NULL)
server_client_unref(ne->client); server_client_unref(ne->client);
if (ne->session != NULL) if (ne->session != NULL)
session_unref(ne->session); session_remove_ref(ne->session, __func__);
if (ne->window != NULL) if (ne->window != NULL)
window_remove_ref(ne->window); window_remove_ref(ne->window, __func__);
if (ne->fs.s != NULL) if (ne->fs.s != NULL)
session_unref(ne->fs.s); session_remove_ref(ne->fs.s, __func__);
free((void *)ne->name); free((void *)ne->name);
free(ne); free(ne);
@@ -135,13 +141,13 @@ notify_add(const char *name, struct cmd_find_state *fs, struct client *c,
if (c != NULL) if (c != NULL)
c->references++; c->references++;
if (s != NULL) if (s != NULL)
s->references++; session_add_ref(s, __func__);
if (w != NULL) if (w != NULL)
w->references++; window_add_ref(w, __func__);
cmd_find_copy_state(&ne->fs, fs); cmd_find_copy_state(&ne->fs, fs);
if (ne->fs.s != NULL) if (ne->fs.s != NULL) /* cmd_find_valid_state needs session */
ne->fs.s->references++; /* cmd_find_valid_state need session */ session_add_ref(ne->fs.s, __func__);
new_item = cmdq_get_callback(notify_callback, ne); new_item = cmdq_get_callback(notify_callback, ne);
cmdq_append(NULL, new_item); cmdq_append(NULL, new_item);
@@ -163,10 +169,7 @@ notify_client(const char *name, struct client *c)
{ {
struct cmd_find_state fs; struct cmd_find_state fs;
if (c->session != NULL) cmd_find_from_client(&fs, c);
cmd_find_from_session(&fs, c->session);
else
cmd_find_current(&fs, NULL, CMD_FIND_QUIET);
notify_add(name, &fs, c, NULL, NULL, NULL); notify_add(name, &fs, c, NULL, NULL, NULL);
} }
@@ -178,17 +181,17 @@ notify_session(const char *name, struct session *s)
if (session_alive(s)) if (session_alive(s))
cmd_find_from_session(&fs, s); cmd_find_from_session(&fs, s);
else else
cmd_find_current(&fs, NULL, CMD_FIND_QUIET); cmd_find_from_nothing(&fs);
notify_add(name, &fs, NULL, s, NULL, NULL); notify_add(name, &fs, NULL, s, NULL, NULL);
} }
void void
notify_winlink(const char *name, struct session *s, struct winlink *wl) notify_winlink(const char *name, struct winlink *wl)
{ {
struct cmd_find_state fs; struct cmd_find_state fs;
cmd_find_from_winlink(&fs, s, wl); cmd_find_from_winlink(&fs, wl);
notify_add(name, &fs, NULL, s, wl->window, NULL); notify_add(name, &fs, NULL, wl->session, wl->window, NULL);
} }
void void

View File

@@ -433,7 +433,7 @@ options_match(const char *s, int *idx, int* ambiguous)
if (*name == '@') { if (*name == '@') {
*ambiguous = 0; *ambiguous = 0;
return (xstrdup(name)); return (name);
} }
found = NULL; found = NULL;

88
pty.c
View File

@@ -1,88 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#ifdef __OpenBSD__
#include <sys/tty.h>
#endif
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "compat.h"
int pty_open(int *);
pid_t pty_fork(int, int *, char *, size_t, struct winsize *);
#ifdef __OpenBSD__
int
pty_open(int *fd)
{
*fd = open(PATH_PTMDEV, O_RDWR|O_CLOEXEC);
if (*fd < 0)
return (-1);
return (0);
}
#else
int
pty_open(__unused int *fd)
{
*fd = -1;
return (0);
}
#endif
#ifdef __OpenBSD__
pid_t
pty_fork(int ptmfd, int *fd, char *name, size_t namelen, struct winsize *ws)
{
struct ptmget ptm;
pid_t pid;
if (ioctl(ptmfd, PTMGET, &ptm) == -1)
return (-1);
strlcpy(name, ptm.sn, namelen);
ioctl(ptm.sfd, TIOCSWINSZ, ws);
switch (pid = fork()) {
case -1:
close(ptm.cfd);
close(ptm.sfd);
return (-1);
case 0:
close(ptm.cfd);
login_tty(ptm.sfd);
return (0);
}
*fd = ptm.cfd;
close(ptm.sfd);
return (pid);
}
#else
pid_t
pty_fork(__unused int ptmfd, int *fd, char *name, __unused size_t namelen,
struct winsize *ws)
{
return (forkpty(fd, name, NULL, ws));
}
#endif

9
regress/Makefile Normal file
View File

@@ -0,0 +1,9 @@
TESTS!= echo *.sh
.PHONY: all $(TESTS)
.NOTPARALLEL: all $(TESTS)
all: $(TESTS)
$(TESTS):
sh $*.sh

View File

@@ -0,0 +1,24 @@
#!/bin/sh
# 884
# capture-pane should send colours after SGR 0
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 15
$TMUX -f/dev/null new -d \
"printf '\033[31;42;1mabc\033[0;31mdef'; $TMUX capturep -peS0 -E0 >$TMP"
sleep 1
printf '\033[1m\033[31m\033[42mabc\033[0m\033[31m\033[49mdef\033[39m\n'| \
cmp - $TMP || exit 1
$TMUX has 2>/dev/null && exit 1
exit 0

30
regress/if-shell-TERM.sh Normal file
View File

@@ -0,0 +1,30 @@
#!/bin/sh
# 882
# TERM should come from outside tmux for if-shell from the config file
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 15
cat <<EOF >$TMP
if '[ "\$TERM" = "xterm" ]' \
'set -g default-terminal "vt220"' \
'set -g default-terminal "ansi"'
EOF
TERM=xterm $TMUX -f$TMP new -d "echo \"#\$TERM\" >>$TMP" || exit 1
sleep 1 && [ "$(tail -1 $TMP)" = "#vt220" ] || exit 1
TERM=screen $TMUX -f$TMP new -d "echo \"#\$TERM\" >>$TMP" || exit 1
sleep 1 && [ "$(tail -1 $TMP)" = "#ansi" ] || exit 1
$TMUX has 2>/dev/null && exit 1
exit 0

26
regress/if-shell-error.sh Normal file
View File

@@ -0,0 +1,26 @@
#!/bin/sh
# 883
# if-shell with an error should not core :-)
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 15
cat <<EOF >$TMP
if 'true' 'wibble wobble'
EOF
$TMUX -f$TMP new -d || exit 1
sleep 1
E=$($TMUX display -p '#{pane_in_mode}')
$TMUX kill-server 2>/dev/null
[ "$E" = "1" ] || exit 1
exit 0

View File

@@ -0,0 +1,25 @@
#!/bin/sh
# 882
# tmux inside if-shell itself should work
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 15
cat <<EOF >$TMP
if '$TMUX run "true"' 'set -s @done yes'
EOF
TERM=xterm $TMUX -f$TMP new -d "$TMUX show -vs @done >>$TMP" || exit 1
sleep 1 && [ "$(tail -1 $TMP)" = "yes" ] || exit 1
$TMUX has 2>/dev/null && exit 1
exit 0

View File

@@ -0,0 +1,21 @@
#!/bin/sh
# when we kill a session, processes running in it should be killed
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null
$TMUX new -d 'sleep 1000' || exit 1
P=$($TMUX display -pt0:0.0 '#{pane_pid}')
$TMUX new -d || exit 1
sleep 1
$TMUX kill-session -t0:
sleep 1
kill -0 $P 2>/dev/null && exit 1
$TMUX kill-server 2>/dev/null
exit 0

View File

@@ -0,0 +1,27 @@
#!/bin/sh
# new session base-index
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 15
cat <<EOF >$TMP
set -g base-index 100
new
set base-index 200
neww
EOF
$TMUX -f$TMP start
echo $($TMUX lsw -F'#{window_index}') >$TMP
(echo "100 200"|cmp -s - $TMP) || exit 1
$TMUX kill-server 2>/dev/null
exit 0

View File

@@ -0,0 +1,25 @@
#!/bin/sh
# new session command
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 15
cat <<EOF >$TMP
new sleep 101
new -- sleep 102
new "sleep 103"
EOF
$TMUX -f$TMP start
[ $($TMUX ls|wc -l) -eq 3 ] || exit 1
$TMUX kill-server 2>/dev/null
exit 0

View File

@@ -0,0 +1,66 @@
#!/bin/sh
# new session environment
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)
OUT=$(mktemp)
SCRIPT=$(mktemp)
trap "rm -f $TMP $OUT $SCRIPT" 0 1 15
cat <<EOF >$SCRIPT
(
echo TERM=\$TERM
echo PWD=\$(pwd)
echo PATH=\$PATH
echo SHELL=\$SHELL
echo TEST=\$TEST
) >$OUT
EOF
cat <<EOF >$TMP
new -- /bin/sh $SCRIPT
EOF
(cd /; env -i TERM=ansi TEST=test1 PATH=1 SHELL=/bin/sh \
$TMUX -f$TMP start) || exit 1
sleep 1
(cat <<EOF|cmp -s - $OUT) || exit 1
TERM=screen
PWD=/
PATH=1
SHELL=/bin/sh
TEST=test1
EOF
(cd /; env -i TERM=ansi TEST=test2 PATH=2 SHELL=/bin/sh \
$TMUX -f$TMP new -d -- /bin/sh $SCRIPT) || exit 1
sleep 1
(cat <<EOF|cmp -s - $OUT) || exit 1
TERM=screen
PWD=/
PATH=2
SHELL=/bin/sh
TEST=test2
EOF
(cd /; env -i TERM=ansi TEST=test3 PATH=3 SHELL=/bin/sh \
$TMUX -f/dev/null new -d source $TMP) || exit 1
sleep 1
(cat <<EOF|cmp -s - $OUT) || exit 1
TERM=screen
PWD=/
PATH=2
SHELL=/bin/sh
TEST=test2
EOF
$TMUX kill-server 2>/dev/null
exit 0

View File

@@ -0,0 +1,25 @@
#!/bin/sh
# 869
# new with no client (that is, from the config file) should imply -d and
# not attach
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 15
cat <<EOF >$TMP
new -stest
EOF
$TMUX -f$TMP start || exit 1
sleep 1 && $TMUX has -t=test: || exit 1
$TMUX kill-server 2>/dev/null
exit 0

View File

@@ -0,0 +1,26 @@
#!/bin/sh
# new session command
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 15
cat <<EOF >$TMP
new
neww sleep 101
neww -- sleep 102
neww "sleep 103"
EOF
$TMUX -f$TMP start
[ $($TMUX lsw|wc -l) -eq 4 ] || exit 1
$TMUX kill-server 2>/dev/null
exit 0

View File

@@ -280,7 +280,7 @@ screen_redraw_make_pane_status(struct client *c, struct window *w,
fmt = options_get_string(w->options, "pane-border-format"); fmt = options_get_string(w->options, "pane-border-format");
ft = format_create(NULL, FORMAT_PANE|wp->id, 0); ft = format_create(c, NULL, FORMAT_PANE|wp->id, 0);
format_defaults(ft, c, NULL, NULL, wp); format_defaults(ft, c, NULL, NULL, wp);
memcpy(&old, &wp->status_screen, sizeof old); memcpy(&old, &wp->status_screen, sizeof old);

View File

@@ -41,6 +41,7 @@ static const struct grid_cell screen_write_pad_cell = {
struct screen_write_collect_item { struct screen_write_collect_item {
u_int x; u_int x;
int wrapped;
u_int used; u_int used;
char data[256]; char data[256];
@@ -386,6 +387,8 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
{ {
struct screen *s = ctx->s; struct screen *s = ctx->s;
memset(ttyctx, 0, sizeof *ttyctx);
ttyctx->wp = ctx->wp; ttyctx->wp = ctx->wp;
ttyctx->ocx = s->cx; ttyctx->ocx = s->cx;
@@ -605,7 +608,7 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
/* Clear nx characters. */ /* Clear nx characters. */
void void
screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx) screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
{ {
struct screen *s = ctx->s; struct screen *s = ctx->s;
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
@@ -622,8 +625,9 @@ screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx)
return; return;
screen_write_initctx(ctx, &ttyctx); screen_write_initctx(ctx, &ttyctx);
ttyctx.bg = bg;
grid_view_clear(s->grid, s->cx, s->cy, nx, 1, 8); grid_view_clear(s->grid, s->cx, s->cy, nx, 1, bg);
screen_write_collect_flush(ctx, 0); screen_write_collect_flush(ctx, 0);
ttyctx.num = nx; ttyctx.num = nx;
@@ -942,9 +946,9 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg)
if (s->cy > 0) if (s->cy > 0)
grid_view_clear(s->grid, 0, 0, sx, s->cy, bg); grid_view_clear(s->grid, 0, 0, sx, s->cy, bg);
if (s->cx > sx - 1) if (s->cx > sx - 1)
grid_view_clear(s->grid, 0, s->cy, sx, 1, 8); grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
else else
grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, 8); grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg);
screen_write_collect_clear(ctx, 0, s->cy); screen_write_collect_clear(ctx, 0, s->cy);
screen_write_collect_flush(ctx, 0); screen_write_collect_flush(ctx, 0);
@@ -1054,6 +1058,7 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only)
screen_write_cursormove(ctx, ci->x, y); screen_write_cursormove(ctx, ci->x, y);
screen_write_initctx(ctx, &ttyctx); screen_write_initctx(ctx, &ttyctx);
ttyctx.cell = &ci->gc; ttyctx.cell = &ci->gc;
ttyctx.wrapped = ci->wrapped;
ttyctx.ptr = ci->data; ttyctx.ptr = ci->data;
ttyctx.num = ci->used; ttyctx.num = ci->used;
tty_write(tty_cmd_cells, &ttyctx); tty_write(tty_cmd_cells, &ttyctx);
@@ -1113,7 +1118,7 @@ screen_write_collect_add(struct screen_write_ctx *ctx,
*/ */
collect = 1; collect = 1;
if (gc->data.width != 1) if (gc->data.width != 1 || gc->data.size != 1)
collect = 0; collect = 0;
else if (gc->attr & GRID_ATTR_CHARSET) else if (gc->attr & GRID_ATTR_CHARSET)
collect = 0; collect = 0;
@@ -1133,13 +1138,15 @@ screen_write_collect_add(struct screen_write_ctx *ctx,
if (s->cx > sx - 1 || ctx->item->used > sx - 1 - s->cx) if (s->cx > sx - 1 || ctx->item->used > sx - 1 - s->cx)
screen_write_collect_end(ctx); screen_write_collect_end(ctx);
ci = ctx->item; /* may have changed */
if (s->cx > sx - 1) { if (s->cx > sx - 1) {
log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy); log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy);
ci->wrapped = 1;
screen_write_linefeed(ctx, 1); screen_write_linefeed(ctx, 1);
s->cx = 0; s->cx = 0;
} }
ci = ctx->item; /* may have changed */
if (ci->used == 0) if (ci->used == 0)
memcpy(&ci->gc, gc, sizeof ci->gc); memcpy(&ci->gc, gc, sizeof ci->gc);
ci->data[ci->used++] = gc->data.data[0]; ci->data[ci->used++] = gc->data.data[0];
@@ -1312,12 +1319,12 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud,
fatalx("UTF-8 data empty"); fatalx("UTF-8 data empty");
/* Retrieve the previous cell. */ /* Retrieve the previous cell. */
for (n = 1; n < s->cx; n++) { for (n = 1; n <= s->cx; n++) {
grid_view_get_cell(gd, s->cx - n, s->cy, &gc); grid_view_get_cell(gd, s->cx - n, s->cy, &gc);
if (~gc.flags & GRID_FLAG_PADDING) if (~gc.flags & GRID_FLAG_PADDING)
break; break;
} }
if (n == s->cx) if (n > s->cx)
return (NULL); return (NULL);
*xx = s->cx - n; *xx = s->cx - n;

View File

@@ -47,7 +47,7 @@ static void server_client_dispatch_command(struct client *, struct imsg *);
static void server_client_dispatch_identify(struct client *, struct imsg *); static void server_client_dispatch_identify(struct client *, struct imsg *);
static void server_client_dispatch_shell(struct client *); static void server_client_dispatch_shell(struct client *);
/* Idenfity mode callback. */ /* Identify mode callback. */
static void static void
server_client_callback_identify(__unused int fd, __unused short events, void *data) server_client_callback_identify(__unused int fd, __unused short events, void *data)
{ {
@@ -136,11 +136,11 @@ server_client_get_key_table(struct client *c)
return (name); return (name);
} }
/* Is this client using the default key table? */ /* Is this table the default key table? */
int static int
server_client_is_default_key_table(struct client *c) server_client_is_default_key_table(struct client *c, struct key_table *table)
{ {
return (strcmp(c->keytable->name, server_client_get_key_table(c)) == 0); return (strcmp(table->name, server_client_get_key_table(c)) == 0);
} }
/* Create a new client. */ /* Create a new client. */
@@ -281,6 +281,7 @@ server_client_lost(struct client *c)
free(c->prompt_string); free(c->prompt_string);
free(c->prompt_buffer); free(c->prompt_buffer);
format_lost_client(c);
environ_free(c->environ); environ_free(c->environ);
proc_remove_peer(c->peer); proc_remove_peer(c->peer);
@@ -323,15 +324,30 @@ server_client_free(__unused int fd, __unused short events, void *arg)
} }
} }
/* Suspend a client. */
void
server_client_suspend(struct client *c)
{
struct session *s = c->session;
if (s == NULL || (c->flags & CLIENT_DETACHING))
return;
tty_stop_tty(&c->tty);
c->flags |= CLIENT_SUSPENDED;
proc_send(c->peer, MSG_SUSPEND, -1, NULL, 0);
}
/* Detach a client. */ /* Detach a client. */
void void
server_client_detach(struct client *c, enum msgtype msgtype) server_client_detach(struct client *c, enum msgtype msgtype)
{ {
struct session *s = c->session; struct session *s = c->session;
if (s == NULL) if (s == NULL || (c->flags & CLIENT_DETACHING))
return; return;
c->flags |= CLIENT_DETACHING;
notify_client("client-detached", c); notify_client("client-detached", c);
proc_send_s(c->peer, msgtype, s->name); proc_send_s(c->peer, msgtype, s->name);
} }
@@ -776,8 +792,7 @@ server_client_handle_key(struct client *c, key_code key)
struct window *w; struct window *w;
struct window_pane *wp; struct window_pane *wp;
struct timeval tv; struct timeval tv;
const char *name; struct key_table *table, *first;
struct key_table *table;
struct key_binding bd_find, *bd; struct key_binding bd_find, *bd;
int xtimeout; int xtimeout;
struct cmd_find_state fs; struct cmd_find_state fs;
@@ -840,10 +855,9 @@ server_client_handle_key(struct client *c, key_code key)
m->valid = 0; m->valid = 0;
/* Find affected pane. */ /* Find affected pane. */
if (KEYC_IS_MOUSE(key) && m->valid) if (!KEYC_IS_MOUSE(key) || cmd_find_from_mouse(&fs, m) != 0)
wp = cmd_mouse_pane(m, NULL, NULL); cmd_find_from_session(&fs, s);
else wp = fs.wp;
wp = w->active;
/* Forward mouse keys if disabled. */ /* Forward mouse keys if disabled. */
if (KEYC_IS_MOUSE(key) && !options_get_number(s->options, "mouse")) if (KEYC_IS_MOUSE(key) && !options_get_number(s->options, "mouse"))
@@ -853,22 +867,18 @@ server_client_handle_key(struct client *c, key_code key)
if (!KEYC_IS_MOUSE(key) && server_client_assume_paste(s)) if (!KEYC_IS_MOUSE(key) && server_client_assume_paste(s))
goto forward; goto forward;
retry:
/* /*
* Work out the current key table. If the pane is in a mode, use * Work out the current key table. If the pane is in a mode, use
* the mode table instead of the default key table. * the mode table instead of the default key table.
*/ */
name = NULL; if (server_client_is_default_key_table(c, c->keytable) &&
if (wp != NULL && wp->mode != NULL && wp->mode->key_table != NULL) wp != NULL &&
name = wp->mode->key_table(wp); wp->mode != NULL &&
if (name == NULL || !server_client_is_default_key_table(c)) wp->mode->key_table != NULL)
table = key_bindings_get_table(wp->mode->key_table(wp), 1);
else
table = c->keytable; table = c->keytable;
else first = table;
table = key_bindings_get_table(name, 1);
if (wp == NULL)
log_debug("key table %s (no pane)", table->name);
else
log_debug("key table %s (pane %%%u)", table->name, wp->id);
/* /*
* The prefix always takes precedence and forces a switch to the prefix * The prefix always takes precedence and forces a switch to the prefix
@@ -882,8 +892,17 @@ retry:
return; return;
} }
retry:
/* Log key table. */
if (wp == NULL)
log_debug("key table %s (no pane)", table->name);
else
log_debug("key table %s (pane %%%u)", table->name, wp->id);
if (c->flags & CLIENT_REPEAT)
log_debug("currently repeating");
/* Try to see if there is a key binding in the current table. */ /* Try to see if there is a key binding in the current table. */
bd_find.key = key; bd_find.key = (key & ~KEYC_XTERM);
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find); bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
if (bd != NULL) { if (bd != NULL) {
/* /*
@@ -891,12 +910,15 @@ retry:
* non-repeating binding was found, stop repeating and try * non-repeating binding was found, stop repeating and try
* again in the root table. * again in the root table.
*/ */
if ((c->flags & CLIENT_REPEAT) && !bd->can_repeat) { if ((c->flags & CLIENT_REPEAT) &&
(~bd->flags & KEY_BINDING_REPEAT)) {
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
c->flags &= ~CLIENT_REPEAT; c->flags &= ~CLIENT_REPEAT;
server_status_client(c); server_status_client(c);
table = c->keytable;
goto retry; goto retry;
} }
log_debug("found in key table %s", table->name);
/* /*
* Take a reference to this table to make sure the key binding * Take a reference to this table to make sure the key binding
@@ -909,7 +931,7 @@ retry:
* the client back to the root table. * the client back to the root table.
*/ */
xtimeout = options_get_number(s->options, "repeat-time"); xtimeout = options_get_number(s->options, "repeat-time");
if (xtimeout != 0 && bd->can_repeat) { if (xtimeout != 0 && (bd->flags & KEY_BINDING_REPEAT)) {
c->flags |= CLIENT_REPEAT; c->flags |= CLIENT_REPEAT;
tv.tv_sec = xtimeout / 1000; tv.tv_sec = xtimeout / 1000;
@@ -922,39 +944,31 @@ retry:
} }
server_status_client(c); server_status_client(c);
/* Find default state if the pane is known. */ /* Execute the key binding. */
cmd_find_clear_state(&fs, NULL, 0);
if (wp != NULL) {
fs.s = s;
fs.wl = fs.s->curw;
fs.w = fs.wl->window;
fs.wp = wp;
cmd_find_log_state(__func__, &fs);
if (!cmd_find_valid_state(&fs))
fatalx("invalid key state");
}
/* Dispatch the key binding. */
key_bindings_dispatch(bd, c, m, &fs); key_bindings_dispatch(bd, c, m, &fs);
key_bindings_unref_table(table); key_bindings_unref_table(table);
return; return;
} }
/* /*
* No match in this table. If repeating, switch the client back to the * No match in this table. If not in the root table or if repeating,
* root table and try again. * switch the client back to the root table and try again.
*/ */
if (c->flags & CLIENT_REPEAT) { log_debug("not found in key table %s", table->name);
if (!server_client_is_default_key_table(c, table) ||
(c->flags & CLIENT_REPEAT)) {
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
c->flags &= ~CLIENT_REPEAT; c->flags &= ~CLIENT_REPEAT;
server_status_client(c); server_status_client(c);
table = c->keytable;
goto retry; goto retry;
} }
/* If no match and we're not in the root table, that's it. */ /*
if (name == NULL && !server_client_is_default_key_table(c)) { * No match in the root table either. If this wasn't the first table
log_debug("no key in key table %s", table->name); * tried, don't pass the key to the pane.
*/
if (first != table) {
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
server_status_client(c); server_status_client(c);
return; return;
@@ -1209,6 +1223,14 @@ server_client_check_exit(struct client *c)
c->flags &= ~CLIENT_EXIT; c->flags &= ~CLIENT_EXIT;
} }
/* Redraw timer callback. */
static void
server_client_redraw_timer(__unused int fd, __unused short events,
__unused void* data)
{
log_debug("redraw timer fired");
}
/* Check for client redraws. */ /* Check for client redraws. */
static void static void
server_client_check_redraw(struct client *c) server_client_check_redraw(struct client *c)
@@ -1216,19 +1238,61 @@ server_client_check_redraw(struct client *c)
struct session *s = c->session; struct session *s = c->session;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct window_pane *wp; struct window_pane *wp;
int flags, masked; int needed, flags, masked;
struct timeval tv = { .tv_usec = 1000 };
static struct event ev;
size_t left;
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
return; return;
/*
* If there is outstanding data, defer the redraw until it has been
* consumed. We can just add a timer to get out of the event loop and
* end up back here.
*/
needed = 0;
if (c->flags & CLIENT_REDRAW)
needed = 1;
else {
TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
if (wp->flags & PANE_REDRAW) {
needed = 1;
break;
}
}
}
if (needed) {
left = EVBUFFER_LENGTH(tty->out);
if (left != 0) {
log_debug("%s: redraw deferred (%zu left)", c->name, left);
if (evtimer_initialized(&ev) && evtimer_pending(&ev, NULL))
return;
log_debug("redraw timer started");
evtimer_set(&ev, server_client_redraw_timer, NULL);
evtimer_add(&ev, &tv);
/*
* We may have got here for a single pane redraw, but
* force a full redraw next time in case other panes
* have been updated.
*/
c->flags |= CLIENT_REDRAW;
return;
}
if (evtimer_initialized(&ev))
evtimer_del(&ev);
log_debug("%s: redraw needed", c->name);
}
if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
if (options_get_number(s->options, "set-titles")) if (options_get_number(s->options, "set-titles"))
server_client_set_title(c); server_client_set_title(c);
screen_redraw_update(c); /* will adjust flags */ screen_redraw_update(c); /* will adjust flags */
} }
flags = tty->flags & (TTY_FREEZE|TTY_NOCURSOR); flags = tty->flags & (TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR);
tty->flags = (tty->flags & ~TTY_FREEZE) | TTY_NOCURSOR; tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE)) | TTY_NOCURSOR;
if (c->flags & CLIENT_REDRAW) { if (c->flags & CLIENT_REDRAW) {
tty_update_mode(tty, tty->mode, NULL); tty_update_mode(tty, tty->mode, NULL);
@@ -1258,6 +1322,16 @@ server_client_check_redraw(struct client *c)
c->flags &= ~(CLIENT_REDRAW|CLIENT_BORDERS|CLIENT_STATUS| c->flags &= ~(CLIENT_REDRAW|CLIENT_BORDERS|CLIENT_STATUS|
CLIENT_STATUSFORCE); CLIENT_STATUSFORCE);
if (needed) {
/*
* We would have deferred the redraw unless the output buffer
* was empty, so we can record how many bytes the redraw
* generated.
*/
c->redraw = EVBUFFER_LENGTH(tty->out);
log_debug("%s: redraw added %zu bytes", c->name, c->redraw);
}
} }
/* Set client title. */ /* Set client title. */
@@ -1271,7 +1345,7 @@ server_client_set_title(struct client *c)
template = options_get_string(s->options, "set-titles-string"); template = options_get_string(s->options, "set-titles-string");
ft = format_create(NULL, FORMAT_NONE, 0); ft = format_create(c, NULL, FORMAT_NONE, 0);
format_defaults(ft, c, NULL, NULL, NULL); format_defaults(ft, c, NULL, NULL, NULL);
title = format_expand_time(ft, template, time(NULL)); title = format_expand_time(ft, template, time(NULL));

View File

@@ -62,7 +62,7 @@ static void server_child_stopped(pid_t, int);
void void
server_set_marked(struct session *s, struct winlink *wl, struct window_pane *wp) server_set_marked(struct session *s, struct winlink *wl, struct window_pane *wp)
{ {
cmd_find_clear_state(&marked_pane, NULL, 0); cmd_find_clear_state(&marked_pane, 0);
marked_pane.s = s; marked_pane.s = s;
marked_pane.wl = wl; marked_pane.wl = wl;
marked_pane.w = wl->window; marked_pane.w = wl->window;
@@ -73,7 +73,7 @@ server_set_marked(struct session *s, struct winlink *wl, struct window_pane *wp)
void void
server_clear_marked(void) server_clear_marked(void)
{ {
cmd_find_clear_state(&marked_pane, NULL, 0); cmd_find_clear_state(&marked_pane, 0);
} }
/* Is this the marked pane? */ /* Is this the marked pane? */
@@ -118,12 +118,16 @@ server_create_socket(void)
return (-1); return (-1);
mask = umask(S_IXUSR|S_IXGRP|S_IRWXO); mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
close(fd);
return (-1); return (-1);
}
umask(mask); umask(mask);
if (listen(fd, 128) == -1) if (listen(fd, 128) == -1) {
close(fd);
return (-1); return (-1);
}
setblocking(fd, 0); setblocking(fd, 0);
return (fd); return (fd);
@@ -133,7 +137,8 @@ server_create_socket(void)
int int
server_start(struct event_base *base, int lockfd, char *lockfile) server_start(struct event_base *base, int lockfd, char *lockfile)
{ {
int pair[2]; int pair[2];
struct job *job;
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
fatal("socketpair failed"); fatal("socketpair failed");
@@ -174,11 +179,15 @@ server_start(struct event_base *base, int lockfd, char *lockfile)
start_cfg(); start_cfg();
status_prompt_load_history();
server_add_accept(0); server_add_accept(0);
proc_loop(server_proc, server_loop); proc_loop(server_proc, server_loop);
LIST_FOREACH(job, &all_jobs, entry) {
if (job->pid != -1)
kill(job->pid, SIGTERM);
}
status_prompt_save_history(); status_prompt_save_history();
exit(0); exit(0);
} }
@@ -399,7 +408,7 @@ server_child_exited(pid_t pid, int status)
} }
} }
LIST_FOREACH(job, &all_jobs, lentry) { LIST_FOREACH(job, &all_jobs, entry) {
if (pid == job->pid) { if (pid == job->pid) {
job_died(job, status); /* might free job */ job_died(job, status); /* might free job */
break; break;

View File

@@ -188,13 +188,21 @@ session_create(const char *prefix, const char *name, int argc, char **argv,
return (s); return (s);
} }
/* Add a reference to a session. */
void
session_add_ref(struct session *s, const char *from)
{
s->references++;
log_debug("%s: %s %s, now %d", __func__, s->name, from, s->references);
}
/* Remove a reference from a session. */ /* Remove a reference from a session. */
void void
session_unref(struct session *s) session_remove_ref(struct session *s, const char *from)
{ {
log_debug("session %s has %d references", s->name, s->references);
s->references--; s->references--;
log_debug("%s: %s %s, now %d", __func__, s->name, from, s->references);
if (s->references == 0) if (s->references == 0)
event_once(-1, EV_TIMEOUT, session_free, s, NULL); event_once(-1, EV_TIMEOUT, session_free, s, NULL);
} }
@@ -247,7 +255,7 @@ session_destroy(struct session *s)
free((void *)s->cwd); free((void *)s->cwd);
session_unref(s); session_remove_ref(s, __func__);
} }
/* Check a session name is valid: not empty and no colons or periods. */ /* Check a session name is valid: not empty and no colons or periods. */
@@ -359,7 +367,7 @@ session_new(struct session *s, const char *name, int argc, char **argv,
shell = _PATH_BSHELL; shell = _PATH_BSHELL;
hlimit = options_get_number(s->options, "history-limit"); hlimit = options_get_number(s->options, "history-limit");
env = environ_for_session(s); env = environ_for_session(s, 0);
w = window_create_spawn(name, argc, argv, path, shell, cwd, env, s->tio, w = window_create_spawn(name, argc, argv, path, shell, cwd, env, s->tio,
s->sx, s->sy, hlimit, cause); s->sx, s->sy, hlimit, cause);
if (w == NULL) { if (w == NULL) {
@@ -544,6 +552,7 @@ session_set_current(struct session *s, struct winlink *wl)
s->curw = wl; s->curw = wl;
winlink_clear_flags(wl); winlink_clear_flags(wl);
window_update_activity(wl->window); window_update_activity(wl->window);
notify_session("session-window-changed", s);
return (0); return (0);
} }

View File

@@ -519,9 +519,9 @@ status_replace(struct client *c, struct winlink *wl, const char *fmt, time_t t)
else else
tag = FORMAT_NONE; tag = FORMAT_NONE;
if (c->flags & CLIENT_STATUSFORCE) if (c->flags & CLIENT_STATUSFORCE)
ft = format_create(NULL, tag, FORMAT_STATUS|FORMAT_FORCE); ft = format_create(c, NULL, tag, FORMAT_STATUS|FORMAT_FORCE);
else else
ft = format_create(NULL, tag, FORMAT_STATUS); ft = format_create(c, NULL, tag, FORMAT_STATUS);
format_defaults(ft, c, NULL, wl, NULL); format_defaults(ft, c, NULL, wl, NULL);
expanded = format_expand_time(ft, fmt, t); expanded = format_expand_time(ft, fmt, t);
@@ -661,9 +661,9 @@ status_prompt_set(struct client *c, const char *msg, const char *input,
{ {
struct format_tree *ft; struct format_tree *ft;
time_t t; time_t t;
char *tmp; char *tmp, *cp;
ft = format_create(NULL, FORMAT_NONE, 0); ft = format_create(c, NULL, FORMAT_NONE, 0);
format_defaults(ft, c, NULL, NULL, NULL); format_defaults(ft, c, NULL, NULL, NULL);
t = time(NULL); t = time(NULL);
@@ -690,6 +690,12 @@ status_prompt_set(struct client *c, const char *msg, const char *input,
c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE); c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE);
c->flags |= CLIENT_STATUS; c->flags |= CLIENT_STATUS;
if ((flags & PROMPT_INCREMENTAL) && *tmp != '\0') {
xasprintf(&cp, "=%s", tmp);
c->prompt_callbackfn(c->prompt_data, cp, 0);
free(cp);
}
free(tmp); free(tmp);
format_free(ft); format_free(ft);
} }
@@ -724,7 +730,7 @@ status_prompt_update(struct client *c, const char *msg, const char *input)
time_t t; time_t t;
char *tmp; char *tmp;
ft = format_create(NULL, FORMAT_NONE, 0); ft = format_create(c, NULL, FORMAT_NONE, 0);
format_defaults(ft, c, NULL, NULL, NULL); format_defaults(ft, c, NULL, NULL, NULL);
t = time(NULL); t = time(NULL);
@@ -1497,6 +1503,7 @@ status_prompt_complete(struct session *session, const char *s)
out = status_prompt_complete_prefix(list, size); out = status_prompt_complete_prefix(list, size);
if (out != NULL) { if (out != NULL) {
xasprintf(&tmp, "-%c%s%s", copy[1], out, colon); xasprintf(&tmp, "-%c%s%s", copy[1], out, colon);
free(out);
out = tmp; out = tmp;
goto found; goto found;
} }

29
tmux.1
View File

@@ -3199,7 +3199,6 @@ will generate
.Xr xterm 1 -style .Xr xterm 1 -style
function key sequences; these have a number included to indicate modifiers such function key sequences; these have a number included to indicate modifiers such
as Shift, Alt or Ctrl. as Shift, Alt or Ctrl.
The default is off.
.El .El
.It Xo Ic show-options .It Xo Ic show-options
.Op Fl gqsvw .Op Fl gqsvw
@@ -3439,7 +3438,7 @@ or
.Ql != .Ql !=
and a colon. and a colon.
For example For example
.Ql #{==,#{host},myhost} .Ql #{==:#{host},myhost}
will be replaced by will be replaced by
.Ql 1 .Ql 1
if running on if running on
@@ -3494,6 +3493,8 @@ does not wait for
.Ql #() .Ql #()
commands to finish; instead, the previous result from running the same command is used, commands to finish; instead, the previous result from running the same command is used,
or a placeholder if the command has not been run before. or a placeholder if the command has not been run before.
If the command hasn't exited, the most recent line of output will be used, but the status
line will not be updated more than once a second.
Commands are executed with the Commands are executed with the
.Nm .Nm
global environment set (see the global environment set (see the
@@ -3512,6 +3513,7 @@ The following variables are available, where appropriate:
.It Li "client_activity" Ta "" Ta "Integer time client last had activity" .It Li "client_activity" Ta "" Ta "Integer time client last had activity"
.It Li "client_created" Ta "" Ta "Integer time client created" .It Li "client_created" Ta "" Ta "Integer time client created"
.It Li "client_control_mode" Ta "" Ta "1 if client is in control mode" .It Li "client_control_mode" Ta "" Ta "1 if client is in control mode"
.It Li "client_discarded" Ta "" Ta "Bytes discarded when client behind"
.It Li "client_height" Ta "" Ta "Height of client" .It Li "client_height" Ta "" Ta "Height of client"
.It Li "client_key_table" Ta "" Ta "Current key table" .It Li "client_key_table" Ta "" Ta "Current key table"
.It Li "client_last_session" Ta "" Ta "Name of the client's last session" .It Li "client_last_session" Ta "" Ta "Name of the client's last session"
@@ -3564,8 +3566,10 @@ The following variables are available, where appropriate:
.It Li "pane_input_off" Ta "" Ta "If input to pane is disabled" .It Li "pane_input_off" Ta "" Ta "If input to pane is disabled"
.It Li "pane_index" Ta "#P" Ta "Index of pane" .It Li "pane_index" Ta "#P" Ta "Index of pane"
.It Li "pane_left" Ta "" Ta "Left of pane" .It Li "pane_left" Ta "" Ta "Left of pane"
.It Li "pane_mode" Ta "" Ta "Name of pane mode, if any."
.It Li "pane_pid" Ta "" Ta "PID of first process in pane" .It Li "pane_pid" Ta "" Ta "PID of first process in pane"
.It Li "pane_right" Ta "" Ta "Right of pane" .It Li "pane_right" Ta "" Ta "Right of pane"
.It Li "pane_search_string" Ta "" Ta "Last search string in copy mode"
.It Li "pane_start_command" Ta "" Ta "Command pane started with" .It Li "pane_start_command" Ta "" Ta "Command pane started with"
.It Li "pane_synchronized" Ta "" Ta "If pane is synchronized" .It Li "pane_synchronized" Ta "" Ta "If pane is synchronized"
.It Li "pane_tabs" Ta "" Ta "Pane tab positions" .It Li "pane_tabs" Ta "" Ta "Pane tab positions"
@@ -3588,6 +3592,7 @@ The following variables are available, where appropriate:
.It Li "session_id" Ta "" Ta "Unique session ID" .It Li "session_id" Ta "" Ta "Unique session ID"
.It Li "session_many_attached" Ta "" Ta "1 if multiple clients attached" .It Li "session_many_attached" Ta "" Ta "1 if multiple clients attached"
.It Li "session_name" Ta "#S" Ta "Name of session" .It Li "session_name" Ta "#S" Ta "Name of session"
.It Li "session_stack" Ta "" Ta "Window indexes in most recent order"
.It Li "session_width" Ta "" Ta "Width of session" .It Li "session_width" Ta "" Ta "Width of session"
.It Li "session_windows" Ta "" Ta "Number of windows in session" .It Li "session_windows" Ta "" Ta "Number of windows in session"
.It Li "socket_path" Ta "" Ta "Server socket path" .It Li "socket_path" Ta "" Ta "Server socket path"
@@ -3608,6 +3613,7 @@ The following variables are available, where appropriate:
.It Li "window_name" Ta "#W" Ta "Name of window" .It Li "window_name" Ta "#W" Ta "Name of window"
.It Li "window_panes" Ta "" Ta "Number of panes in window" .It Li "window_panes" Ta "" Ta "Number of panes in window"
.It Li "window_silence_flag" Ta "" Ta "1 if window has silence alert" .It Li "window_silence_flag" Ta "" Ta "1 if window has silence alert"
.It Li "window_stack_index" Ta "" Ta "Index in session most recent stack"
.It Li "window_visible_layout" Ta "" Ta "Window layout description, respecting zoomed window panes" .It Li "window_visible_layout" Ta "" Ta "Window layout description, respecting zoomed window panes"
.It Li "window_width" Ta "" Ta "Width of window" .It Li "window_width" Ta "" Ta "Width of window"
.It Li "window_zoomed_flag" Ta "" Ta "1 if window is zoomed" .It Li "window_zoomed_flag" Ta "" Ta "1 if window is zoomed"
@@ -4234,6 +4240,11 @@ A notification will never occur inside an output block.
.Pp .Pp
The following notifications are defined: The following notifications are defined:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Ic %client-session-changed Ar client Ar session-id Ar name
The client is now attached to the session with ID
.Ar session-id ,
which is named
.Ar name .
.It Ic %exit Op Ar reason .It Ic %exit Op Ar reason
The The
.Nm .Nm
@@ -4256,6 +4267,10 @@ and the window flags are
A window pane produced output. A window pane produced output.
.Ar value .Ar value
escapes non-printable characters and backslash as octal \\xxx. escapes non-printable characters and backslash as octal \\xxx.
.It Ic %pane-mode-changed Ar pane-id
The pane with ID
.Ar pane-id
has changed mode.
.It Ic %session-changed Ar session-id Ar name .It Ic %session-changed Ar session-id Ar name
The client is now attached to the session with ID The client is now attached to the session with ID
.Ar session-id , .Ar session-id ,
@@ -4264,6 +4279,11 @@ which is named
.It Ic %session-renamed Ar name .It Ic %session-renamed Ar name
The current session was renamed to The current session was renamed to
.Ar name . .Ar name .
.It Ic %session-window-changed Ar session-id Ar window-id
The session with ID
.Ar session-id
changed its active window to the window with ID
.Ar window-id .
.It Ic %sessions-changed .It Ic %sessions-changed
A session was created or destroyed. A session was created or destroyed.
.It Ic %unlinked-window-add Ar window-id .It Ic %unlinked-window-add Ar window-id
@@ -4278,6 +4298,11 @@ was linked to the current session.
The window with ID The window with ID
.Ar window-id .Ar window-id
closed. closed.
.It Ic %window-pane-changed Ar window-id Ar pane-id
The active pane in the window with ID
.Ar window-id
changed to the pane with ID
.Ar pane-id .
.It Ic %window-renamed Ar window-id Ar name .It Ic %window-renamed Ar window-id Ar name
The window with ID The window with ID
.Ar window-id .Ar window-id

7
tmux.c
View File

@@ -22,7 +22,6 @@
#include <errno.h> #include <errno.h>
#include <event.h> #include <event.h>
#include <fcntl.h> #include <fcntl.h>
#include <getopt.h>
#include <langinfo.h> #include <langinfo.h>
#include <locale.h> #include <locale.h>
#include <pwd.h> #include <pwd.h>
@@ -118,7 +117,7 @@ make_label(const char *label)
uid = getuid(); uid = getuid();
if ((s = getenv("TMUX_TMPDIR")) != NULL && *s != '\0') if ((s = getenv("TMUX_TMPDIR")) != NULL && *s != '\0')
xasprintf(&base, "%s/tmux-%u", s, uid); xasprintf(&base, "%s/tmux-%ld", s, (long)uid);
else else
xasprintf(&base, "%s/tmux-%ld", _PATH_TMP, (long)uid); xasprintf(&base, "%s/tmux-%ld", _PATH_TMP, (long)uid);
@@ -261,8 +260,8 @@ main(int argc, char **argv)
if (shellcmd != NULL && argc != 0) if (shellcmd != NULL && argc != 0)
usage(); usage();
if (pty_open(&ptm_fd) != 0) if ((ptm_fd = getptmfd()) == -1)
errx(1, "open(\"/dev/ptm\""); err(1, "getptmfd");
if (pledge("stdio rpath wpath cpath flock fattr unix getpw sendfd " if (pledge("stdio rpath wpath cpath flock fattr unix getpw sendfd "
"recvfd proc exec tty ps", NULL) != 0) "recvfd proc exec tty ps", NULL) != 0)
err(1, "pledge"); err(1, "pledge");

196
tmux.h
View File

@@ -45,6 +45,7 @@ struct client;
struct cmdq_item; struct cmdq_item;
struct cmdq_list; struct cmdq_list;
struct environ; struct environ;
struct format_job_tree;
struct input_ctx; struct input_ctx;
struct mode_key_cmdstr; struct mode_key_cmdstr;
struct mouse_event; struct mouse_event;
@@ -94,9 +95,10 @@ struct tmuxproc;
#define KEYC_ESCAPE 0x200000000000ULL #define KEYC_ESCAPE 0x200000000000ULL
#define KEYC_CTRL 0x400000000000ULL #define KEYC_CTRL 0x400000000000ULL
#define KEYC_SHIFT 0x800000000000ULL #define KEYC_SHIFT 0x800000000000ULL
#define KEYC_XTERM 0x1000000000000ULL
/* Mask to obtain key w/o modifiers. */ /* Mask to obtain key w/o modifiers. */
#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT) #define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_XTERM)
#define KEYC_MASK_KEY (~KEYC_MASK_MOD) #define KEYC_MASK_KEY (~KEYC_MASK_MOD)
/* Is this a mouse key? */ /* Is this a mouse key? */
@@ -592,6 +594,10 @@ struct hook {
}; };
/* Scheduled job. */ /* Scheduled job. */
struct job;
typedef void (*job_update_cb) (struct job *);
typedef void (*job_complete_cb) (struct job *);
typedef void (*job_free_cb) (void *);
struct job { struct job {
enum { enum {
JOB_RUNNING, JOB_RUNNING,
@@ -599,18 +605,19 @@ struct job {
JOB_CLOSED JOB_CLOSED
} state; } state;
char *cmd; char *cmd;
pid_t pid; pid_t pid;
int status; int status;
int fd; int fd;
struct bufferevent *event; struct bufferevent *event;
void (*callbackfn)(struct job *); job_update_cb updatecb;
void (*freefn)(void *); job_complete_cb completecb;
void *data; job_free_cb freecb;
void *data;
LIST_ENTRY(job) lentry; LIST_ENTRY(job) entry;
}; };
LIST_HEAD(joblist, job); LIST_HEAD(joblist, job);
@@ -686,15 +693,18 @@ struct screen_write_ctx {
* right function to handle input and output. * right function to handle input and output.
*/ */
struct window_mode { struct window_mode {
struct screen *(*init)(struct window_pane *); const char *name;
void (*free)(struct window_pane *);
void (*resize)(struct window_pane *, u_int, u_int);
void (*key)(struct window_pane *, struct client *, struct session *,
key_code, struct mouse_event *);
const char *(*key_table)(struct window_pane *); struct screen *(*init)(struct window_pane *);
void (*command)(struct window_pane *, struct client *, void (*free)(struct window_pane *);
struct session *, struct args *, struct mouse_event *); void (*resize)(struct window_pane *, u_int, u_int);
void (*key)(struct window_pane *, struct client *,
struct session *, key_code, struct mouse_event *);
const char *(*key_table)(struct window_pane *);
void (*command)(struct window_pane *, struct client *,
struct session *, struct args *,
struct mouse_event *);
}; };
#define WINDOW_MODE_TIMEOUT 180 #define WINDOW_MODE_TIMEOUT 180
@@ -1047,7 +1057,8 @@ struct tty {
struct evbuffer *in; struct evbuffer *in;
struct event event_out; struct event event_out;
struct evbuffer *out; struct evbuffer *out;
size_t written; struct event timer;
size_t discarded;
struct termios tio; struct termios tio;
@@ -1063,6 +1074,7 @@ struct tty {
#define TTY_STARTED 0x10 #define TTY_STARTED 0x10
#define TTY_OPENED 0x20 #define TTY_OPENED 0x20
#define TTY_FOCUS 0x40 #define TTY_FOCUS 0x40
#define TTY_BLOCK 0x80
int flags; int flags;
struct tty_term *term; struct tty_term *term;
@@ -1089,13 +1101,14 @@ struct tty {
struct tty_key *key_tree; struct tty_key *key_tree;
}; };
#define TTY_TYPES \ #define TTY_TYPES \
{ "VT100", "VT101", "VT102", "VT220", "VT320", "VT420", "UNKNOWN" } { "VT100", "VT101", "VT102", "VT220", "VT320", "VT420", "Unknown" }
/* TTY command context. */ /* TTY command context. */
struct tty_ctx { struct tty_ctx {
struct window_pane *wp; struct window_pane *wp;
const struct grid_cell *cell; const struct grid_cell *cell;
int wrapped;
u_int num; u_int num;
void *ptr; void *ptr;
@@ -1142,7 +1155,6 @@ enum cmd_find_type {
CMD_FIND_SESSION, CMD_FIND_SESSION,
}; };
struct cmd_find_state { struct cmd_find_state {
struct cmdq_item *item;
int flags; int flags;
struct cmd_find_state *current; struct cmd_find_state *current;
@@ -1160,13 +1172,7 @@ struct cmd_find_state {
#define CMD_FIND_DEFAULT_MARKED 0x8 #define CMD_FIND_DEFAULT_MARKED 0x8
#define CMD_FIND_EXACT_SESSION 0x10 #define CMD_FIND_EXACT_SESSION 0x10
#define CMD_FIND_EXACT_WINDOW 0x20 #define CMD_FIND_EXACT_WINDOW 0x20
#define CMD_FIND_CANFAIL 0x40
/* Context for command being executed. */
struct cmd_state {
struct client *c;
struct cmd_find_state tflag;
struct cmd_find_state sflag;
};
/* Command and list of commands. */ /* Command and list of commands. */
struct cmd { struct cmd {
@@ -1201,6 +1207,19 @@ enum cmdq_type {
CMDQ_CALLBACK, CMDQ_CALLBACK,
}; };
/* Command queue item shared state. */
struct cmdq_shared {
int references;
int flags;
#define CMDQ_SHARED_REPEAT 0x1
struct format_tree *formats;
struct mouse_event mouse;
struct cmd_find_state current;
};
/* Command queue item. */ /* Command queue item. */
typedef enum cmd_retval (*cmdq_cb) (struct cmdq_item *, void *); typedef enum cmd_retval (*cmdq_cb) (struct cmdq_item *, void *);
struct cmdq_item { struct cmdq_item {
@@ -1216,51 +1235,30 @@ struct cmdq_item {
u_int number; u_int number;
time_t time; time_t time;
struct format_tree *formats;
int flags; int flags;
#define CMDQ_FIRED 0x1 #define CMDQ_FIRED 0x1
#define CMDQ_WAITING 0x2 #define CMDQ_WAITING 0x2
#define CMDQ_NOHOOKS 0x4 #define CMDQ_NOHOOKS 0x4
struct cmdq_shared *shared;
struct cmd_find_state source;
struct cmd_find_state target;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd *cmd; struct cmd *cmd;
int repeat;
cmdq_cb cb; cmdq_cb cb;
void *data; void *data;
struct cmd_find_state current;
struct cmd_state state;
struct mouse_event mouse;
TAILQ_ENTRY(cmdq_item) entry; TAILQ_ENTRY(cmdq_item) entry;
}; };
TAILQ_HEAD(cmdq_list, cmdq_item); TAILQ_HEAD(cmdq_list, cmdq_item);
/* Command -c, -t or -s flags. */ /* Command definition flag. */
enum cmd_entry_flag { struct cmd_entry_flag {
CMD_NONE, char flag;
enum cmd_find_type type;
CMD_CLIENT, int flags;
CMD_CLIENT_CANFAIL,
CMD_SESSION,
CMD_SESSION_CANFAIL,
CMD_SESSION_PREFERUNATTACHED,
CMD_SESSION_WITHPANE, /* implies PREFERUNATTACHED */
CMD_WINDOW,
CMD_WINDOW_CANFAIL,
CMD_WINDOW_MARKED,
CMD_WINDOW_INDEX,
CMD_PANE,
CMD_PANE_CANFAIL,
CMD_PANE_MARKED,
CMD_MOVEW_R,
}; };
/* Command definition. */ /* Command definition. */
@@ -1275,16 +1273,15 @@ struct cmd_entry {
} args; } args;
const char *usage; const char *usage;
enum cmd_entry_flag tflag; struct cmd_entry_flag source;
enum cmd_entry_flag sflag; struct cmd_entry_flag target;
enum cmd_entry_flag cflag;
#define CMD_STARTSERVER 0x1 #define CMD_STARTSERVER 0x1
#define CMD_READONLY 0x2 #define CMD_READONLY 0x2
#define CMD_AFTERHOOK 0x4 #define CMD_AFTERHOOK 0x4
int flags; int flags;
enum cmd_retval (*exec)(struct cmd *, struct cmdq_item *); enum cmd_retval (*exec)(struct cmd *, struct cmdq_item *);
}; };
/* Client connection. */ /* Client connection. */
@@ -1302,6 +1299,7 @@ struct client {
struct timeval activity_time; struct timeval activity_time;
struct environ *environ; struct environ *environ;
struct format_job_tree *jobs;
char *title; char *title;
const char *cwd; const char *cwd;
@@ -1310,6 +1308,10 @@ struct client {
char *ttyname; char *ttyname;
struct tty tty; struct tty tty;
size_t written;
size_t discarded;
size_t redraw;
void (*stdin_callback)(struct client *, int, void *); void (*stdin_callback)(struct client *, int, void *);
void *stdin_callback_data; void *stdin_callback_data;
struct evbuffer *stdin_data; struct evbuffer *stdin_data;
@@ -1337,7 +1339,7 @@ struct client {
#define CLIENT_DEAD 0x200 #define CLIENT_DEAD 0x200
#define CLIENT_BORDERS 0x400 #define CLIENT_BORDERS 0x400
#define CLIENT_READONLY 0x800 #define CLIENT_READONLY 0x800
/* 0x1000 unused */ #define CLIENT_DETACHING 0x1000
#define CLIENT_CONTROL 0x2000 #define CLIENT_CONTROL 0x2000
#define CLIENT_CONTROLCONTROL 0x4000 #define CLIENT_CONTROLCONTROL 0x4000
#define CLIENT_FOCUSED 0x8000 #define CLIENT_FOCUSED 0x8000
@@ -1388,7 +1390,9 @@ TAILQ_HEAD(clients, client);
struct key_binding { struct key_binding {
key_code key; key_code key;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
int can_repeat;
int flags;
#define KEY_BINDING_REPEAT 0x1
RB_ENTRY(key_binding) entry; RB_ENTRY(key_binding) entry;
}; };
@@ -1478,7 +1482,6 @@ void proc_kill_peer(struct tmuxpeer *);
/* cfg.c */ /* cfg.c */
extern int cfg_finished; extern int cfg_finished;
extern struct client *cfg_client;
void start_cfg(void); void start_cfg(void);
int load_cfg(const char *, struct client *, struct cmdq_item *, int); int load_cfg(const char *, struct client *, struct cmdq_item *, int);
void set_cfg_file(const char *); void set_cfg_file(const char *);
@@ -1509,7 +1512,8 @@ char *paste_make_sample(struct paste_buffer *);
#define FORMAT_PANE 0x80000000U #define FORMAT_PANE 0x80000000U
#define FORMAT_WINDOW 0x40000000U #define FORMAT_WINDOW 0x40000000U
struct format_tree; struct format_tree;
struct format_tree *format_create(struct cmdq_item *, int, int); struct format_tree *format_create(struct client *, struct cmdq_item *, int,
int);
void format_free(struct format_tree *); void format_free(struct format_tree *);
void printflike(3, 4) format_add(struct format_tree *, const char *, void printflike(3, 4) format_add(struct format_tree *, const char *,
const char *, ...); const char *, ...);
@@ -1525,6 +1529,7 @@ void format_defaults_pane(struct format_tree *,
struct window_pane *); struct window_pane *);
void format_defaults_paste_buffer(struct format_tree *, void format_defaults_paste_buffer(struct format_tree *,
struct paste_buffer *); struct paste_buffer *);
void format_lost_client(struct client *);
/* hooks.c */ /* hooks.c */
struct hook; struct hook;
@@ -1546,7 +1551,7 @@ void printflike(4, 5) hooks_insert(struct hooks *, struct cmdq_item *,
void notify_input(struct window_pane *, struct evbuffer *); void notify_input(struct window_pane *, struct evbuffer *);
void notify_client(const char *, struct client *); void notify_client(const char *, struct client *);
void notify_session(const char *, struct session *); void notify_session(const char *, struct session *);
void notify_winlink(const char *, struct session *, struct winlink *); void notify_winlink(const char *, struct winlink *);
void notify_session_window(const char *, struct session *, struct window *); void notify_session_window(const char *, struct session *, struct window *);
void notify_window(const char *, struct window *); void notify_window(const char *, struct window *);
void notify_pane(const char *, struct window_pane *); void notify_pane(const char *, struct window_pane *);
@@ -1600,10 +1605,10 @@ extern const struct options_table_entry options_table[];
/* job.c */ /* job.c */
extern struct joblist all_jobs; extern struct joblist all_jobs;
struct job *job_run(const char *, struct session *, const char *, struct job *job_run(const char *, struct session *, const char *,
void (*)(struct job *), void (*)(void *), void *); job_update_cb, job_complete_cb, job_free_cb, void *);
void job_free(struct job *); void job_free(struct job *);
void job_died(struct job *, int); void job_died(struct job *, int);
/* environ.c */ /* environ.c */
struct environ *environ_create(void); struct environ *environ_create(void);
@@ -1620,7 +1625,7 @@ void environ_unset(struct environ *, const char *);
void environ_update(struct options *, struct environ *, struct environ *); void environ_update(struct options *, struct environ *, struct environ *);
void environ_push(struct environ *); void environ_push(struct environ *);
void environ_log(struct environ *, const char *); void environ_log(struct environ *, const char *);
struct environ *environ_for_session(struct session *); struct environ *environ_for_session(struct session *, int);
/* tty.c */ /* tty.c */
void tty_create_log(void); void tty_create_log(void);
@@ -1714,28 +1719,30 @@ long long args_strtonum(struct args *, u_char, long long, long long,
char **); char **);
/* cmd-find.c */ /* cmd-find.c */
int cmd_find_current(struct cmd_find_state *, struct cmdq_item *, int cmd_find_target(struct cmd_find_state *, struct cmdq_item *,
int); const char *, enum cmd_find_type, int);
int cmd_find_target(struct cmd_find_state *,
struct cmd_find_state *, struct cmdq_item *, const char *,
enum cmd_find_type, int);
struct client *cmd_find_client(struct cmdq_item *, const char *, int); struct client *cmd_find_client(struct cmdq_item *, const char *, int);
void cmd_find_clear_state(struct cmd_find_state *, void cmd_find_clear_state(struct cmd_find_state *, int);
struct cmdq_item *, int);
int cmd_find_empty_state(struct cmd_find_state *); int cmd_find_empty_state(struct cmd_find_state *);
int cmd_find_valid_state(struct cmd_find_state *); int cmd_find_valid_state(struct cmd_find_state *);
void cmd_find_copy_state(struct cmd_find_state *, void cmd_find_copy_state(struct cmd_find_state *,
struct cmd_find_state *); struct cmd_find_state *);
void cmd_find_log_state(const char *, struct cmd_find_state *); void cmd_find_log_state(const char *, struct cmd_find_state *);
int cmd_find_from_session(struct cmd_find_state *, void cmd_find_from_session(struct cmd_find_state *,
struct session *); struct session *);
int cmd_find_from_winlink(struct cmd_find_state *, void cmd_find_from_winlink(struct cmd_find_state *,
struct session *, struct winlink *); struct winlink *);
int cmd_find_from_session_window(struct cmd_find_state *, int cmd_find_from_session_window(struct cmd_find_state *,
struct session *, struct window *); struct session *, struct window *);
int cmd_find_from_window(struct cmd_find_state *, struct window *); int cmd_find_from_window(struct cmd_find_state *, struct window *);
void cmd_find_from_winlink_pane(struct cmd_find_state *,
struct winlink *, struct window_pane *);
int cmd_find_from_pane(struct cmd_find_state *, int cmd_find_from_pane(struct cmd_find_state *,
struct window_pane *); struct window_pane *);
int cmd_find_from_client(struct cmd_find_state *, struct client *);
int cmd_find_from_mouse(struct cmd_find_state *,
struct mouse_event *);
int cmd_find_from_nothing(struct cmd_find_state *);
/* cmd.c */ /* cmd.c */
int cmd_pack_argv(int, char **, char *, size_t); int cmd_pack_argv(int, char **, char *, size_t);
@@ -1744,7 +1751,6 @@ char **cmd_copy_argv(int, char **);
void cmd_free_argv(int, char **); void cmd_free_argv(int, char **);
char *cmd_stringify_argv(int, char **); char *cmd_stringify_argv(int, char **);
struct cmd *cmd_parse(int, char **, const char *, u_int, char **); struct cmd *cmd_parse(int, char **, const char *, u_int, char **);
int cmd_prepare_state(struct cmd *, struct cmdq_item *);
char *cmd_print(struct cmd *); char *cmd_print(struct cmd *);
int cmd_mouse_at(struct window_pane *, struct mouse_event *, int cmd_mouse_at(struct window_pane *, struct mouse_event *,
u_int *, u_int *, int); u_int *, u_int *, int);
@@ -1755,8 +1761,8 @@ char *cmd_template_replace(const char *, const char *, int);
extern const struct cmd_entry *cmd_table[]; extern const struct cmd_entry *cmd_table[];
/* cmd-attach-session.c */ /* cmd-attach-session.c */
enum cmd_retval cmd_attach_session(struct cmdq_item *, int, int, const char *, enum cmd_retval cmd_attach_session(struct cmdq_item *, const char *, int, int,
int); const char *, int);
/* cmd-list.c */ /* cmd-list.c */
struct cmd_list *cmd_list_parse(int, char **, const char *, u_int, char **); struct cmd_list *cmd_list_parse(int, char **, const char *, u_int, char **);
@@ -1830,13 +1836,13 @@ void server_client_set_identify(struct client *);
void server_client_clear_identify(struct client *, struct window_pane *); void server_client_clear_identify(struct client *, struct window_pane *);
void server_client_set_key_table(struct client *, const char *); void server_client_set_key_table(struct client *, const char *);
const char *server_client_get_key_table(struct client *); const char *server_client_get_key_table(struct client *);
int server_client_is_default_key_table(struct client *);
int server_client_check_nested(struct client *); int server_client_check_nested(struct client *);
void server_client_handle_key(struct client *, key_code); void server_client_handle_key(struct client *, key_code);
void server_client_create(int); void server_client_create(int);
int server_client_open(struct client *, char **); int server_client_open(struct client *, char **);
void server_client_unref(struct client *); void server_client_unref(struct client *);
void server_client_lost(struct client *); void server_client_lost(struct client *);
void server_client_suspend(struct client *);
void server_client_detach(struct client *, enum msgtype); void server_client_detach(struct client *, enum msgtype);
void server_client_exec(struct client *, const char *); void server_client_exec(struct client *, const char *);
void server_client_loop(void); void server_client_loop(void);
@@ -1993,7 +1999,7 @@ void screen_write_cursorleft(struct screen_write_ctx *, u_int);
void screen_write_alignmenttest(struct screen_write_ctx *); void screen_write_alignmenttest(struct screen_write_ctx *);
void screen_write_insertcharacter(struct screen_write_ctx *, u_int, u_int); void screen_write_insertcharacter(struct screen_write_ctx *, u_int, u_int);
void screen_write_deletecharacter(struct screen_write_ctx *, u_int, u_int); void screen_write_deletecharacter(struct screen_write_ctx *, u_int, u_int);
void screen_write_clearcharacter(struct screen_write_ctx *, u_int); void screen_write_clearcharacter(struct screen_write_ctx *, u_int, u_int);
void screen_write_insertline(struct screen_write_ctx *, u_int, u_int); void screen_write_insertline(struct screen_write_ctx *, u_int, u_int);
void screen_write_deleteline(struct screen_write_ctx *, u_int, u_int); void screen_write_deleteline(struct screen_write_ctx *, u_int, u_int);
void screen_write_clearline(struct screen_write_ctx *, u_int); void screen_write_clearline(struct screen_write_ctx *, u_int);
@@ -2113,13 +2119,14 @@ int window_pane_outside(struct window_pane *);
int window_pane_visible(struct window_pane *); int window_pane_visible(struct window_pane *);
char *window_pane_search(struct window_pane *, const char *, char *window_pane_search(struct window_pane *, const char *,
u_int *); u_int *);
char *window_printable_flags(struct session *, struct winlink *); const char *window_printable_flags(struct winlink *);
struct window_pane *window_pane_find_up(struct window_pane *); 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_down(struct window_pane *);
struct window_pane *window_pane_find_left(struct window_pane *); struct window_pane *window_pane_find_left(struct window_pane *);
struct window_pane *window_pane_find_right(struct window_pane *); struct window_pane *window_pane_find_right(struct window_pane *);
void window_set_name(struct window *, const char *); void window_set_name(struct window *, const char *);
void window_remove_ref(struct window *); void window_add_ref(struct window *, const char *);
void window_remove_ref(struct window *, const char *);
void winlink_clear_flags(struct winlink *); void winlink_clear_flags(struct winlink *);
int winlink_shuffle_up(struct session *, struct winlink *); int winlink_shuffle_up(struct session *, struct winlink *);
@@ -2173,6 +2180,7 @@ void window_copy_vadd(struct window_pane *, const char *, va_list);
void window_copy_pageup(struct window_pane *, int); void window_copy_pageup(struct window_pane *, int);
void window_copy_start_drag(struct client *, struct mouse_event *); void window_copy_start_drag(struct client *, struct mouse_event *);
int window_copy_scroll_position(struct window_pane *); int window_copy_scroll_position(struct window_pane *);
const char *window_copy_search_string(struct window_pane *);
/* window-choose.c */ /* window-choose.c */
extern const struct window_mode window_choose_mode; extern const struct window_mode window_choose_mode;
@@ -2209,7 +2217,9 @@ void control_write_buffer(struct client *, struct evbuffer *);
/* control-notify.c */ /* control-notify.c */
void control_notify_input(struct client *, struct window_pane *, void control_notify_input(struct client *, struct window_pane *,
struct evbuffer *); struct evbuffer *);
void control_notify_pane_mode_changed(int);
void control_notify_window_layout_changed(struct window *); void control_notify_window_layout_changed(struct window *);
void control_notify_window_pane_changed(struct window *);
void control_notify_window_unlinked(struct session *, struct window *); void control_notify_window_unlinked(struct session *, struct window *);
void control_notify_window_linked(struct session *, struct window *); void control_notify_window_linked(struct session *, struct window *);
void control_notify_window_renamed(struct window *); void control_notify_window_renamed(struct window *);
@@ -2217,6 +2227,7 @@ void control_notify_client_session_changed(struct client *);
void control_notify_session_renamed(struct session *); void control_notify_session_renamed(struct session *);
void control_notify_session_created(struct session *); void control_notify_session_created(struct session *);
void control_notify_session_closed(struct session *); void control_notify_session_closed(struct session *);
void control_notify_session_window_changed(struct session *);
/* session.c */ /* session.c */
extern struct sessions sessions; extern struct sessions sessions;
@@ -2233,7 +2244,8 @@ struct session *session_create(const char *, const char *, int, char **,
const char *, const char *, struct environ *, const char *, const char *, struct environ *,
struct termios *, int, u_int, u_int, char **); struct termios *, int, u_int, u_int, char **);
void session_destroy(struct session *); void session_destroy(struct session *);
void session_unref(struct session *); void session_add_ref(struct session *, const char *);
void session_remove_ref(struct session *, const char *);
int session_check_name(const char *); int session_check_name(const char *);
void session_update_activity(struct session *, struct timeval *); void session_update_activity(struct session *, struct timeval *);
struct session *session_next_session(struct session *); struct session *session_next_session(struct session *);
@@ -2302,8 +2314,4 @@ void style_apply_update(struct grid_cell *, struct options *,
int style_equal(const struct grid_cell *, int style_equal(const struct grid_cell *,
const struct grid_cell *); const struct grid_cell *);
/* pty.c */
int pty_open(int *);
pid_t pty_fork(int, int *, char *, size_t, struct winsize *);
#endif /* TMUX_H */ #endif /* TMUX_H */

Some files were not shown because too many files have changed in this diff Show More