1 Commits
2.0 ... 1.5

Author SHA1 Message Date
Tiago Cunha
509c63b618 Tag 1.5 release. 2011-07-09 16:10:35 +00:00
187 changed files with 9253 additions and 18108 deletions

19
.gitignore vendored
View File

@@ -1,19 +0,0 @@
*.o
*~
*.diff
*.patch
*.core
core
tags
.deps/
compat/.dirstamp
aclocal.m4
autom4te.cache/
config.log
config.status
etc/
tmux
Makefile
Makefile.in
configure
tmux.1.*

View File

@@ -1,24 +0,0 @@
Bob Beck <beck@openbsd.org> beck <beck>
Igor Sobrado <sobrado@openbsd.org> sobrado <sobrado>
Jacek Masiulaniec <jacekm@openbsd.org> jacekm <jacekm>
Jason McIntyre <jmc@openbsd.org> jcm <jcm>
Joel Sing <jsing@openbsd.org> jsing <jsing>
Marc Espie <espie@openbsd.org> espie <espie>
Matthew Dempsky <matthew@openbsd.org> matthew <matthew>
Matthias Kilian <kili@openbsd.org> kili <kili>
Matthieu Herrb <matthieu@openbsd.org> matthieu <matthieu>
Miod Vallat <miod@openbsd.org> miod <miod>
Nicholas Marriott <nicm@openbsd.org> nicm <nicm>
Nicholas Marriott <nicm@openbsd.org> no_author <no_author@example.org>
<nicm@openbsd.org> <nicholas.marriott@gmail.com>
Okan Demirmen <okan@openbsd.org> okan <okan>
Philip Guenther <guenther@openbsd.org> guenther <guenther>
Pierre-Yves Ritschard <pyr@openbsd.org> pyr <pyr>
Ray Lai <ray@openbsd.org> ray <ray>
Ryan McBride <mcbride@openbsd.org> mcbride <mcbride>
Stefan Sperling <stsp@openbsd.org> stsp <stsp>
Stuart Henderson <sthen@openbsd.org> sthen <sthen>
Ted Unangst <tedu@openbsd.org> tedu <tedu>
Theo Deraadt <deraadt@openbsd.org> deraadt <deraadt>
Thomas Adam <thomas@xteddy.org> Thomas <thomas@xteddy.org>
William Yodlowsky <william@openbsd.org> william <william>

232
CHANGES
View File

@@ -1,230 +1,3 @@
CHANGES FROM 1.9 to 1.9a 22 February 2014
NOTE: This is a bug-fix release to address some important bugs which just
missed the 1.9 deadline, but were found afterwards.
Normal Changes
==============
* Fix crash due to uninitialized lastwp member of layout_cell
* Fix -fg/-bg/-style with 256 colour terminals.
CHANGES FROM 1.8 to 1.9, 20 February 2014
NOTE: This release has bumped the tmux protocol version. It is therefore
advised that the prior tmux server is restarted when this version of tmux is
installed, to avoid protocol mismatch errors for newer clients trying to
talk to an older running tmux server.
Incompatible Changes
====================
* 88 colour support has been removed.
* 'default-path' has been removed. The new-window command accepts '-c' to
cater for this. The previous value of "." can be replaced with: 'neww -c
$PWD', the previous value of '' which meant current path of the pane can
be specified as: 'neww -c "#{pane_current_path}"'
Deprecated Changes
==================
* The single format specifiers: #A -> #Z (where defined) have been
deprecated and replaced with longer-named equivalents, as listed in the
FORMATS section of the tmux manpage.
* The various foo-{fg,bg,attr} commands have been deprecated and replaced
with equivalent foo-style option instead. Currently this is still
backwards-compatible, but will be removed over time.
Normal Changes
==============
* A new environment variable TMUX_TMPDIR is now honoured, allowing the
socket directory to be set outside of TMPDIR (/tmp/ if not set).
* If -s not given to swap-pane the current pane is assumed.
* A #{pane_syncronized} format specifier has been added to be a conditional
format if a pane is in a syncronised mode (c.f. syncronize-panes)
* Tmux now runs under Cygwin natively.
* Formats can now be nested within each other and expanded accordingly.
* Added 'automatic-rename-format' option to allow the automatic rename
mechanism to use something other than the default of
#{pane_current_command}.
* new-session learnt '-c' to specify the starting directory for that session
and all subsequent windows therein.
* The session name is now shown in the message printed to the terminal when
a session is detached.
* Lots more format specifiers have been added.
* Server race conditions have been fixed; in particular commands are not run
until after the configuration file is read completely.
* Case insensitive searching in tmux's copy-mode is now possible.
* attach-session and switch-client learnt the '-t' option to accept a window
and/or a pane to use.
* Copy-mode is only exited if no selection is in progress.
* Paste key in copy-mode is now possible to enter text from the clipboard.
* status-interval set to '0' now works as intended.
* tmux now supports 256 colours running under fbterm.
* Many bug fixes!
CHANGES FROM 1.7 to 1.8, 26 March 2013
Incompatible Changes
====================
* layout redo/undo has been removed.
Normal Changes
==============
* Add halfpage up/down bindings to copy mode.
* Session choosing fixed to work with unattached sessions.
* New window options window-status-last-{attr,bg,fg} to denote the last
window which was active.
* Scrolling in copy-mode now scrolls the region without moving the mouse
cursor.
* run-shell learnt '-t' to specify the pane to use when displaying output.
* Support for middle-click pasting.
* choose-tree learns '-u' to start uncollapsed.
* select-window learnt '-T' to toggle to the last window if it's already
current.
* New session option 'assume-paste-time' for pasting text versus key-binding
actions.
* choose-* commands now work outside of an attached client.
* Aliases are now shown for list-commands command.
* Status learns about formats.
* Free-form options can be set with set-option if prepended with an '@'
sign.
* capture-pane learnt '-p' to send to stdout, and '-e' for capturing escape
sequences, and '-a' to capture the alternate screen, and '-P' to dump
pending output.
* Many new formats added (client_session, client_last_session, etc.)
* Control mode, which is a way for a client to send tmux commands.
Currently more useful to users of iterm2.
* resize-pane learnt '-x' and '-y' for absolute pane sizing.
* Config file loading now reports errors from all files which are loaded via
the 'source-file' command.
* 'copy-pipe' mode command to copy selection and pipe the selection to a
command.
* Panes can now emit focus notifications for certain applications
which use those.
* run-shell and if-shell now accept formats.
* resize-pane learnt '-Z' for zooming a pane temporarily.
* new-session learnt '-A' to make it behave like attach-session.
* set-option learnt '-o' to prevent setting an option which is already set.
* capture-pane and show-options learns '-q' to silence errors.
* New command 'wait-for' which blocks a client until woken up again.
* Resizing panes will now reflow the text inside them.
* Lots and lots of bug fixes, fixing memory-leaks, etc.
* Various manpage improvements.
CHANGES FROM 1.6 to 1.7, 13 October 2012
* tmux configuration files now support line-continuation with a "\" at the
end of a line.
* New option status-position to move the status line to the top or bottom of
the screen.
* Enforce history-limit option when clearing the screen.
* Give each window a unique id, like panes but prefixed with @.
* Add pane id to each pane in layout description (while still accepting
the old form).
* Provide defined ways to set the various default-path possibilities: ~
for home directory, . for server start directory, - for session start
directory and empty for the pane's working directory (the default). All
can also be used as part of a relative path (eg -/foo). Also provide -c
flags to neww and splitw to override default-path setting.
* Add -l flag to send-keys to send input literally (without translating
key names).
* Allow a single option to be specified to show-options to show just that
option.
* New command "move-pane" (like join-pane but allows the same window).
* join-pane and move-pane commands learn "-b" option to place the pane to
the left or above.
* Support for bracketed-paste mode.
* Allow send-keys command to accept hex values.
* Add locking around "start-server" to avoid race-conditions.
* break-pane learns -P/-F arguments for display formatting.
* set-option learns "-q" to make it quiet, and not print out anything.
* copy mode learns "wrap-search" option.
* Add a simple form of output rate limiting by counting the number of
certain C0 sequences (linefeeds, backspaces, carriage returns) and if it
exceeds a threshold (current default 250/millisecond), start to redraw
the pane every 100 milliseconds instead of making each change as it
comes. Two configuration options - c0-change-trigger and
c0-change-interval.
* find-window learns new flags: "-C", "-N", "-T" to match against either or
all of a window's content, name, or title. Defaults to all three options
if none specified.
* find-window automatically selects the appropriate pane for the found
matches.
* show-environment can now accept one option to show that environment value.
* Exit mouse mode when end-of-screen reached when scrolling with the mouse
wheel.
* select-layout learns -u and -U for layout history stacks.
* kill-window, detach-client, kill-session all learn "-a" option for
killing all but the current thing specified.
* move-window learns "-r" option to renumber window sequentially in a
session.
* New session option "renumber-windows" to automatically renumber windows in
a session when a window is closed. (see "move-window -r").
* Only enter copy-mode on scroll up.
* choose-* and list-* commands all use "-F" for format specifiers.
* When spawning external commands, the value from the "default-shell" option
is now used, rather than assuming /bin/sh.
* New choose-tree command to render window/sessions as a tree for selection.
* display-message learns new format options.
* For linked-windows across sessions, all flags for that window are now
cleared across sessions.
* Lots and lots of bug fixes, fixing memory-leaks, etc.
* Various manpage improvements.
CHANGES FROM 1.5 TO 1.6, 23 January 2012
* Extend the mode-mouse option to add a third choice which means the mouse
does not enter copy mode.
* Add a -r flag to switch-client to toggle the client read-only flag.
* Add pane-base-index option.
* Support \ for line continuation in the configuration file.
* Framework for more powerful formatting of command output and use it for
list-{panes,windows,sessions}. This allows more descriptive replacements
(such as #{session_name}) and conditionals.
* Mark dead panes with some text saying they are dead.
* Reject $SHELL if it is not a full path.
* Add -S option to refresh-client to redraw status line.
* Add an else clause for if-shell.
* Try to resolve relative paths for loadb and saveb (first, using client
working directory, if any, then default-path or session working directory).
* Support for \e[3J to clear the history and send the corresponding
terminfo code (E3) before locking.
* When in copy mode, make repeat count indicate buffer to replace, if used.
* Add screen*:XT to terminal-overrides for tmux-in-tmux.
* Status-line message attributes added.
* Move word-separators to be a session rather than window option.
* Change the way the working directory for new processes is discovered. If
default-path isn't empty, it is used. Otherwise, if a new window is created
from the command-line, the working directory of the client is used. If not,
platform specific code is used to retrieve the current working directory
of the process in the active pane. If that fails, the directory where the
session was created is used, instead.
* Do not change the current pane if both mouse-select-{pane,window} are
enabled.
* Add \033[s and \033[u to save and restore cursor position.
* Allow $HOME to be used as default-path.
* Add CNL and CPL escape sequences.
* Calculate last position correctly for UTF-8 wide characters.
* Add an option allow-rename to disable the window rename escape sequence.
* Attributes for each type of status-line alert (ie bell, content and
activity) added. Therefore, remove the superfluous options
window-status-alert-{attr,bg,fg}.
* Add a -R flag to send-keys to reset the terminal.
* Add strings to allow the aixterm bright colours to be used when
configuring colours.
* Drop the ability to have a list of keys in the prefix in favour of two
separate options, prefix and prefix2.
* Flag -2 added to send-prefix to send the secondary prefix key.
* Show pane size in top right of display panes mode.
* Some memory leaks plugged.
* More command-prompt editing improvements.
* Various manpage improvements.
* More Vi mode improvements.
CHANGES FROM 1.4 TO 1.5, 09 July 2011 CHANGES FROM 1.4 TO 1.5, 09 July 2011
* Support xterm mouse modes 1002 and 1003. * Support xterm mouse modes 1002 and 1003.
@@ -1867,3 +1640,8 @@ The list of older changes is below.
customisation. customisation.
$Id$ $Id$
LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr
LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms
LocalWords: dstidx srcname srcidx winlink lsw nabc sabc Exp Tiago Cunha dch
LocalWords: setw Chisnall renamew merdely eg Maier newname selectw neww Gass

21
COPYING
View File

@@ -1,21 +0,0 @@
THIS IS FOR INFORMATION ONLY, CODE IS UNDER THE LICENCE AT THE TOP OF ITS FILE.
The README, CHANGES, FAQ and TODO files are licensed under the ISC
license. Files under examples/ remain copyright their authors unless otherwise
stated in the file but permission has been received to distribute them with
tmux. All other files have a license and copyright notice at their start,
typically:
Copyright (c) <author>
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.

148
FAQ
View File

@@ -95,6 +95,9 @@ aware of are (bearing in mind I haven't used screen for a few years now):
- screen has builtin serial and telnet support; this is bloat and is unlikely - screen has builtin serial and telnet support; this is bloat and is unlikely
to be added to tmux. to be added to tmux.
- screen has support for updating utmp. Nobody has really come up with a clean,
portable way to do this without making tmux setuid or setgid yet.
- Environment handling is different. - Environment handling is different.
- tmux tends to be more demanding on the terminal so tends to show up terminal - tmux tends to be more demanding on the terminal so tends to show up terminal
@@ -104,10 +107,6 @@ aware of are (bearing in mind I haven't used screen for a few years now):
* I found a bug! What do I do? * I found a bug! What do I do?
Check the latest version of tmux from Git to see if the problem is still
reproducible. Sometimes the length of time between releases means a lot of
fixes can be sitting in Git and the problem might already be fixed.
Please send bug reports by email to nicm@users.sourceforge.net or Please send bug reports by email to nicm@users.sourceforge.net or
tmux-users@lists.sourceforge.net. Please include as much of the following tmux-users@lists.sourceforge.net. Please include as much of the following
information as possible: information as possible:
@@ -239,31 +238,6 @@ would be welcome.
vim users may also want to set the "ttyfast" option inside tmux. vim users may also want to set the "ttyfast" option inside tmux.
* How do I make ctrl and shift arrow keys work in emacs?
The terminal-init-screen function in term/screen.el is called for new frames,
but it doesn't configure any function keys.
If the tmux xterm-keys option is on, it is enough to define the same keys as
xterm. Add the following to init.el or .emacs to do this:
(defadvice terminal-init-screen
;; The advice is named `tmux', and is run before `terminal-init-screen' runs.
(before tmux activate)
;; Docstring. This describes the advice and is made available inside emacs;
;; for example when doing C-h f terminal-init-screen RET
"Apply xterm keymap, allowing use of keys passed through tmux."
;; This is the elisp code that is run before `terminal-init-screen'.
(if (getenv "TMUX")
(let ((map (copy-keymap xterm-function-map)))
(set-keymap-parent map (keymap-parent input-decode-map))
(set-keymap-parent input-decode-map map))))
And ensure .tmux.conf contains "set -g xterm-keys on".
Alternatively, the screen.el file can be copied to the load path and
customized.
* Why doesn't elinks set the window title inside tmux? * Why doesn't elinks set the window title inside tmux?
There isn't a way to detect if a terminal supports setting the window title, so There isn't a way to detect if a terminal supports setting the window title, so
@@ -352,6 +326,51 @@ lock(1) or vlock(1)) by using the following:
bind x set lock-command '/usr/bin/vlock' \; lock-client \; set lock-command 'tput civis && read -s -n1' bind x set lock-command '/usr/bin/vlock' \; lock-client \; set lock-command 'tput civis && read -s -n1'
* How can I open a new window in the same directory as the current window?
One option is to just run "TMUX= tmux" in the window. However, this only works if no
command is running, so that you can input the command.
A workaround is to let tmux know about the current path through an environment
variable. To do so, use the following command:
[ -n "$TMUX" ] && tmux setenv TMUXPWD_$(tmux display -p "#I") $PWD
Which sets TMUXPWD_i (where i is the number of the current window) to the path
of the current directory. This command can be added to PS1, for example:
PS1='$([ -n "$TMUX" ] && tmux setenv TMUXPWD_$(tmux display -p "#I") $PWD)\h$ '
When a new window is created, the shell should be asked to change
directory. You can define a new binding (for example, if using GNU bash):
bind-key C-c run-shell 'tmux neww "cd $(tmux display -p "\$TMUXPWD_#I"); exec bash"'
This solution will work even if a command is currently running in the terminal,
but it will not work from a window that has just been swapped with another
because TMUXPWD_i will not be updated after a swap. However, once a new prompt
is displayed, TMUXPWD_i is updated properly.
* tmux doesn't start with "daemon failed"
tmux shows something similar to this when started:
fatal: server_start: daemon failed: No such file or directory
fatal: main_dispatch: imsg_read failed
A possible reason is that /dev/null is not a character device or is otherwise
inaccessible.
Check with:
file /dev/null
ls -l /dev/null
If it is not a character device or has incorrect permissions, it can typically
be recreated with:
cd /dev && rm null && ./MAKEDEV null
* vim displays reverse video instead of italics, while less displays italics * vim displays reverse video instead of italics, while less displays italics
(or just regular text) instead of reverse. What's wrong? (or just regular text) instead of reverse. What's wrong?
@@ -390,76 +409,5 @@ If your urxvt cannot display italics at all, make sure you have an italics
capable font enabled, for example, add to ~/.Xdefaults: capable font enabled, for example, add to ~/.Xdefaults:
urxvt.italicFont: xft:Bitstream Vera Sans Mono:italic:autohint=true urxvt.italicFont: xft:Bitstream Vera Sans Mono:italic:autohint=true
* How can I make tmux use my terminal's scrollback buffer?
Normally, tmux enables the terminal's "alternate screen". Most terminals (such
as xterm) do not save scrollback for the alternate screen. You might prefer
tmux to use the normal screen, so it uses your terminal's scrollback
buffer. This way, you can access the scrollback buffer as usual, for example
using the mouse wheel - although there is no guarantee output inside tmux will
always (or ever) be added to the scrollback.
You can make tmux use the normal screen by telling it that your terminal does
not have an alternate screen. Put the following in ~/.tmux.conf:
set -ga terminal-overrides ',xterm*:smcup@:rmcup@'
Adjust if your $TERM does not start with xterm.
tmux will still emulate the alternate screen for applications run under tmux,
so you don't really lose anything with this setting. The only disadvantage is
that when you exit tmux, it will not restore whatever was there before you
started.
* How do I see the default configuration?
Show the default session options by starting a new tmux server with no
configuration file:
$ tmux -Lfoo -f/dev/null start\; show -g
Or the default window options:
$ tmux -Lfoo -f/dev/null start\; show -gw
* How do I copy a selection from tmux to the system's clipboard?
When running in xterm(1), tmux can automatically send copied text to the
clipboard. This is controlled by the set-clipboard option and also needs this
X resource to be set:
XTerm*disallowedWindowOps: 20,21,SetXprop
For rxvt-unicode (urxvt), there is an unofficial Perl extension here:
http://anti.teamidiot.de/static/nei/*/Code/urxvt/
Otherwise a key binding for copy mode using xclip (or xsel) works:
bind -temacs-copy C-y copy-pipe "xclip -i >/dev/null"
Or for inside and outside copy mode with the prefix key:
bind C-y run -b "tmux save-buffer - | xclip -i"
On OS X, reattach-to-usernamespace lets pbcopy/pbpaste work:
https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard
* Why do I see dots around a session when I attach to it?
tmux limits the size of the window to the smallest attached session. If
it didn't do this then it would be impossible to see the entire window.
The dots mark the size of the window tmux can display.
To avoid this, detach all other clients when attaching:
$ tmux attach -d
Or from inside tmux by detaching individual clients with C-b D or all
using:
C-b : attach -d
$Id$ $Id$

View File

@@ -2,19 +2,18 @@
# Obvious program stuff. # Obvious program stuff.
bin_PROGRAMS = tmux bin_PROGRAMS = tmux
CLEANFILES = tmux.1.mdoc tmux.1.man dist_man1_MANS = tmux.1
# Distribution tarball options. # Distribution tarball options.
EXTRA_DIST = \ EXTRA_DIST = \
CHANGES FAQ README TODO COPYING examples compat \ CHANGES FAQ NOTES TODO examples compat \
array.h compat.h tmux.h osdep-*.c mdoc2man.awk tmux.1 array.h compat.h tmux.h osdep-*.c
dist-hook: dist-hook:
make clean
grep "^#found_debug=" configure grep "^#found_debug=" configure
find $(distdir) -name .svn -type d|xargs rm -Rf find $(distdir) -name .svn -type d|xargs rm -Rf
# Preprocessor flags. # Preprocessor flags.
CPPFLAGS += @XOPEN_DEFINES@ -DTMUX_CONF="\"$(sysconfdir)/tmux.conf\"" CPPFLAGS += @XOPEN_DEFINES@
# glibc as usual does things ass-backwards and hides useful things by default, # glibc as usual does things ass-backwards and hides useful things by default,
# so everyone has to add this. # so everyone has to add this.
@@ -25,34 +24,34 @@ endif
# Set flags for gcc. gcc4 whines abouts silly stuff so it needs slightly # Set flags for gcc. gcc4 whines abouts silly stuff so it needs slightly
# different flags. # different flags.
if IS_GCC if IS_GCC
CFLAGS += -std=gnu99 -O2 CFLAGS += -std=c99
if IS_DEBUG if IS_DEBUG
CFLAGS += -g CFLAGS += -g -ggdb -O0
CFLAGS += -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 CFLAGS += -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
CFLAGS += -Wdeclaration-after-statement
CPPFLAGS += -DDEBUG CPPFLAGS += -DDEBUG
endif endif
if IS_GCC4 if IS_GCC4
CPPFLAGS += -iquote. CPPFLAGS += -iquote. -I/usr/local/include
if IS_DEBUG if IS_DEBUG
CFLAGS += -Wno-pointer-sign CFLAGS += -Wno-pointer-sign
endif endif
else else
CPPFLAGS += -I. -I- CPPFLAGS += -I. -I- -I/usr/local/include
endif endif
endif endif
# Set flags for static.
if IS_STATIC
LDFLAGS += -static
endif
# Set flags for Solaris. # Set flags for Solaris.
if IS_SUNOS if IS_SUNOS
if IS_GCC
CPPFLAGS += -D_XPG6 -D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS
else
CPPFLAGS += -D_XPG4_2 -D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS CPPFLAGS += -D_XPG4_2 -D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS
endif endif
endif
# Set flags for Sun CC. # Set flags for Sun CC.
if IS_SUNCC if IS_SUNCC
@@ -65,14 +64,17 @@ dist_tmux_SOURCES = \
attributes.c \ attributes.c \
cfg.c \ cfg.c \
client.c \ client.c \
clock.c \
cmd-attach-session.c \ cmd-attach-session.c \
cmd-bind-key.c \ cmd-bind-key.c \
cmd-break-pane.c \ cmd-break-pane.c \
cmd-capture-pane.c \ cmd-capture-pane.c \
cmd-choose-buffer.c \ cmd-choose-buffer.c \
cmd-choose-client.c \ cmd-choose-client.c \
cmd-choose-tree.c \ cmd-choose-session.c \
cmd-choose-window.c \
cmd-clear-history.c \ cmd-clear-history.c \
cmd-clock-mode.c \
cmd-command-prompt.c \ cmd-command-prompt.c \
cmd-confirm-before.c \ cmd-confirm-before.c \
cmd-copy-mode.c \ cmd-copy-mode.c \
@@ -81,14 +83,17 @@ dist_tmux_SOURCES = \
cmd-display-message.c \ cmd-display-message.c \
cmd-display-panes.c \ cmd-display-panes.c \
cmd-find-window.c \ cmd-find-window.c \
cmd-has-session.c \
cmd-if-shell.c \ cmd-if-shell.c \
cmd-join-pane.c \ cmd-join-pane.c \
cmd-kill-pane.c \ cmd-kill-pane.c \
cmd-kill-server.c \ cmd-kill-server.c \
cmd-kill-session.c \ cmd-kill-session.c \
cmd-kill-window.c \ cmd-kill-window.c \
cmd-link-window.c \
cmd-list-buffers.c \ cmd-list-buffers.c \
cmd-list-clients.c \ cmd-list-clients.c \
cmd-list-commands.c \
cmd-list-keys.c \ cmd-list-keys.c \
cmd-list-panes.c \ cmd-list-panes.c \
cmd-list-sessions.c \ cmd-list-sessions.c \
@@ -101,7 +106,6 @@ dist_tmux_SOURCES = \
cmd-new-window.c \ cmd-new-window.c \
cmd-paste-buffer.c \ cmd-paste-buffer.c \
cmd-pipe-pane.c \ cmd-pipe-pane.c \
cmd-queue.c \
cmd-refresh-client.c \ cmd-refresh-client.c \
cmd-rename-session.c \ cmd-rename-session.c \
cmd-rename-window.c \ cmd-rename-window.c \
@@ -115,27 +119,29 @@ dist_tmux_SOURCES = \
cmd-select-pane.c \ cmd-select-pane.c \
cmd-select-window.c \ cmd-select-window.c \
cmd-send-keys.c \ cmd-send-keys.c \
cmd-send-prefix.c \
cmd-server-info.c \
cmd-set-buffer.c \ cmd-set-buffer.c \
cmd-set-environment.c \ cmd-set-environment.c \
cmd-set-option.c \ cmd-set-option.c \
cmd-show-buffer.c \
cmd-show-environment.c \ cmd-show-environment.c \
cmd-show-messages.c \ cmd-show-messages.c \
cmd-show-options.c \ cmd-show-options.c \
cmd-source-file.c \ cmd-source-file.c \
cmd-split-window.c \ cmd-split-window.c \
cmd-start-server.c \
cmd-string.c \ cmd-string.c \
cmd-suspend-client.c \
cmd-swap-pane.c \ cmd-swap-pane.c \
cmd-swap-window.c \ cmd-swap-window.c \
cmd-switch-client.c \ cmd-switch-client.c \
cmd-unbind-key.c \ cmd-unbind-key.c \
cmd-wait-for.c \ cmd-unlink-window.c \
cmd.c \ cmd.c \
colour.c \ colour.c \
control.c \
control-notify.c \
environ.c \ environ.c \
format.c \ grid-utf8.c \
grid-cell.c \
grid-view.c \ grid-view.c \
grid.c \ grid.c \
input-keys.c \ input-keys.c \
@@ -149,7 +155,6 @@ dist_tmux_SOURCES = \
log.c \ log.c \
mode-key.c \ mode-key.c \
names.c \ names.c \
notify.c \
options-table.c \ options-table.c \
options.c \ options.c \
paste.c \ paste.c \
@@ -164,7 +169,6 @@ dist_tmux_SOURCES = \
session.c \ session.c \
signal.c \ signal.c \
status.c \ status.c \
style.c \
tmux.c \ tmux.c \
tty-acs.c \ tty-acs.c \
tty-keys.c \ tty-keys.c \
@@ -207,9 +211,6 @@ endif
if NO_FGETLN if NO_FGETLN
nodist_tmux_SOURCES += compat/fgetln.c nodist_tmux_SOURCES += compat/fgetln.c
endif endif
if NO_FPARSELN
nodist_tmux_SOURCES += compat/fparseln.c
endif
if NO_GETOPT if NO_GETOPT
nodist_tmux_SOURCES += compat/getopt.c nodist_tmux_SOURCES += compat/getopt.c
endif endif
@@ -225,28 +226,6 @@ endif
if NO_STRTONUM if NO_STRTONUM
nodist_tmux_SOURCES += compat/strtonum.c nodist_tmux_SOURCES += compat/strtonum.c
endif endif
if NO_B64_NTOP
nodist_tmux_SOURCES += compat/b64_ntop.c
endif
if NO_CFMAKERAW
nodist_tmux_SOURCES += compat/cfmakeraw.c
endif
if NO_OPENAT
nodist_tmux_SOURCES += compat/openat.c
endif
# Install tmux.1 in the right format.
install-exec-hook:
if test x@MANFORMAT@ = xmdoc; then \
sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1 \
>$(srcdir)/tmux.1.mdoc; \
else \
sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1| \
$(AWK) -f$(srcdir)/mdoc2man.awk >$(srcdir)/tmux.1.man; \
fi
$(mkdir_p) $(DESTDIR)$(mandir)/man1
$(INSTALL_DATA) $(srcdir)/tmux.1.@MANFORMAT@ \
$(DESTDIR)$(mandir)/man1/tmux.1
# Update SF web site. # Update SF web site.
upload-index.html: update-index.html upload-index.html: update-index.html
@@ -261,4 +240,4 @@ update-index.html:
convert "$$i" -resize 200x150 "small-$$i"; \ convert "$$i" -resize 200x150 "small-$$i"; \
done \ done \
) )
sed "s/%%RELEASE%%/${RELEASE}/g" www/index.html.in >www/index.html sed "s/%%VERSION%%/${VERSION}/g" www/index.html.in >www/index.html

65
NOTES Normal file
View File

@@ -0,0 +1,65 @@
Welcome to tmux!
tmux is a "terminal multiplexer", it enables a number of terminals (or windows)
to be accessed and controlled from a single terminal. tmux is intended to be a
simple, modern, BSD-licensed alternative to programs such as GNU screen.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux and OS X and may still
run on Solaris and AIX (although they haven't been tested in a while). It is
usable, although there remain a number of missing features and some remaining
bugs are expected.
Since the 1.2 release that tmux depends on libevent. Download it from:
http://www.monkey.org/~provos/libevent/
tmux consists of a server part and multiple clients. The server is created when
required and runs continuously unless killed by the user. Clients access the
server through a socket in /tmp. Multiple sessions may be created on a single
server and attached to a number of clients. Each session may then have a number
of windows and windows may be linked to a number of sessions. Commands are
available to create, rename and destroy windows and sessions; to attach and
detach sessions from client terminals; to set configuration options; to split
windows into several simultaneously displayed panes; and to bind and unbind
command keys (invoked preceded by a prefix key, by default ctrl-b). Please see
the tmux(1) man page for further information.
A more extensive, but rough, todo list is included in the TODO file.
tmux also depends on several features of the client terminal (TERM), if these
are missing it may refuse to run, or not behave correctly.
A Vim syntax file is available in the examples directory. To install it:
- Drop the file in the syntax directory in your runtimepath (such as
~/.vim/syntax/tmux.vim).
- Make the filetype recognisable by adding the following to filetype.vim
in your runtimepath (~/.vim/filetype.vim):
augroup filetypedetect
au BufNewFile,BufRead .tmux.conf*,tmux.conf* setf tmux
augroup END
- Switch on syntax highlighting by adding "syntax enable" to your vimrc file.
For debugging, running tmux with -v or -vv will generate server and client log
files in the current directory.
tmux mailing lists are available; visit:
https://sourceforge.net/mail/?group_id=200378
Bug reports, feature suggestions and especially code contributions are most
welcome. Please send by email to:
nicm@users.sf.net
This file and the CHANGES, FAQ and TODO files are licensed under the ISC
license. Files under examples/ remain copyright their authors unless otherwise
stated in the file but permission has been received to distribute them with
tmux. All other files have a license and copyright notice at their
start. Please contact me with any queries.
-- Nicholas Marriott <nicm@users.sf.net>
$Id$

60
README
View File

@@ -1,60 +0,0 @@
Welcome to tmux!
tmux is a "terminal multiplexer", it enables a number of terminals (or windows)
to be accessed and controlled from a single terminal. tmux is intended to be a
simple, modern, BSD-licensed alternative to programs such as GNU screen.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux and OS X and may still
run on Solaris and AIX (although they haven't been tested in a while).
tmux depends on libevent 2.x. Download it from:
http://www.monkey.org/~provos/libevent/
To build tmux from a release tarball, do:
$ ./configure && make
$ sudo make install
To get and build the latest from version control:
$ git clone git://git.code.sf.net/p/tmux/tmux-code tmux
$ cd tmux
$ sh autogen.sh
$ ./configure && make
For more information see https://sourceforge.net/scm/?type=git&group_id=200378
and http://git-scm.com. Patches should be sent by email to the mailing list at
tmux-users@lists.sourceforge.net.
For documentation on using tmux, see the tmux.1 manpage. It can be viewed from
the source tree with:
$ nroff -mdoc tmux.1|less
Some common questions are answered in the FAQ file and a more extensive (but
slightly out of date) guide is available in the OpenBSD FAQ at
http://www.openbsd.org/faq/faq7.html#tmux. A rough todo list is in the TODO
file and some example configurations and a Vim syntax file are in the examples
directory.
For debugging, running tmux with -v or -vv will generate server and client log
files in the current directory.
tmux mailing lists are available. Visit:
https://sourceforge.net/mail/?group_id=200378
Bug reports, feature suggestions and especially code contributions are most
welcome. Please send by email to:
tmux-users@lists.sourceforge.net
This file and the CHANGES, FAQ and TODO files are licensed under the ISC
license. Files under examples/ remain copyright their authors unless otherwise
stated in the file but permission has been received to distribute them with
tmux. All other files have a license and copyright notice at their start.
-- Nicholas Marriott <nicm@users.sf.net>
$Id$

183
SYNCING
View File

@@ -1,183 +0,0 @@
Preamble
========
Tmux on SourceForge has two git repositories [1] "tmux-code" and "tmux-openbsd".
Here's a description of them:
* "tmux-code" is the portable version, the one which contains code for other
operating systems, and autotools, etc., which isn't found or needed in the
OpenBSD base system.
* "tmux-openbsd" is the version of tmux in OpenBSD base system which provides
the basis of the portable tmux version.
Note: The "tmux-openbsd" repository is actually handled by "git cvsimport"
running at 15 minute intervals, so a commit made to OpenBSD's tmux CVS
repository will take at least that long to appear in this git repository.
(It might take longer, depending on the CVS mirror used to import the
OpenBSD code).
It is assumed that the person doing the sync has read/write access to the
tmux-code repository on SourceForge already.
If you've never used git before, git tracks meta-data about the committer
and the author, as part of a commit, hence:
% git config [--global] user.name "Your name"
% git config [--global] user.email "you@yourdomain.com"
Note that, if you already have this in the global ~/.gitconfig option, then
this will be used. Setting this per-repository would involve not using the
"--global" flag above. If you wish to use the same credentials always,
pass the "--global" option, as shown.
This is a one-off operation once the repository has been cloned, assuming
this information has ever been set before.
Cloning repositories
====================
This involves having both tmux-code and tmux-openbsd cloned, as in:
% cd /some/where/useful
% git clone ssh://${USER}@git.code.sf.net/p/tmux/tmux
% git clone ssh://${USER}@git.code.sf.net/p/tmux/tmux-openbsd
Note that you do not need additional checkouts to manage the sync -- an
existing clone of either repositories will suffice. So if you already have
these checkouts existing, skip that.
Adding in git-remotes
=====================
Because the portable "tmux-code" git repository and the "tmux-openbsd"
repository do not inherently share any history between each other, the
history has been faked between them. This "faking of history" is something
which has to be told to git for the purposes of comparing the "tmux" and
"tmux-openbsd" repositories for syncing. To do this, we must reference the
clone of the "tmux-openbsd" repository from the "tmux-code" repository, as
shown by the following command:
% cd /path/to/tmux-code
% git remote add obsd-tmux file:///path/to/tmux-openbsd
So that now, the remote "obsd-tmux" can be used to reference branches and
commits from the "tmux-openbsd" repository, but from the context of the
portable "tmux-code" repository, which makes sense because it's the "tmux"
repository which will have the updates applied to them.
Fetching updates
================
To ensure the latest commits from "tmux-openbsd" can be found from within
"tmux-code", we have to ensure the "master" branch from "tmux-openbsd" is
up-to-date first, and then reference that update in "tmux-code", as in:
% cd /path/to/tmux-openbsd
% git checkout master
% git pull
Then back in "tmux-code":
% cd /path/to/tmux-code
% git fetch obsd-tmux-code
Creating the necessary branches
===============================
Now that "tmux-code" can see commits and branches from "tmux-openbsd" by way
of the remote name "obsd-tmux", we can now create the master branch from
"tmux-openbsd" in the "tmux-code" repository:
% git checkout -b obsd-master obsd-tmux/master
Adding in the fake history points
=================================
To tie both the "master" branch from "tmux-code" and the "obsd-master"
branch from "tmux-openbsd" together, the fake history points added to the
"tmux-code" repository need to be added. To do this, we must add an
additional refspec line, as in:
% cd /path/to/tmux-code
% git config --add remote.origin.fetch '+refs/replace/*:refs/replace/*'
% git fetch origin
Performing the Sync
===================
Make sure the "master" branch is checked out:
% git checkout master
The following will show commits on OpenBSD not yet synched with "tmux-code":
% git log master..obsd-master
From there, merge the result in, fixing up any conflicts which might arise.
% git merge obsd-master
Then ensure things look correct by BULDING the result of that sync:
% make clean && ./autogen.sh && ./configure && make
Compare the git merge result with what's on origin/master -- that is, check
which commits you're about to push:
% git log origin/master..master
And if happy:
% git push origin master
Keeping an eye on libutil in OpenBSD
====================================
A lot of the compat/ code in tmux comes from libutil, especially imsg.
Sometimes the API can change, etc., which might cause interesting problems
trying to run the portable version of tmux. It's worth checking
periodically for any changes to libutil in OpenBSD and syncing those files
to compat/ as and when appropriate.
Release tmux for next version
=============================
1. Comment the "found_debug=yes" line in configure.ac, since releases
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
upgrades and the latter should mention all the major changes since
the last version.
3. Tag with:
% git tag -a 1.X
Where "1.X" is the next version.
Push the tag out with:
% git push 1.X
4. Build the tarball with make dist. Now that it's using autoconf there
shouldn't be any weird files (such as the original and rejection files
from patch(1)) but it doesn't hurt taking a quick look at it.
5. Split the release changes into a new file. This should be named
tmux-$VERSION-readme to make sourceforge show it automagically in specific
parts of the project page.
6. Upload the tarball and the above file. Make the tarball the default
download by selecting all operating systems under the file details.
7. Run make update-index.html upload-index.html to replace %%VERSION%%.
8. Bump version in configure.ac and uncomment "found_debug=yes" to create
a debug build by default.
9. Update freshmeat.
[1] https://sourceforge.net/p/tmux/_list/git

293
TODO
View File

@@ -1,155 +1,140 @@
- command bits and pieces: - implicitly add exec to the commands for new windows (switch to disable it)?
* why doesn't command-prompt work if made read-only? - bring back detach-session to detach all clients on a session?
* allow multiple targets: fnmatch for -t/-c, for example detach all - allow fnmatch for -c, so that you can, eg, detach all clients
clients with -t* - garbage collect window history (100 lines at a time?) if it hasn't been used
* add -c for new-session like new-window in $x time
* attach should take a pane and select it as well as attaching - flags to centre screen in window
* ' and " should be parsed the same (eg "\e" vs '\e') in config - activity/bell should be per-window not per-link? what if it is cur win in
and command prompt session not being watched?
* last-pane across sessions - next prev word etc in command prompt
* exact match operator for targets (or break the substring match - use a better termcap internally instead of screen, perhaps xterm
and require eg x* instead of just x) - should be able to move to a hidden pane and it would be moved into view. pane
number in status line/top-right would be cool for this
- make command sequences more usable - support other mouse modes (highlight etc) and use it in copy mode
* don't require space after ; - set-remain-on-exit is a bit of a hack, some way to do it generically?
* options for error handling: && and ||? - clear window title on exit
- would be nice to be able to use "--" to mark start of command w/ neww etc
- options bits and pieces: to avoid quoting
* set-remain-on-exit is a complete hack - make command sequences more usable: don't require space after ;, handle
* way to set socket path from config file errors better
- attach should have a flag to create session if it doesn't exist
- format improvements: - choice and more mode would be better per client than per window?
* last bits of status_replace into formats? - hooks to which commands may be attached, for example: tmux add-hook
* option to quote format (#{session_name:quoted}) "new-session" if-shell "[ -e $HOME/.tmux-session.conf ]" source-file
* formats need conditions for >0 (for #P) $HOME/.tmux-session.conf
* some way to pad # stuff with spaces, #!2T maybe - get it passing all the vttest tests that don't require resizing the terminal
* last window update time and format for it - way to set socket path from config file
* formats to show if a window is linked into multiple sessions, into - what about utmp etc? can tmux update it like screen? setgid?
multiple attached sessions, and is the active window in multiple
attached sessions?
- choose mode improvements:
* choose-pane command (augment choose-tree to do this?)
* choose-mode and copy-mode are very similar, make choose-mode a subset?
* flag to choose-* for sort order
* choose mode would be better per client than per window?
* two choices (first one then second, for swap-pane and join-pane)
- improve monitor-*:
* straighten out rules for multiple clients
* think about what happens across sessions
* monitor changes within a region
* perhaps monitor /all/ panes in the window not just one
- improve mouse support:
* bind commands to mouse in different areas?
* more fine-grained options?
* commands executed when clicking on a pattern (URL)
* mouse-select-pane will screw up with !MODE_MOUSE_STANDARD (it sets
the flag on w/o checking the others before calling tty_update_mode)
* mouse can be like normal key bindings?
- {button-{1,2,3},wheel-{up,down}}-{status,pane,border} and
drag-{start,end}-{status,pane,border} plus the modifiers
- resize and copy can be special cases - once you call something
like copy-mode -M or resize-pane -M to start the drag, it tracks
mouse until you call -m to stop the drag. or just keep drags
entirely special?
- what happens with stuff that wants mouse inside? especially for
pane clicks which need to run command AND pass event through
(like mouse-select-pane). maybe just a flag to say whether it
always runs or only if pane hasn't taken mouse? or it could be
eg bind Button1Pane "select-pane -t=; send-keys -Mt='
- also need a) some way to tell commands bound to key which
window or pane the mouse key binding applies to (maybe a new
special char in target, or pass targets through formats?) b) a
way to bind repeat count to mode keys so that wheel up/down can
do multiple lines c) send-keys -M to pass a mouse event through?
- what does the mouse->KEYC_* conversion and find-the-pane bit?
server_client_handle_key?
- hooks!
- warts on current naming: - warts on current naming:
* display-time but message-fg/bg/attr - display-time but message-fg/bg/attr
* list-* vs show-* - list-* vs show-*
* split-window -> split-pane?? - server-info
- up-pane/down-pane/swap-pane -U/swap-pane -D vs next-*/previous-*
- better UTF-8 support: - split-window -> split-pane??
* window names and titles - a way for force-width/height to apply to only one pane (how?)
* message display - command to list what is actually running in each window with command line,
* prompt input pid (need some adaption of the osdep code)
* multibyte key input - support for bce
- some way to force a screen to use the entire terminal even if it is forced
- copy/paste improvements: to be smaller by other clients. pan smaller terminal? (like screen F)
* incremental searching -- idea of a "view" onto a window, need base x/y offsets for redraw
* append to buffer - handle resize better in copy mode
* paste w/o trailing whitespace - way to copy stuff that is off screen due to resize
* command to toggle selection not to move it in copy-mode - commands should be able to succeed or fail and have || or && for command
lists
- layout stuff - some way to KEEP a command running continually and just use its LAST line of
* way to tag a layout as a number/name output
* maybe keep last layout + size around and if size reverts just put it - UTF-8 to a non-UTF-8 terminal should not be able to balls up
back the terminal - www/ruby-addressable; make regress
* revamp layouts: they are too complicated, should be more closely - support esc-esc to quit in modes
integrated, should support hints, layout sets should just be a - fix ctrl+F1-F4 output. to what?
special case of custom layouts, and we should support panes that are - better utf8 support: window names, prompt input, message display
not attached to a cell at all. this could be the time to introduce - session history for client and last-session command
panelink to replace layout_cell - option to change status line colour when current window is in a mode?
* way to set hints/limits about pane size for resizing - option to move copy mode indicator into status line
* panning over window (window larger than visible) - list-buffer/show-buffer should display UTF-8
* a mode where one application can cross two panes (ie x|y, width = - selection behaviour closer to vi in vi mode
COLUMNS/2 but height = ROWS * 2) - live update: server started with -U connects to server, requests sessions and
* general key to space cells out evenly (horiz or vert) within their windows, receives fds
parent cell (could replace even-vert/even-horiz layouts) - command to show a tree of sessions-windows-panes (active marked with *)
- sort out inheriting config from shell on new sessions/windows:
- terminfo bits should pick up default-path/termios/etc from client if possible,
* use a better termcap internally instead of screen, perhaps xterm else leave empty/default
* use screen-256color when started on 256 colour terminal? - link panes into multiple windows
* need a tmux terminfo entry to document the extensions we are using in - bells should be passed between sessions with visual-bell etc
upstream terminfo - use screen-256color when started on 256 colour terminal??
- if-shell/run-shell should block further command execution in the same command
- code cleanup sequence until its shell exits, to allow them to be used from the config file
* instead of separate window and session options, just one master - better session sharing: create-socket command to create socket somewhere (-r
options list with each option having a type (window or session), then flag for readonly)
options on window, on session, and global. for window options we look - allow buffer to be specified when copying in copy mode
window->session->global, and for session we look session->global - multiline status line (no?)
* the way pane, window, session destroy is handled is too complicated - flag for absolute pane size to resize-pane
and the distinction between session.c, window.c and server-fn.c - sanity check input to socket
functions is not clear. could we just have kill_pane(), - support title stack, both internally and externally
kill_window(), unlink_window(), kill_session() that fix up all data http://docs.freebsd.org/cgi/getmsg.cgi?fetch=1149299+0+archive/2010/freebsd-questions/20100207.freebsd-questions
structures (flagging sessions as dead) and return a value to say - command to show status line information briefly when it is off
whether clients need to be checked for dead sessions? sort of like - some way to pad # stuff with spaces, #!2T maybe
session_detach now but more so. or some other scheme to make it - a binding to "scroll down and exit at bottom" copy mode
simpler and clearer? also would be nice to remove/rename server-fn.c - some way to pass keystrokes in copy mode through to underlying window
* more readable way to work out the various things commands need to - last window update time and # replacement for it for display-message
know about the client, notably: - find-window across sessions - other ways to make session handling easier?
- is this the config file? (cmdq->c == NULL) - ' and " should be parsed the same (eg "\e" vs '\e') in config and command
- is this a command client? (cmdq->c != NULL && prompt?
cmdq->c->session == NULL) - command to toggle selection not to move it in copy-mode
- is this a control client? - why are alerts per-winlink? try per window?
- can i do stdin or stdout to this client? - audit of escape sequence support vs xterm
or even guarantee that cmdq->c != NULL and provide a better way to - support binding keys to mouse (mouse-select-pane -> mouse-keys or something,
tell when in the config file - then we use cmdq->c if we need a mouse click == select-pane -t %%, mouse scroll up == copy-mode)
client w/o a session else cmd_current_client - something for -t "last window in session" so a session can be used as a stack
* optimize pane redraws, 20120318184853.GK10965@yelena.nicm.ath.cx - synchronous commands - client sends cmd and blocks, neww/splitw saves client
* cmd_find_* could be much simpler - parse everything the same, only ptr then when program inside died, sends MSG_SOMETHING with wait status to
difference is what to choose when not given a ":" or "." (such as a client
plain "0" could be session, window or pane). So just cmd_find_target - documentation improvements - rlpowell's tutorial - build instructions
with a type (session, window, or pane).. - bind commands to key sequences? -- make it so ALL keys go through a table,
first an implicit table in which C-b is the only default binding to a
- miscellaneous command that says "next key from $othertable" and so on. means -n can
* way to keep a job running just read its last line of output for #() go away as well
* link panes into multiple windows - monitor, bell etc should monitor /all/ panes in the window not just one
* live update: server started with -U connects to server, requests - a history of commands that can be reversed (reverse member of each command,
sessions and windows, receives file descriptors and a buffer) info() when changing to same window
* there are inconsistencies in what we get from old shell and what - way to add dest for break-pane; maybe some easier way to unbreak-pane
comes from config for new sessions and windows. likewise, panes and - case insensitive searching
jobs and run-shell and lock command all start with slightly different - pane-index option like base-index
environments - option to move status line to top
* multiline status line? - configurable borders and empty space filler for when panes < window?
* bind commands to key sequences -- make it so ALL keys go through a - mouse-select-pane will screw up with !MODE_MOUSE_STANDARD (it sets the
table, first an implicit table in which C-b is the only default flag on w/o checking the others before calling tty_update_mode)
binding to a command that says "next key from $othertable" and so - multiple keys could be done with tables, ie have prefixes go and instead
on. means -n can go away as well bind -n ^A prefix-table "default"
* customizable command aliases where prefix-table sets command lookup table and sets prefix flag, then next
* any remaining clients in wait-for should be woken when server exits key is looked up in that table
- pass shell commands as argv rather than strings, allow them to be specified
in commands without quotes
- a command to choose from a generic list, so you can do eg
choose-list -l Abc,Moo,Blah "run-shell 'sh /my/choose/script %%'"
- else part for if-shell
- add general internal format for lists (key=value) and a way to output them in
different representations, use for list-windows, etc etc. see message id
20110221205346.GA1580@yelena.nicm.ath.cx
- numeric prefix in copy mode should be paste buffer for C-w
- named buffers and allow gaps in the stack
- npage/ppage/dc/ic should have aliases for more typical names
- get rid of separate UTF-8 cell stuff: add 1 byte to cell and store BMP as
uint16_t+3 bits of flags. anything <=0xffff is Unicode, higher are used to
build tree of combined characters/non-BMP (LRU dropped when full)
- entry in FAQ about what to do when someone does mkdir /tmp/tmux-1000
- show size under pane number in display-panes mode
- monitor-activity is broken in several ways with multiple clients
- monitor-activity should be more powerful (eg set a region)
- maybe a way to put pane names instead of window names in status line
- Support for borderless panes
- run-shell/if-shell should support status_replace stuff
- wait-pane command or another way to make it synchronous/wait for command to
finish
- way to get command window was started with (part of format stuff?)
- last-pane across sessions
- attach should take a pane and select it as well as attaching
* We need a tmux terminfo entry to document the extensions we are using in
upstream terminfo. Must NOT change (only add or remove) anything from
TERM=screen so we can fallback!

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,28 +18,11 @@
#include <sys/types.h> #include <sys/types.h>
#include <getopt.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
/*
* Manipulate command arguments.
*/
struct args_entry *args_find(struct args *, u_char);
RB_GENERATE(args_tree, args_entry, entry, args_cmp);
/* Arguments tree comparison function. */
int
args_cmp(struct args_entry *a1, struct args_entry *a2)
{
return (a1->flag - a2->flag);
}
/* Create an arguments set with no flags. */ /* Create an arguments set with no flags. */
struct args * struct args *
args_create(int argc, ...) args_create(int argc, ...)
@@ -49,6 +32,8 @@ args_create(int argc, ...)
int i; int i;
args = xcalloc(1, sizeof *args); args = xcalloc(1, sizeof *args);
if ((args->flags = bit_alloc(SCHAR_MAX)) == NULL)
fatal("bit_alloc failed");
args->argc = argc; args->argc = argc;
if (argc == 0) if (argc == 0)
@@ -64,36 +49,36 @@ args_create(int argc, ...)
return (args); return (args);
} }
/* Find a flag in the arguments tree. */
struct args_entry *
args_find(struct args *args, u_char ch)
{
struct args_entry entry;
entry.flag = ch;
return (RB_FIND(args_tree, &args->tree, &entry));
}
/* Parse an argv and argc into a new argument set. */ /* Parse an argv and argc into a new argument set. */
struct args * struct args *
args_parse(const char *template, int argc, char **argv) args_parse(const char *template, int argc, char **argv)
{ {
struct args *args; struct args *args;
char *ptr;
int opt; int opt;
args = xcalloc(1, sizeof *args); args = xcalloc(1, sizeof *args);
if ((args->flags = bit_alloc(SCHAR_MAX)) == NULL)
fatal("bit_alloc failed");
optreset = 1; optreset = 1;
optind = 1; optind = 1;
while ((opt = getopt(argc, argv, template)) != -1) { while ((opt = getopt(argc, argv, template)) != -1) {
if (opt < 0) if (opt < 0 || opt >= SCHAR_MAX)
continue; continue;
if (opt == '?' || strchr(template, opt) == NULL) { if (opt == '?' || (ptr = strchr(template, opt)) == NULL) {
args_free(args); xfree(args->flags);
xfree(args);
return (NULL); return (NULL);
} }
args_set(args, opt, optarg);
bit_set(args->flags, opt);
if (ptr[1] == ':') {
if (args->values[opt] != NULL)
xfree(args->values[opt]);
args->values[opt] = xstrdup(optarg);
}
} }
argc -= optind; argc -= optind;
argv += optind; argv += optind;
@@ -108,28 +93,26 @@ args_parse(const char *template, int argc, char **argv)
void void
args_free(struct args *args) args_free(struct args *args)
{ {
struct args_entry *entry; u_int i;
struct args_entry *entry1;
cmd_free_argv(args->argc, args->argv); cmd_free_argv(args->argc, args->argv);
RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) { for (i = 0; i < SCHAR_MAX; i++) {
RB_REMOVE(args_tree, &args->tree, entry); if (args->values[i] != NULL)
free(entry->value); xfree(args->values[i]);
free(entry);
} }
free(args); xfree(args->flags);
xfree(args);
} }
/* Print a set of arguments. */ /* Print a set of arguments. */
size_t size_t
args_print(struct args *args, char *buf, size_t len) args_print(struct args *args, char *buf, size_t len)
{ {
size_t off, used; size_t off;
int i; int i;
const char *quotes; const char *quotes;
struct args_entry *entry;
/* There must be at least one byte at the start. */ /* There must be at least one byte at the start. */
if (len == 0) if (len == 0)
@@ -138,23 +121,23 @@ args_print(struct args *args, char *buf, size_t len)
/* Process the flags first. */ /* Process the flags first. */
buf[off++] = '-'; buf[off++] = '-';
RB_FOREACH(entry, args_tree, &args->tree) { for (i = 0; i < SCHAR_MAX; i++) {
if (entry->value != NULL) if (!bit_test(args->flags, i) || args->values[i] != NULL)
continue; continue;
if (off == len - 1) { if (off == len - 1) {
buf[off] = '\0'; buf[off] = '\0';
return (len); return (len);
} }
buf[off++] = entry->flag; buf[off++] = i;
buf[off] = '\0'; buf[off] = '\0';
} }
if (off == 1) if (off == 1)
buf[--off] = '\0'; buf[--off] = '\0';
/* Then the flags with arguments. */ /* Then the flags with arguments. */
RB_FOREACH(entry, args_tree, &args->tree) { for (i = 0; i < SCHAR_MAX; i++) {
if (entry->value == NULL) if (!bit_test(args->flags, i) || args->values[i] == NULL)
continue; continue;
if (off >= len) { if (off >= len) {
@@ -162,16 +145,12 @@ args_print(struct args *args, char *buf, size_t len)
return (len); return (len);
} }
if (strchr(entry->value, ' ') != NULL) if (strchr(args->values[i], ' ') != NULL)
quotes = "\""; quotes = "\"";
else else
quotes = ""; quotes = "";
used = xsnprintf(buf + off, len - off, "%s-%c %s%s%s", off += xsnprintf(buf + off, len - off, "%s-%c %s%s%s",
off != 0 ? " " : "", entry->flag, quotes, entry->value, off != 0 ? " " : "", i, quotes, args->values[i], quotes);
quotes);
if (used > len - off)
used = len - off;
off += used;
} }
/* And finally the argument vector. */ /* And finally the argument vector. */
@@ -185,11 +164,8 @@ args_print(struct args *args, char *buf, size_t len)
quotes = "\""; quotes = "\"";
else else
quotes = ""; quotes = "";
used = xsnprintf(buf + off, len - off, "%s%s%s%s", off += xsnprintf(buf + off, len - off, "%s%s%s%s",
off != 0 ? " " : "", quotes, args->argv[i], quotes); off != 0 ? " " : "", quotes, args->argv[i], quotes);
if (used > len - off)
used = len - off;
off += used;
} }
return (off); return (off);
@@ -199,55 +175,43 @@ args_print(struct args *args, char *buf, size_t len)
int int
args_has(struct args *args, u_char ch) args_has(struct args *args, u_char ch)
{ {
return (args_find(args, ch) == NULL ? 0 : 1); return (bit_test(args->flags, ch));
} }
/* Set argument value in the arguments tree. */ /* Set argument value. */
void void
args_set(struct args *args, u_char ch, const char *value) args_set(struct args *args, u_char ch, const char *value)
{ {
struct args_entry *entry; if (args->values[ch] != NULL)
xfree(args->values[ch]);
/* Replace existing argument. */
if ((entry = args_find(args, ch)) != NULL) {
free(entry->value);
entry->value = NULL;
} else {
entry = xcalloc(1, sizeof *entry);
entry->flag = ch;
RB_INSERT(args_tree, &args->tree, entry);
}
if (value != NULL) if (value != NULL)
entry->value = xstrdup(value); args->values[ch] = xstrdup(value);
else
args->values[ch] = NULL;
bit_set(args->flags, ch);
} }
/* Get argument value. Will be NULL if it isn't present. */ /* Get argument value. Will be NULL if it isn't present. */
const char * const char *
args_get(struct args *args, u_char ch) args_get(struct args *args, u_char ch)
{ {
struct args_entry *entry; return (args->values[ch]);
if ((entry = args_find(args, ch)) == NULL)
return (NULL);
return (entry->value);
} }
/* Convert an argument value to a number. */ /* Convert an argument value to a number. */
long long long long
args_strtonum(struct args *args, u_char ch, long long minval, long long maxval, args_strtonum(struct args *args,
char **cause) u_char ch, long long minval, long long maxval, char **cause)
{ {
const char *errstr; const char *errstr;
long long ll; long long ll;
struct args_entry *entry;
if ((entry = args_find(args, ch)) == NULL) { if (!args_has(args, ch)) {
*cause = xstrdup("missing"); *cause = xstrdup("missing");
return (0); return (0);
} }
ll = strtonum(entry->value, minval, maxval, &errstr); ll = strtonum(args->values[ch], minval, maxval, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
*cause = xstrdup(errstr); *cause = xstrdup(errstr);
return (0); return (0);

View File

@@ -39,10 +39,10 @@
fatalx("size too big"); \ fatalx("size too big"); \
if ((a)->space == 0) { \ if ((a)->space == 0) { \
(a)->space = ARRAY_INITIALSPACE(a); \ (a)->space = ARRAY_INITIALSPACE(a); \
(a)->list = xrealloc((a)->list, (a)->space); \ (a)->list = xrealloc((a)->list, 1, (a)->space); \
} \ } \
while ((a)->space <= ((a)->num + (n)) * ARRAY_ITEMSIZE(a)) { \ while ((a)->space <= ((a)->num + (n)) * ARRAY_ITEMSIZE(a)) { \
(a)->list = xreallocarray((a)->list, 2, (a)->space); \ (a)->list = xrealloc((a)->list, 2, (a)->space); \
(a)->space *= 2; \ (a)->space *= 2; \
} \ } \
} while (0) } while (0)
@@ -109,12 +109,13 @@
} while (0) } while (0)
#define ARRAY_FREE(a) do { \ #define ARRAY_FREE(a) do { \
free((a)->list); \ if ((a)->list != NULL) \
xfree((a)->list); \
ARRAY_INIT(a); \ ARRAY_INIT(a); \
} while (0) } while (0)
#define ARRAY_FREEALL(a) do { \ #define ARRAY_FREEALL(a) do { \
ARRAY_FREE(a); \ ARRAY_FREE(a); \
free(a); \ xfree(a); \
} while (0) } while (0)
#endif #endif

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org> * Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org>
@@ -26,21 +26,27 @@ const char *
attributes_tostring(u_char attr) attributes_tostring(u_char attr)
{ {
static char buf[128]; static char buf[128];
size_t len;
if (attr == 0) if (attr == 0)
return ("none"); return ("none");
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s", buf[0] = '\0';
attr & GRID_ATTR_BRIGHT ? "bright," : "", if (attr & GRID_ATTR_BRIGHT)
attr & GRID_ATTR_DIM ? "dim," : "", strlcat(buf, "bright,", sizeof (buf));
attr & GRID_ATTR_UNDERSCORE ? "underscore," : "", if (attr & GRID_ATTR_DIM)
attr & GRID_ATTR_BLINK ? "blink," : "", strlcat(buf, "dim,", sizeof (buf));
attr & GRID_ATTR_REVERSE ? "reverse," : "", if (attr & GRID_ATTR_UNDERSCORE)
attr & GRID_ATTR_HIDDEN ? "hidden," : "", strlcat(buf, "underscore,", sizeof (buf));
attr & GRID_ATTR_ITALICS ? "italics," : ""); if (attr & GRID_ATTR_BLINK)
if (len > 0) strlcat(buf, "blink,", sizeof (buf));
buf[len - 1] = '\0'; if (attr & GRID_ATTR_REVERSE)
strlcat(buf, "reverse,", sizeof (buf));
if (attr & GRID_ATTR_HIDDEN)
strlcat(buf, "hidden,", sizeof (buf));
if (attr & GRID_ATTR_ITALICS)
strlcat(buf, "italics,", sizeof (buf));
if (*buf != '\0')
*(strrchr(buf, ',')) = '\0';
return (buf); return (buf);
} }

6
autogen.sh Executable file → Normal file
View File

@@ -1,10 +1,8 @@
#!/bin/sh #!/bin/sh
# $Id$ # $Id$
if [ "x$(uname)" = "xOpenBSD" ]; then [ -z "$AUTOMAKE_VERSION" ] && export AUTOMAKE_VERSION=1.10
[ -z "$AUTOMAKE_VERSION" ] && export AUTOMAKE_VERSION=1.10 [ -z "$AUTOCONF_VERSION" ] && export AUTOCONF_VERSION=2.65
[ -z "$AUTOCONF_VERSION" ] && export AUTOCONF_VERSION=2.65
fi
die() die()
{ {

215
cfg.c
View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -17,144 +17,127 @@
*/ */
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
struct cmd_q *cfg_cmd_q; /*
int cfg_finished; * Config file parser. Pretty quick and simple, each line is parsed into a
int cfg_references; * argv array and executed as a command.
ARRAY_DECL (, char *) cfg_causes = ARRAY_INITIALIZER; */
struct client *cfg_client;
int void printflike2 cfg_print(struct cmd_ctx *, const char *, ...);
load_cfg(const char *path, struct cmd_q *cmdq, char **cause) void printflike2 cfg_error(struct cmd_ctx *, const char *, ...);
char *cfg_cause;
int cfg_finished;
struct causelist cfg_causes = ARRAY_INITIALIZER;
/* ARGSUSED */
void printflike2
cfg_print(unused struct cmd_ctx *ctx, unused const char *fmt, ...)
{ {
FILE *f;
char delim[3] = { '\\', '\\', '\0' };
u_int found;
size_t line = 0;
char *buf, *cause1, *p;
struct cmd_list *cmdlist;
log_debug("loading %s", path);
if ((f = fopen(path, "rb")) == NULL) {
xasprintf(cause, "%s: %s", path, strerror(errno));
return (-1);
}
found = 0;
while ((buf = fparseln(f, NULL, &line, delim, 0))) {
log_debug("%s: %s", path, buf);
/* Skip empty lines. */
p = buf;
while (isspace((u_char) *p))
p++;
if (*p == '\0') {
free(buf);
continue;
}
/* Parse and run the command. */
if (cmd_string_parse(p, &cmdlist, path, line, &cause1) != 0) {
free(buf);
if (cause1 == NULL)
continue;
cfg_add_cause("%s:%zu: %s", path, line, cause1);
free(cause1);
continue;
}
free(buf);
if (cmdlist == NULL)
continue;
cmdq_append(cmdq, cmdlist);
cmd_list_free(cmdlist);
found++;
}
fclose(f);
return (found);
} }
void /* ARGSUSED */
cfg_default_done(unused struct cmd_q *cmdq) void printflike2
{ cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...)
if (--cfg_references != 0)
return;
cfg_finished = 1;
if (!RB_EMPTY(&sessions))
cfg_show_causes(RB_MIN(sessions, &sessions));
cmdq_free(cfg_cmd_q);
cfg_cmd_q = NULL;
if (cfg_client != NULL) {
/*
* The client command queue starts with client_exit set to 1 so
* only continue if not empty (that is, we have been delayed
* during configuration parsing for long enough that the
* MSG_COMMAND has arrived), else the client will exit before
* the MSG_COMMAND which might tell it not to.
*/
if (!TAILQ_EMPTY(&cfg_client->cmdq->queue))
cmdq_continue(cfg_client->cmdq);
cfg_client->references--;
cfg_client = NULL;
}
}
void
cfg_add_cause(const char* fmt, ...)
{ {
va_list ap; va_list ap;
char* msg;
va_start(ap, fmt); va_start(ap, fmt);
xvasprintf(&msg, fmt, ap); xvasprintf(&cfg_cause, fmt, ap);
va_end (ap); va_end(ap);
ARRAY_ADD(&cfg_causes, msg);
} }
void void printflike2
cfg_print_causes(struct cmd_q *cmdq) cfg_add_cause(struct causelist *causes, const char *fmt, ...)
{ {
char *cause; char *cause;
u_int i; va_list ap;
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) { va_start(ap, fmt);
cause = ARRAY_ITEM(&cfg_causes, i); xvasprintf(&cause, fmt, ap);
cmdq_print(cmdq, "%s", cause); va_end(ap);
free(cause);
} ARRAY_ADD(causes, cause);
ARRAY_FREE(&cfg_causes);
} }
void /*
cfg_show_causes(struct session *s) * Load configuration file. Returns -1 for an error with a list of messages in
* causes. Note that causes must be initialised by the caller!
*/
int
load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)
{ {
struct window_pane *wp; FILE *f;
char *cause; u_int n;
u_int i; char *buf, *line, *cause;
size_t len;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
int retval;
if (s == NULL || ARRAY_EMPTY(&cfg_causes)) if ((f = fopen(path, "rb")) == NULL) {
return; cfg_add_cause(causes, "%s: %s", path, strerror(errno));
wp = s->curw->window->active; return (-1);
window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp);
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
cause = ARRAY_ITEM(&cfg_causes, i);
window_copy_add(wp, "%s", cause);
free(cause);
} }
ARRAY_FREE(&cfg_causes); n = 0;
line = NULL;
retval = 0;
while ((buf = fgetln(f, &len))) {
if (buf[len - 1] == '\n')
buf[len - 1] = '\0';
else {
line = xrealloc(line, 1, len + 1);
memcpy(line, buf, len);
line[len] = '\0';
buf = line;
}
n++;
if (cmd_string_parse(buf, &cmdlist, &cause) != 0) {
if (cause == NULL)
continue;
cfg_add_cause(causes, "%s: %u: %s", path, n, cause);
xfree(cause);
continue;
}
if (cmdlist == NULL)
continue;
cfg_cause = NULL;
if (ctxin == NULL) {
ctx.msgdata = NULL;
ctx.curclient = NULL;
ctx.cmdclient = NULL;
} else {
ctx.msgdata = ctxin->msgdata;
ctx.curclient = ctxin->curclient;
ctx.cmdclient = ctxin->cmdclient;
}
ctx.error = cfg_error;
ctx.print = cfg_print;
ctx.info = cfg_print;
cfg_cause = NULL;
if (cmd_list_exec(cmdlist, &ctx) == 1)
retval = 1;
cmd_list_free(cmdlist);
if (cfg_cause != NULL) {
cfg_add_cause(causes, "%s: %d: %s", path, n, cfg_cause);
xfree(cfg_cause);
}
}
if (line != NULL)
xfree(line);
fclose(f);
return (retval);
} }

480
client.c
View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -17,7 +17,6 @@
*/ */
#include <sys/types.h> #include <sys/types.h>
#include <sys/file.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/un.h> #include <sys/un.h>
@@ -26,7 +25,7 @@
#include <errno.h> #include <errno.h>
#include <event.h> #include <event.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h> #include <pwd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@@ -35,64 +34,20 @@
struct imsgbuf client_ibuf; struct imsgbuf client_ibuf;
struct event client_event; struct event client_event;
struct event client_stdin; const char *client_exitmsg;
enum {
CLIENT_EXIT_NONE,
CLIENT_EXIT_DETACHED,
CLIENT_EXIT_DETACHED_HUP,
CLIENT_EXIT_LOST_TTY,
CLIENT_EXIT_TERMINATED,
CLIENT_EXIT_LOST_SERVER,
CLIENT_EXIT_EXITED,
CLIENT_EXIT_SERVER_EXITED,
} client_exitreason = CLIENT_EXIT_NONE;
int client_exitval; int client_exitval;
enum msgtype client_exittype; enum msgtype client_exittype;
const char *client_exitsession;
int client_attached; int client_attached;
int client_get_lock(char *);
int client_connect(char *, int); int client_connect(char *, int);
void client_send_identify(int); void client_send_identify(int);
int client_write_one(enum msgtype, int, const void *, size_t); void client_send_environ(void);
int client_write_server(enum msgtype, const void *, size_t); void client_write_server(enum msgtype, void *, size_t);
void client_update_event(void); void client_update_event(void);
void client_signal(int, short, void *); void client_signal(int, short, void *);
void client_stdin_callback(int, short, void *);
void client_write(int, const char *, size_t);
void client_callback(int, short, void *); void client_callback(int, short, void *);
int client_dispatch_attached(void); int client_dispatch_attached(void);
int client_dispatch_wait(void *); int client_dispatch_wait(void *);
const char *client_exit_message(void);
/*
* Get server create lock. If already held then server start is happening in
* another client, so block until the lock is released and return -1 to
* retry. Ignore other errors - just continue and start the server without the
* lock.
*/
int
client_get_lock(char *lockfile)
{
int lockfd;
if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1)
fatal("open failed");
log_debug("lock file is %s", lockfile);
if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
log_debug("flock failed: %s", strerror(errno));
if (errno != EAGAIN)
return (lockfd);
while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
/* nothing */;
close(lockfd);
return (-1);
}
log_debug("flock succeeded");
return (lockfd);
}
/* Connect client to server. */ /* Connect client to server. */
int int
@@ -100,8 +55,7 @@ client_connect(char *path, int start_server)
{ {
struct sockaddr_un sa; struct sockaddr_un sa;
size_t size; size_t size;
int fd, lockfd = -1, locked = 0; int fd;
char *lockfile = NULL;
memset(&sa, 0, sizeof sa); memset(&sa, 0, sizeof sa);
sa.sun_family = AF_UNIX; sa.sun_family = AF_UNIX;
@@ -110,50 +64,25 @@ client_connect(char *path, int start_server)
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
return (-1); return (-1);
} }
log_debug("socket is %s", path);
retry:
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
fatal("socket failed"); fatal("socket failed");
log_debug("trying connect");
if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
log_debug("connect failed: %s", strerror(errno));
if (errno != ECONNREFUSED && errno != ENOENT)
goto failed;
if (!start_server) if (!start_server)
goto failed; goto failed;
close(fd); switch (errno) {
case ECONNREFUSED:
if (!locked) { if (unlink(path) != 0)
xasprintf(&lockfile, "%s.lock", path); goto failed;
if ((lockfd = client_get_lock(lockfile)) == -1) { /* FALLTHROUGH */
log_debug("didn't get lock"); case ENOENT:
free(lockfile); if ((fd = server_start()) == -1)
goto retry; goto failed;
} break;
log_debug("got lock"); default:
goto failed;
/*
* Always retry at least once, even if we got the lock,
* because another client could have taken the lock,
* started the server and released the lock between our
* connect() and flock().
*/
locked = 1;
goto retry;
} }
if (unlink(path) != 0 && errno != ENOENT) {
free(lockfile);
close(lockfd);
return (-1);
}
fd = server_start(lockfd, lockfile);
}
if (locked) {
free(lockfile);
close(lockfd);
} }
setblocking(fd, 0); setblocking(fd, 0);
@@ -164,56 +93,17 @@ failed:
return (-1); return (-1);
} }
/* Get exit string from reason number. */
const char *
client_exit_message(void)
{
static char msg[256];
switch (client_exitreason) {
case CLIENT_EXIT_NONE:
break;
case CLIENT_EXIT_DETACHED:
if (client_exitsession != NULL) {
xsnprintf(msg, sizeof msg, "detached "
"(from session %s)", client_exitsession);
return (msg);
}
return ("detached");
case CLIENT_EXIT_DETACHED_HUP:
if (client_exitsession != NULL) {
xsnprintf(msg, sizeof msg, "detached and SIGHUP "
"(from session %s)", client_exitsession);
return (msg);
}
return ("detached and SIGHUP");
case CLIENT_EXIT_LOST_TTY:
return ("lost tty");
case CLIENT_EXIT_TERMINATED:
return ("terminated");
case CLIENT_EXIT_LOST_SERVER:
return ("lost server");
case CLIENT_EXIT_EXITED:
return ("exited");
case CLIENT_EXIT_SERVER_EXITED:
return ("server exited");
}
return ("unknown reason");
}
/* Client main loop. */ /* Client main loop. */
int int
client_main(int argc, char **argv, int flags) client_main(int argc, char **argv, int flags)
{ {
struct cmd *cmd; struct cmd *cmd;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct msg_command_data *data; struct msg_command_data cmddata;
int cmdflags, fd, i; int cmdflags, fd;
pid_t ppid; pid_t ppid;
enum msgtype msg; enum msgtype msg;
char *cause; char *cause;
struct termios tio, saved_tio;
size_t size;
/* Set up the initial command. */ /* Set up the initial command. */
cmdflags = 0; cmdflags = 0;
@@ -222,7 +112,7 @@ client_main(int argc, char **argv, int flags)
cmdflags = CMD_STARTSERVER; cmdflags = CMD_STARTSERVER;
} else if (argc == 0) { } else if (argc == 0) {
msg = MSG_COMMAND; msg = MSG_COMMAND;
cmdflags = CMD_STARTSERVER|CMD_CANTNEST; cmdflags = CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST;
} else { } else {
msg = MSG_COMMAND; msg = MSG_COMMAND;
@@ -231,15 +121,16 @@ client_main(int argc, char **argv, int flags)
* later in server) but it is necessary to get the start server * later in server) but it is necessary to get the start server
* flag. * flag.
*/ */
cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause); if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
if (cmdlist == NULL) { log_warnx("%s", cause);
fprintf(stderr, "%s\n", cause);
return (1); return (1);
} }
cmdflags &= ~CMD_STARTSERVER; cmdflags &= ~CMD_STARTSERVER;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
if (cmd->entry->flags & CMD_STARTSERVER) if (cmd->entry->flags & CMD_STARTSERVER)
cmdflags |= CMD_STARTSERVER; cmdflags |= CMD_STARTSERVER;
if (cmd->entry->flags & CMD_SENDENVIRON)
cmdflags |= CMD_SENDENVIRON;
if (cmd->entry->flags & CMD_CANTNEST) if (cmd->entry->flags & CMD_CANTNEST)
cmdflags |= CMD_CANTNEST; cmdflags |= CMD_CANTNEST;
} }
@@ -251,18 +142,16 @@ client_main(int argc, char **argv, int flags)
* if the socket path matches $TMUX, this is probably the same server. * if the socket path matches $TMUX, this is probably the same server.
*/ */
if (shell_cmd == NULL && environ_path != NULL && if (shell_cmd == NULL && environ_path != NULL &&
(cmdflags & CMD_CANTNEST) && cmdflags & CMD_CANTNEST && strcmp(socket_path, environ_path) == 0) {
strcmp(socket_path, environ_path) == 0) { log_warnx("sessions should be nested with care. "
fprintf(stderr, "sessions should be nested with care, " "unset $TMUX to force.");
"unset $TMUX to force\n");
return (1); return (1);
} }
/* Initialize the client socket and start the server. */ /* Initialise the client socket and start the server. */
fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER); fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER);
if (fd == -1) { if (fd == -1) {
fprintf(stderr, "failed to connect to server: %s\n", log_warn("failed to connect to server");
strerror(errno));
return (1); return (1);
} }
@@ -276,60 +165,29 @@ client_main(int argc, char **argv, int flags)
imsg_init(&client_ibuf, fd); imsg_init(&client_ibuf, fd);
event_set(&client_event, fd, EV_READ, client_callback, shell_cmd); event_set(&client_event, fd, EV_READ, client_callback, shell_cmd);
/* Create stdin handler. */
setblocking(STDIN_FILENO, 0);
event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
client_stdin_callback, NULL);
if (flags & CLIENT_CONTROLCONTROL) {
if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) {
fprintf(stderr, "tcgetattr failed: %s\n",
strerror(errno));
return (1);
}
cfmakeraw(&tio);
tio.c_iflag = ICRNL|IXANY;
tio.c_oflag = OPOST|ONLCR;
#ifdef NOKERNINFO
tio.c_lflag = NOKERNINFO;
#endif
tio.c_cflag = CREAD|CS8|HUPCL;
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;
cfsetispeed(&tio, cfgetispeed(&saved_tio));
cfsetospeed(&tio, cfgetospeed(&saved_tio));
tcsetattr(STDIN_FILENO, TCSANOW, &tio);
}
/* Establish signal handlers. */ /* Establish signal handlers. */
set_signals(client_signal); set_signals(client_signal);
/* Send identify messages. */ /* Send initial environment. */
if (cmdflags & CMD_SENDENVIRON)
client_send_environ();
client_send_identify(flags); client_send_identify(flags);
/* Send first command. */ /* Send first command. */
if (msg == MSG_COMMAND) { if (msg == MSG_COMMAND) {
/* How big is the command? */ /* Fill in command line arguments. */
size = 0; cmddata.pid = environ_pid;
for (i = 0; i < argc; i++) cmddata.idx = environ_idx;
size += strlen(argv[i]) + 1;
data = xmalloc((sizeof *data) + size);
/* Prepare command for server. */ /* Prepare command for server. */
data->argc = argc; cmddata.argc = argc;
if (cmd_pack_argv(argc, argv, (char *)(data + 1), size) != 0) { if (cmd_pack_argv(
fprintf(stderr, "command too long\n"); argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) {
free(data); log_warnx("command too long");
return (1); return (1);
} }
size += sizeof *data;
/* Send the command. */ client_write_server(msg, &cmddata, sizeof cmddata);
if (client_write_server(msg, data, size) != 0) {
fprintf(stderr, "failed to send command\n");
free(data);
return (1);
}
free(data);
} else if (msg == MSG_SHELL) } else if (msg == MSG_SHELL)
client_write_server(msg, NULL, 0); client_write_server(msg, NULL, 0);
@@ -339,81 +197,69 @@ client_main(int argc, char **argv, int flags)
/* Print the exit message, if any, and exit. */ /* Print the exit message, if any, and exit. */
if (client_attached) { if (client_attached) {
if (client_exitreason != CLIENT_EXIT_NONE && !login_shell) if (client_exitmsg != NULL && !login_shell)
printf("[%s]\n", client_exit_message()); printf("[%s]\n", client_exitmsg);
ppid = getppid(); ppid = getppid();
if (client_exittype == MSG_DETACHKILL && ppid > 1) if (client_exittype == MSG_DETACHKILL && ppid > 1)
kill(ppid, SIGHUP); kill(ppid, SIGHUP);
} else if (flags & CLIENT_CONTROLCONTROL) {
if (client_exitreason != CLIENT_EXIT_NONE)
printf("%%exit %s\n", client_exit_message());
else
printf("%%exit\n");
printf("\033\\");
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
} }
setblocking(STDIN_FILENO, 1);
return (client_exitval); return (client_exitval);
} }
/* Send identify messages to server. */ /* Send identify message to server with the file descriptors. */
void void
client_send_identify(int flags) client_send_identify(int flags)
{ {
const char *s; struct msg_identify_data data;
char **ss; char *term;
int fd; int fd;
client_write_one(MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags); data.flags = flags;
if ((s = getenv("TERM")) == NULL) if (getcwd(data.cwd, sizeof data.cwd) == NULL)
s = ""; *data.cwd = '\0';
client_write_one(MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
if ((s = ttyname(STDIN_FILENO)) == NULL) term = getenv("TERM");
s = ""; if (term == NULL ||
client_write_one(MSG_IDENTIFY_TTYNAME, -1, s, strlen(s) + 1); strlcpy(data.term, term, sizeof data.term) >= sizeof data.term)
*data.term = '\0';
if ((fd = open(".", O_RDONLY)) == -1)
fd = open("/", O_RDONLY);
client_write_one(MSG_IDENTIFY_CWD, fd, NULL, 0);
if ((fd = dup(STDIN_FILENO)) == -1) if ((fd = dup(STDIN_FILENO)) == -1)
fatal("dup failed"); fatal("dup failed");
client_write_one(MSG_IDENTIFY_STDIN, fd, NULL, 0); imsg_compose(&client_ibuf,
MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
for (ss = environ; *ss != NULL; ss++) if ((fd = dup(STDOUT_FILENO)) == -1)
client_write_one(MSG_IDENTIFY_ENVIRON, -1, *ss, strlen(*ss) + 1); fatal("dup failed");
imsg_compose(&client_ibuf,
MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0);
client_write_one(MSG_IDENTIFY_DONE, -1, NULL, 0); if ((fd = dup(STDERR_FILENO)) == -1)
fatal("dup failed");
client_update_event(); imsg_compose(&client_ibuf,
MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0);
} }
/* Helper to send one message. */ /* Forward entire environment to server. */
int void
client_write_one(enum msgtype type, int fd, const void *buf, size_t len) client_send_environ(void)
{ {
int retval; struct msg_environ_data data;
char **var;
retval = imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, fd, for (var = environ; *var != NULL; var++) {
(void *)buf, len); if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var)
if (retval != 1) continue;
return (-1); client_write_server(MSG_ENVIRON, &data, sizeof data);
return (0); }
} }
/* Write a message to the server without a file descriptor. */ /* Write a message to the server without a file descriptor. */
int void
client_write_server(enum msgtype type, const void *buf, size_t len) client_write_server(enum msgtype type, void *buf, size_t len)
{ {
int retval; imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
retval = client_write_one(type, -1, buf, len);
if (retval == 0)
client_update_event();
return (retval);
} }
/* Update client event based on whether it needs to read or read and write. */ /* Update client event based on whether it needs to read or read and write. */
@@ -432,26 +278,31 @@ client_update_event(void)
} }
/* Callback to handle signals in the client. */ /* Callback to handle signals in the client. */
/* ARGSUSED */
void void
client_signal(int sig, unused short events, unused void *data) client_signal(int sig, unused short events, unused void *data)
{ {
struct sigaction sigact; struct sigaction sigact;
int status; int status;
if (sig == SIGCHLD) if (!client_attached) {
waitpid(WAIT_ANY, &status, WNOHANG); switch (sig) {
else if (!client_attached) { case SIGCHLD:
if (sig == SIGTERM) waitpid(WAIT_ANY, &status, WNOHANG);
break;
case SIGTERM:
event_loopexit(NULL); event_loopexit(NULL);
break;
}
} else { } else {
switch (sig) { switch (sig) {
case SIGHUP: case SIGHUP:
client_exitreason = CLIENT_EXIT_LOST_TTY; client_exitmsg = "lost tty";
client_exitval = 1; client_exitval = 1;
client_write_server(MSG_EXITING, NULL, 0); client_write_server(MSG_EXITING, NULL, 0);
break; break;
case SIGTERM: case SIGTERM:
client_exitreason = CLIENT_EXIT_TERMINATED; client_exitmsg = "terminated";
client_exitval = 1; client_exitval = 1;
client_write_server(MSG_EXITING, NULL, 0); client_write_server(MSG_EXITING, NULL, 0);
break; break;
@@ -474,6 +325,7 @@ client_signal(int sig, unused short events, unused void *data)
} }
/* Callback for client imsg read events. */ /* Callback for client imsg read events. */
/* ARGSUSED */
void void
client_callback(unused int fd, short events, void *data) client_callback(unused int fd, short events, void *data)
{ {
@@ -494,7 +346,7 @@ client_callback(unused int fd, short events, void *data)
} }
if (events & EV_WRITE) { if (events & EV_WRITE) {
if (msgbuf_write(&client_ibuf.w) <= 0 && errno != EAGAIN) if (msgbuf_write(&client_ibuf.w) < 0)
goto lost_server; goto lost_server;
} }
@@ -502,74 +354,40 @@ client_callback(unused int fd, short events, void *data)
return; return;
lost_server: lost_server:
client_exitreason = CLIENT_EXIT_LOST_SERVER; client_exitmsg = "lost server";
client_exitval = 1; client_exitval = 1;
event_loopexit(NULL); event_loopexit(NULL);
} }
/* Callback for client stdin read events. */
void
client_stdin_callback(unused int fd, unused short events, unused void *data1)
{
struct msg_stdin_data data;
data.size = read(STDIN_FILENO, data.data, sizeof data.data);
if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
return;
client_write_server(MSG_STDIN, &data, sizeof data);
if (data.size <= 0)
event_del(&client_stdin);
client_update_event();
}
/* Force write to file descriptor. */
void
client_write(int fd, const char *data, size_t size)
{
ssize_t used;
while (size != 0) {
used = write(fd, data, size);
if (used == -1) {
if (errno == EINTR || errno == EAGAIN)
continue;
break;
}
data += used;
size -= used;
}
}
/* Dispatch imsgs when in wait state (before MSG_READY). */ /* Dispatch imsgs when in wait state (before MSG_READY). */
int int
client_dispatch_wait(void *data0) client_dispatch_wait(void *data)
{ {
struct imsg imsg; struct imsg imsg;
char *data; ssize_t n, datalen;
ssize_t n, datalen; struct msg_shell_data shelldata;
struct msg_stdout_data stdoutdata; struct msg_exit_data exitdata;
struct msg_stderr_data stderrdata; const char *shellcmd = data;
int retval;
if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
fatalx("imsg_read failed");
for (;;) { for (;;) {
if ((n = imsg_get(&client_ibuf, &imsg)) == -1) if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
fatalx("imsg_get failed"); fatalx("imsg_get failed");
if (n == 0) if (n == 0)
return (0); return (0);
data = imsg.data;
datalen = imsg.hdr.len - IMSG_HEADER_SIZE; datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
log_debug("got %d from server", imsg.hdr.type);
switch (imsg.hdr.type) { switch (imsg.hdr.type) {
case MSG_EXIT: case MSG_EXIT:
case MSG_SHUTDOWN: case MSG_SHUTDOWN:
if (datalen != sizeof retval && datalen != 0) if (datalen != sizeof exitdata) {
fatalx("bad MSG_EXIT size"); if (datalen != 0)
if (datalen == sizeof retval) { fatalx("bad MSG_EXIT size");
memcpy(&retval, data, sizeof retval); } else {
client_exitval = retval; memcpy(&exitdata, imsg.data, sizeof exitdata);
client_exitval = exitdata.retcode;
} }
imsg_free(&imsg); imsg_free(&imsg);
return (-1); return (-1);
@@ -577,57 +395,30 @@ client_dispatch_wait(void *data0)
if (datalen != 0) if (datalen != 0)
fatalx("bad MSG_READY size"); fatalx("bad MSG_READY size");
event_del(&client_stdin);
client_attached = 1; client_attached = 1;
client_write_server(MSG_RESIZE, NULL, 0);
break;
case MSG_STDIN:
if (datalen != 0)
fatalx("bad MSG_STDIN size");
event_add(&client_stdin, NULL);
break;
case MSG_STDOUT:
if (datalen != sizeof stdoutdata)
fatalx("bad MSG_STDOUT size");
memcpy(&stdoutdata, data, sizeof stdoutdata);
client_write(STDOUT_FILENO, stdoutdata.data,
stdoutdata.size);
break;
case MSG_STDERR:
if (datalen != sizeof stderrdata)
fatalx("bad MSG_STDERR size");
memcpy(&stderrdata, data, sizeof stderrdata);
client_write(STDERR_FILENO, stderrdata.data,
stderrdata.size);
break; break;
case MSG_VERSION: case MSG_VERSION:
if (datalen != 0) if (datalen != 0)
fatalx("bad MSG_VERSION size"); fatalx("bad MSG_VERSION size");
fprintf(stderr, "protocol version mismatch " log_warnx("protocol version mismatch (client %u, "
"(client %u, server %u)\n", PROTOCOL_VERSION, "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
imsg.hdr.peerid);
client_exitval = 1; client_exitval = 1;
imsg_free(&imsg); imsg_free(&imsg);
return (-1); return (-1);
case MSG_SHELL: case MSG_SHELL:
if (datalen == 0 || data[datalen - 1] != '\0') if (datalen != sizeof shelldata)
fatalx("bad MSG_SHELL string"); fatalx("bad MSG_SHELL size");
memcpy(&shelldata, imsg.data, sizeof shelldata);
shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
clear_signals(0); clear_signals(0);
shell_exec(data, data0);
shell_exec(shelldata.shell, shellcmd);
/* NOTREACHED */ /* NOTREACHED */
case MSG_DETACH: default:
case MSG_DETACHKILL: fatalx("unexpected message");
client_write_server(MSG_EXITING, NULL, 0);
break;
case MSG_EXITED:
imsg_free(&imsg);
return (-1);
} }
imsg_free(&imsg); imsg_free(&imsg);
@@ -635,44 +426,43 @@ client_dispatch_wait(void *data0)
} }
/* Dispatch imsgs in attached state (after MSG_READY). */ /* Dispatch imsgs in attached state (after MSG_READY). */
/* ARGSUSED */
int int
client_dispatch_attached(void) client_dispatch_attached(void)
{ {
struct imsg imsg; struct imsg imsg;
struct sigaction sigact; struct msg_lock_data lockdata;
char *data; struct sigaction sigact;
ssize_t n, datalen; ssize_t n, datalen;
for (;;) { for (;;) {
if ((n = imsg_get(&client_ibuf, &imsg)) == -1) if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
fatalx("imsg_get failed"); fatalx("imsg_get failed");
if (n == 0) if (n == 0)
return (0); return (0);
data = imsg.data;
datalen = imsg.hdr.len - IMSG_HEADER_SIZE; datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
log_debug("got %d from server", imsg.hdr.type); log_debug("client got %d", imsg.hdr.type);
switch (imsg.hdr.type) { switch (imsg.hdr.type) {
case MSG_DETACH:
case MSG_DETACHKILL: case MSG_DETACHKILL:
if (datalen == 0 || data[datalen - 1] != '\0') case MSG_DETACH:
fatalx("bad MSG_DETACH string"); if (datalen != 0)
fatalx("bad MSG_DETACH size");
client_exitsession = xstrdup(data);
client_exittype = imsg.hdr.type; client_exittype = imsg.hdr.type;
if (imsg.hdr.type == MSG_DETACHKILL) if (imsg.hdr.type == MSG_DETACHKILL)
client_exitreason = CLIENT_EXIT_DETACHED_HUP; client_exitmsg = "detached and SIGHUP";
else else
client_exitreason = CLIENT_EXIT_DETACHED; client_exitmsg = "detached";
client_write_server(MSG_EXITING, NULL, 0); client_write_server(MSG_EXITING, NULL, 0);
break; break;
case MSG_EXIT: case MSG_EXIT:
if (datalen != 0 && datalen != sizeof (int)) if (datalen != 0 &&
datalen != sizeof (struct msg_exit_data))
fatalx("bad MSG_EXIT size"); fatalx("bad MSG_EXIT size");
client_write_server(MSG_EXITING, NULL, 0); client_write_server(MSG_EXITING, NULL, 0);
client_exitreason = CLIENT_EXIT_EXITED; client_exitmsg = "exited";
break; break;
case MSG_EXITED: case MSG_EXITED:
if (datalen != 0) if (datalen != 0)
@@ -685,7 +475,7 @@ client_dispatch_attached(void)
fatalx("bad MSG_SHUTDOWN size"); fatalx("bad MSG_SHUTDOWN size");
client_write_server(MSG_EXITING, NULL, 0); client_write_server(MSG_EXITING, NULL, 0);
client_exitreason = CLIENT_EXIT_SERVER_EXITED; client_exitmsg = "server exited";
client_exitval = 1; client_exitval = 1;
break; break;
case MSG_SUSPEND: case MSG_SUSPEND:
@@ -701,12 +491,16 @@ client_dispatch_attached(void)
kill(getpid(), SIGTSTP); kill(getpid(), SIGTSTP);
break; break;
case MSG_LOCK: case MSG_LOCK:
if (datalen == 0 || data[datalen - 1] != '\0') if (datalen != sizeof lockdata)
fatalx("bad MSG_LOCK string"); fatalx("bad MSG_LOCK size");
memcpy(&lockdata, imsg.data, sizeof lockdata);
system(data); lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0';
system(lockdata.cmd);
client_write_server(MSG_UNLOCK, NULL, 0); client_write_server(MSG_UNLOCK, NULL, 0);
break; break;
default:
fatalx("unexpected message");
} }
imsg_free(&imsg); imsg_free(&imsg);

159
clock.c Normal file
View File

@@ -0,0 +1,159 @@
/* $Id$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
#include <time.h>
#include "tmux.h"
const char clock_table[14][5][5] = {
{ { 1,1,1,1,1 }, /* 0 */
{ 1,0,0,0,1 },
{ 1,0,0,0,1 },
{ 1,0,0,0,1 },
{ 1,1,1,1,1 } },
{ { 0,0,0,0,1 }, /* 1 */
{ 0,0,0,0,1 },
{ 0,0,0,0,1 },
{ 0,0,0,0,1 },
{ 0,0,0,0,1 } },
{ { 1,1,1,1,1 }, /* 2 */
{ 0,0,0,0,1 },
{ 1,1,1,1,1 },
{ 1,0,0,0,0 },
{ 1,1,1,1,1 } },
{ { 1,1,1,1,1 }, /* 3 */
{ 0,0,0,0,1 },
{ 1,1,1,1,1 },
{ 0,0,0,0,1 },
{ 1,1,1,1,1 } },
{ { 1,0,0,0,1 }, /* 4 */
{ 1,0,0,0,1 },
{ 1,1,1,1,1 },
{ 0,0,0,0,1 },
{ 0,0,0,0,1 } },
{ { 1,1,1,1,1 }, /* 5 */
{ 1,0,0,0,0 },
{ 1,1,1,1,1 },
{ 0,0,0,0,1 },
{ 1,1,1,1,1 } },
{ { 1,1,1,1,1 }, /* 6 */
{ 1,0,0,0,0 },
{ 1,1,1,1,1 },
{ 1,0,0,0,1 },
{ 1,1,1,1,1 } },
{ { 1,1,1,1,1 }, /* 7 */
{ 0,0,0,0,1 },
{ 0,0,0,0,1 },
{ 0,0,0,0,1 },
{ 0,0,0,0,1 } },
{ { 1,1,1,1,1 }, /* 8 */
{ 1,0,0,0,1 },
{ 1,1,1,1,1 },
{ 1,0,0,0,1 },
{ 1,1,1,1,1 } },
{ { 1,1,1,1,1 }, /* 9 */
{ 1,0,0,0,1 },
{ 1,1,1,1,1 },
{ 0,0,0,0,1 },
{ 1,1,1,1,1 } },
{ { 0,0,0,0,0 }, /* : */
{ 0,0,1,0,0 },
{ 0,0,0,0,0 },
{ 0,0,1,0,0 },
{ 0,0,0,0,0 } },
{ { 1,1,1,1,1 }, /* A */
{ 1,0,0,0,1 },
{ 1,1,1,1,1 },
{ 1,0,0,0,1 },
{ 1,0,0,0,1 } },
{ { 1,1,1,1,1 }, /* P */
{ 1,0,0,0,1 },
{ 1,1,1,1,1 },
{ 1,0,0,0,0 },
{ 1,0,0,0,0 } },
{ { 1,0,0,0,1 }, /* M */
{ 1,1,0,1,1 },
{ 1,0,1,0,1 },
{ 1,0,0,0,1 },
{ 1,0,0,0,1 } },
};
void
clock_draw(struct screen_write_ctx *ctx, int colour, int style)
{
struct screen *s = ctx->s;
struct grid_cell gc;
char tim[64], *ptr;
time_t t;
u_int i, j, x, y, idx;
t = time(NULL);
if (style == 0)
strftime(tim, sizeof tim, "%l:%M %p", localtime(&t));
else
strftime(tim, sizeof tim, "%H:%M", localtime(&t));
screen_write_clearscreen(ctx);
if (screen_size_x(s) < 6 * strlen(tim) || screen_size_y(s) < 6) {
if (screen_size_x(s) >= strlen(tim) && screen_size_y(s) != 0) {
x = (screen_size_x(s) / 2) - (strlen(tim) / 2);
y = screen_size_y(s) / 2;
screen_write_cursormove(ctx, x, y);
memcpy(&gc, &grid_default_cell, sizeof gc);
colour_set_fg(&gc, colour);
screen_write_puts(ctx, &gc, "%s", tim);
}
return;
}
x = (screen_size_x(s) / 2) - 3 * strlen(tim);
y = (screen_size_y(s) / 2) - 3;
memcpy(&gc, &grid_default_cell, sizeof gc);
colour_set_bg(&gc, colour);
for (ptr = tim; *ptr != '\0'; ptr++) {
if (*ptr >= '0' && *ptr <= '9')
idx = *ptr - '0';
else if (*ptr == ':')
idx = 10;
else if (*ptr == 'A')
idx = 11;
else if (*ptr == 'P')
idx = 12;
else if (*ptr == 'M')
idx = 13;
else {
x += 6;
continue;
}
for (j = 0; j < 5; j++) {
for (i = 0; i < 5; i++) {
screen_write_cursormove(ctx, x + i, y + j);
if (clock_table[idx][j][i])
screen_write_putc(ctx, &gc, ' ');
}
}
x += 6;
}
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,76 +18,47 @@
#include <sys/types.h> #include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Attach existing session to the current terminal. * Attach existing session to the current terminal.
*/ */
enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_q *); int cmd_attach_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_attach_session_entry = { const struct cmd_entry cmd_attach_session_entry = {
"attach-session", "attach", "attach-session", "attach",
"c:drt:", 0, 0, "drt:", 0, 0,
"[-dr] [-c working-directory] " CMD_TARGET_SESSION_USAGE, "[-dr] " CMD_TARGET_SESSION_USAGE,
CMD_CANTNEST|CMD_STARTSERVER, CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON,
NULL,
NULL,
cmd_attach_session_exec cmd_attach_session_exec
}; };
enum cmd_retval int
cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
const char *cflag)
{ {
struct session *s; struct args *args = self->args;
struct client *c; struct session *s;
struct winlink *wl = NULL; struct client *c;
struct window *w = NULL; const char *update;
struct window_pane *wp = NULL; char *overrides, *cause;
const char *update; u_int i;
char *cause;
u_int i;
int fd;
struct format_tree *ft;
char *cp;
if (RB_EMPTY(&sessions)) { if (RB_EMPTY(&sessions)) {
cmdq_error(cmdq, "no sessions"); ctx->error(ctx, "no sessions");
return (CMD_RETURN_ERROR); return (-1);
} }
if (tflag == NULL) { if ((s = cmd_find_session(ctx, args_get(args, 't'), 1)) == NULL)
if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) return (-1);
return (CMD_RETURN_ERROR);
} else if (tflag[strcspn(tflag, ":.")] != '\0') {
if ((wl = cmd_find_pane(cmdq, tflag, &s, &wp)) == NULL)
return (CMD_RETURN_ERROR);
} else {
if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL)
return (CMD_RETURN_ERROR);
w = cmd_lookup_windowid(tflag);
if (w == NULL && (wp = cmd_lookup_paneid(tflag)) != NULL)
w = wp->window;
if (w != NULL)
wl = winlink_find_by_window(&s->windows, w);
}
if (cmdq->client == NULL) if (ctx->cmdclient == NULL && ctx->curclient == NULL)
return (CMD_RETURN_NORMAL); return (0);
if (wl != NULL) { if (ctx->cmdclient == NULL) {
if (wp != NULL) if (args_has(self->args, 'd')) {
window_set_active_pane(wp->window, wp);
session_set_current(s, wl);
}
if (cmdq->client->session != NULL) {
if (dflag) {
/* /*
* Can't use server_write_session in case attaching to * Can't use server_write_session in case attaching to
* the same session as currently attached to. * the same session as currently attached to.
@@ -96,93 +67,46 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag,
c = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != s) if (c == NULL || c->session != s)
continue; continue;
if (c == cmdq->client) if (c == ctx->curclient)
continue; continue;
server_write_client(c, MSG_DETACH, server_write_client(c, MSG_DETACH, NULL, 0);
c->session->name,
strlen(c->session->name) + 1);
} }
} }
if (cflag != NULL) { ctx->curclient->session = s;
ft = format_create();
format_defaults(ft, cmd_find_client(cmdq, NULL, 1), s,
NULL, NULL);
cp = format_expand(ft, cflag);
format_free(ft);
fd = open(cp, O_RDONLY|O_DIRECTORY);
free(cp);
if (fd == -1) {
cmdq_error(cmdq, "bad working directory: %s",
strerror(errno));
return (CMD_RETURN_ERROR);
}
close(s->cwd);
s->cwd = fd;
}
cmdq->client->session = s;
notify_attached_session_changed(cmdq->client);
session_update_activity(s); session_update_activity(s);
server_redraw_client(cmdq->client); server_redraw_client(ctx->curclient);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
} else { } else {
if (server_client_open(cmdq->client, &cause) != 0) { if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) {
cmdq_error(cmdq, "open terminal failed: %s", cause); ctx->error(ctx, "not a terminal");
free(cause); return (-1);
return (CMD_RETURN_ERROR);
} }
if (cflag != NULL) { overrides =
ft = format_create(); options_get_string(&s->options, "terminal-overrides");
format_defaults(ft, cmd_find_client(cmdq, NULL, 1), s, if (tty_open(&ctx->cmdclient->tty, overrides, &cause) != 0) {
NULL, NULL); ctx->error(ctx, "terminal open failed: %s", cause);
cp = format_expand(ft, cflag); xfree(cause);
format_free(ft); return (-1);
fd = open(cp, O_RDONLY|O_DIRECTORY);
free(cp);
if (fd == -1) {
cmdq_error(cmdq, "bad working directory: %s",
strerror(errno));
return (CMD_RETURN_ERROR);
}
close(s->cwd);
s->cwd = fd;
} }
if (rflag) if (args_has(self->args, 'r'))
cmdq->client->flags |= CLIENT_READONLY; ctx->cmdclient->flags |= CLIENT_READONLY;
if (dflag) { if (args_has(self->args, 'd'))
server_write_session(s, MSG_DETACH, s->name, server_write_session(s, MSG_DETACH, NULL, 0);
strlen(s->name) + 1);
} ctx->cmdclient->session = s;
session_update_activity(s);
server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
update = options_get_string(&s->options, "update-environment"); update = options_get_string(&s->options, "update-environment");
environ_update(update, &cmdq->client->environ, &s->environ); environ_update(update, &ctx->cmdclient->environ, &s->environ);
cmdq->client->session = s; server_redraw_client(ctx->cmdclient);
notify_attached_session_changed(cmdq->client);
session_update_activity(s);
server_redraw_client(cmdq->client);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
server_write_ready(cmdq->client);
cmdq->client_exit = 0;
} }
recalculate_sizes(); recalculate_sizes();
server_update_socket(); server_update_socket();
return (CMD_RETURN_NORMAL); return (1); /* 1 means don't tell command client to exit */
}
enum cmd_retval
cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
return (cmd_attach_session(cmdq, args_get(args, 't'),
args_has(args, 'd'), args_has(args, 'r'), args_get(args, 'c')));
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -27,106 +26,95 @@
* Bind a key to a command, this recurses through cmd_*. * Bind a key to a command, this recurses through cmd_*.
*/ */
enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmd_q *); int cmd_bind_key_check(struct args *);
int cmd_bind_key_exec(struct cmd *, struct cmd_ctx *);
enum cmd_retval cmd_bind_key_mode_table(struct cmd *, struct cmd_q *, int); int cmd_bind_key_table(struct cmd *, struct cmd_ctx *, int);
const struct cmd_entry cmd_bind_key_entry = { const struct cmd_entry cmd_bind_key_entry = {
"bind-key", "bind", "bind-key", "bind",
"cnrt:", 1, -1, "cnrt:", 1, -1,
"[-cnr] [-t mode-table] key command [arguments]", "[-cnr] [-t key-table] key command [arguments]",
0, 0,
NULL,
cmd_bind_key_check,
cmd_bind_key_exec cmd_bind_key_exec
}; };
enum cmd_retval int
cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq) cmd_bind_key_check(struct args *args)
{
if (args_has(args, 't')) {
if (args->argc != 2)
return (-1);
} else {
if (args->argc < 2)
return (-1);
}
return (0);
}
int
cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
char *cause; char *cause;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
int key; int key;
if (args_has(args, 't')) {
if (args->argc != 2 && args->argc != 3) {
cmdq_error(cmdq, "not enough arguments");
return (CMD_RETURN_ERROR);
}
} else {
if (args->argc < 2) {
cmdq_error(cmdq, "not enough arguments");
return (CMD_RETURN_ERROR);
}
}
key = key_string_lookup_string(args->argv[0]); key = key_string_lookup_string(args->argv[0]);
if (key == KEYC_NONE) { if (key == KEYC_NONE) {
cmdq_error(cmdq, "unknown key: %s", args->argv[0]); ctx->error(ctx, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR); return (-1);
} }
if (args_has(args, 't')) if (args_has(args, 't'))
return (cmd_bind_key_mode_table(self, cmdq, key)); return (cmd_bind_key_table(self, ctx, key));
cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0, cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, &cause);
&cause);
if (cmdlist == NULL) { if (cmdlist == NULL) {
cmdq_error(cmdq, "%s", cause); ctx->error(ctx, "%s", cause);
free(cause); xfree(cause);
return (CMD_RETURN_ERROR); return (-1);
} }
if (!args_has(args, 'n')) if (!args_has(args, 'n'))
key |= KEYC_PREFIX; key |= KEYC_PREFIX;
key_bindings_add(key, args_has(args, 'r'), cmdlist); key_bindings_add(key, args_has(args, 'r'), cmdlist);
return (CMD_RETURN_NORMAL); return (0);
} }
enum cmd_retval int
cmd_bind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, int key) cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
{ {
struct args *args = self->args; struct args *args = self->args;
const char *tablename; const char *tablename;
const struct mode_key_table *mtab; const struct mode_key_table *mtab;
struct mode_key_binding *mbind, mtmp; struct mode_key_binding *mbind, mtmp;
enum mode_key_cmd cmd; enum mode_key_cmd cmd;
const char *arg;
tablename = args_get(args, 't'); tablename = args_get(args, 't');
if ((mtab = mode_key_findtable(tablename)) == NULL) { if ((mtab = mode_key_findtable(tablename)) == NULL) {
cmdq_error(cmdq, "unknown key table: %s", tablename); ctx->error(ctx, "unknown key table: %s", tablename);
return (CMD_RETURN_ERROR); return (-1);
} }
cmd = mode_key_fromstring(mtab->cmdstr, args->argv[1]); cmd = mode_key_fromstring(mtab->cmdstr, args->argv[1]);
if (cmd == MODEKEY_NONE) { if (cmd == MODEKEY_NONE) {
cmdq_error(cmdq, "unknown command: %s", args->argv[1]); ctx->error(ctx, "unknown command: %s", args->argv[1]);
return (CMD_RETURN_ERROR); return (-1);
}
if (cmd != MODEKEYCOPY_COPYPIPE) {
if (args->argc != 2) {
cmdq_error(cmdq, "no argument allowed");
return (CMD_RETURN_ERROR);
}
arg = NULL;
} else {
if (args->argc != 3) {
cmdq_error(cmdq, "no argument given");
return (CMD_RETURN_ERROR);
}
arg = args->argv[2];
} }
mtmp.key = key; mtmp.key = key;
mtmp.mode = !!args_has(args, 'c'); mtmp.mode = !!args_has(args, 'c');
if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) == NULL) { if ((mbind = SPLAY_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) {
mbind = xmalloc(sizeof *mbind); mbind->cmd = cmd;
mbind->key = mtmp.key; return (0);
mbind->mode = mtmp.mode;
RB_INSERT(mode_key_tree, mtab->tree, mbind);
} }
mbind = xmalloc(sizeof *mbind);
mbind->key = mtmp.key;
mbind->mode = mtmp.mode;
mbind->cmd = cmd; mbind->cmd = cmd;
mbind->arg = arg != NULL ? xstrdup(arg) : NULL; SPLAY_INSERT(mode_key_tree, mtab->tree, mbind);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,55 +26,56 @@
* Break pane off into a window. * Break pane off into a window.
*/ */
#define BREAK_PANE_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" int cmd_break_pane_exec(struct cmd *, struct cmd_ctx *);
enum cmd_retval cmd_break_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_break_pane_entry = { const struct cmd_entry cmd_break_pane_entry = {
"break-pane", "breakp", "break-pane", "breakp",
"dPF:t:", 0, 0, "dt:", 0, 0,
"[-dP] [-F format] " CMD_TARGET_PANE_USAGE, "[-d] " CMD_TARGET_PANE_USAGE,
0, 0,
NULL,
NULL,
cmd_break_pane_exec cmd_break_pane_exec
}; };
enum cmd_retval int
cmd_break_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl;
struct session *s; struct session *s;
struct window_pane *wp; struct window_pane *wp;
struct window *w; struct window *w;
char *name;
char *cause; char *cause;
int base_idx; int base_idx;
struct format_tree *ft;
const char *template;
char *cp;
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL) if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
if (window_count_panes(wl->window) == 1) { if (window_count_panes(wl->window) == 1) {
cmdq_error(cmdq, "can't break with only one pane"); ctx->error(ctx, "can't break with only one pane");
return (CMD_RETURN_ERROR); return (-1);
} }
w = wl->window; w = wl->window;
server_unzoom_window(w);
TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_REMOVE(&w->panes, wp, entry);
window_lost_pane(w, wp); if (wp == w->active) {
w->active = w->last;
w->last = NULL;
if (w->active == NULL) {
w->active = TAILQ_PREV(wp, window_panes, entry);
if (w->active == NULL)
w->active = TAILQ_NEXT(wp, entry);
}
} else if (wp == w->last)
w->last = NULL;
layout_close_pane(wp); layout_close_pane(wp);
w = wp->window = window_create1(s->sx, s->sy); w = wp->window = window_create1(s->sx, s->sy);
TAILQ_INSERT_HEAD(&w->panes, wp, entry); TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp; w->active = wp;
name = default_window_name(w); w->name = default_window_name(w);
window_set_name(w, name); layout_init(w);
free(name);
layout_init(w, wp);
base_idx = options_get_number(&s->options, "base-index"); base_idx = options_get_number(&s->options, "base-index");
wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */ wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */
@@ -84,18 +85,5 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_q *cmdq)
server_redraw_session(s); server_redraw_session(s);
server_status_session_group(s); server_status_session_group(s);
if (args_has(args, 'P')) { return (0);
if ((template = args_get(args, 'F')) == NULL)
template = BREAK_PANE_TEMPLATE;
ft = format_create();
format_defaults(ft, cmd_find_client(cmdq, NULL, 1), s, wl, wp);
cp = format_expand(ft, template);
cmdq_print(cmdq, "%s", cp);
free(cp);
format_free(ft);
}
return (CMD_RETURN_NORMAL);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Jonathan Alvarado <radobobo@users.sourceforge.net> * Copyright (c) 2009 Jonathan Alvarado <radobobo@users.sourceforge.net>
@@ -24,122 +24,62 @@
#include "tmux.h" #include "tmux.h"
/* /*
* Write the entire contents of a pane to a buffer or stdout. * Write the entire contents of a pane to a buffer.
*/ */
enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmd_q *); int cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *);
char *cmd_capture_pane_append(char *, size_t *, char *, size_t);
char *cmd_capture_pane_pending(struct args *, struct window_pane *,
size_t *);
char *cmd_capture_pane_history(struct args *, struct cmd_q *,
struct window_pane *, size_t *);
const struct cmd_entry cmd_capture_pane_entry = { const struct cmd_entry cmd_capture_pane_entry = {
"capture-pane", "capturep", "capture-pane", "capturep",
"ab:CeE:JpPqS:t:", 0, 0, "b:E:S:t:", 0, 0,
"[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] [-S start-line]" "[-b buffer-index] [-E end-line] [-S start-line] [-t target-pane]",
CMD_TARGET_PANE_USAGE,
0, 0,
NULL,
NULL,
cmd_capture_pane_exec cmd_capture_pane_exec
}; };
char * int
cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen) cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
buf = xrealloc(buf, *len + linelen + 1);
memcpy(buf + *len, line, linelen);
*len += linelen;
return (buf);
}
char *
cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
size_t *len)
{
char *buf, *line, tmp[5];
size_t linelen;
u_int i;
if (wp->ictx.since_ground == NULL)
return (xstrdup(""));
line = EVBUFFER_DATA(wp->ictx.since_ground);
linelen = EVBUFFER_LENGTH(wp->ictx.since_ground);
buf = xstrdup("");
if (args_has(args, 'C')) {
for (i = 0; i < linelen; i++) {
if (line[i] >= ' ') {
tmp[0] = line[i];
tmp[1] = '\0';
} else
xsnprintf(tmp, sizeof tmp, "\\%03o", line[i]);
buf = cmd_capture_pane_append(buf, len, tmp,
strlen(tmp));
}
} else
buf = cmd_capture_pane_append(buf, len, line, linelen);
return (buf);
}
char *
cmd_capture_pane_history(struct args *args, struct cmd_q *cmdq,
struct window_pane *wp, size_t *len)
{ {
struct args *args = self->args;
struct window_pane *wp;
char *buf, *line, *cause;
struct screen *s;
struct grid *gd; struct grid *gd;
const struct grid_line *gl; int buffer, n;
struct grid_cell *gc = NULL; u_int i, limit, top, bottom, tmp;
int n, with_codes, escape_c0, join_lines; size_t len, linelen;
u_int i, sx, top, bottom, tmp;
char *cause, *buf, *line;
const char *Sflag, *Eflag;
size_t linelen;
sx = screen_size_x(&wp->base); if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
if (args_has(args, 'a')) { return (-1);
gd = wp->saved_grid; s = &wp->base;
if (gd == NULL) { gd = s->grid;
if (!args_has(args, 'q')) {
cmdq_error(cmdq, "no alternate screen");
return (NULL);
}
return (xstrdup(""));
}
} else
gd = wp->base.grid;
Sflag = args_get(args, 'S'); buf = NULL;
if (Sflag != NULL && strcmp(Sflag, "-") == 0) len = 0;
n = args_strtonum(args, 'S', SHRT_MIN, SHRT_MAX, &cause);
if (cause != NULL) {
top = gd->hsize;
xfree(cause);
} else if (n < 0 && (u_int) -n > gd->hsize)
top = 0; top = 0;
else { else
n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause); top = gd->hsize + n;
if (cause != NULL) { if (top > gd->hsize + gd->sy - 1)
top = gd->hsize; top = gd->hsize + gd->sy - 1;
free(cause);
} else if (n < 0 && (u_int) -n > gd->hsize)
top = 0;
else
top = gd->hsize + n;
if (top > gd->hsize + gd->sy - 1)
top = gd->hsize + gd->sy - 1;
}
Eflag = args_get(args, 'E'); n = args_strtonum(args, 'E', SHRT_MIN, SHRT_MAX, &cause);
if (Eflag != NULL && strcmp(Eflag, "-") == 0) if (cause != NULL) {
bottom = gd->hsize + gd->sy - 1;
xfree(cause);
} else if (n < 0 && (u_int) -n > gd->hsize)
bottom = 0;
else
bottom = gd->hsize + n;
if (bottom > gd->hsize + gd->sy - 1)
bottom = gd->hsize + gd->sy - 1; bottom = gd->hsize + gd->sy - 1;
else {
n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause);
if (cause != NULL) {
bottom = gd->hsize + gd->sy - 1;
free(cause);
} else if (n < 0 && (u_int) -n > gd->hsize)
bottom = 0;
else
bottom = gd->hsize + n;
if (bottom > gd->hsize + gd->sy - 1)
bottom = gd->hsize + gd->sy - 1;
}
if (bottom < top) { if (bottom < top) {
tmp = bottom; tmp = bottom;
@@ -147,72 +87,37 @@ cmd_capture_pane_history(struct args *args, struct cmd_q *cmdq,
top = tmp; top = tmp;
} }
with_codes = args_has(args, 'e');
escape_c0 = args_has(args, 'C');
join_lines = args_has(args, 'J');
buf = NULL;
for (i = top; i <= bottom; i++) { for (i = top; i <= bottom; i++) {
line = grid_string_cells(gd, 0, i, sx, &gc, with_codes, line = grid_string_cells(s->grid, 0, i, screen_size_x(s));
escape_c0, !join_lines); linelen = strlen(line);
linelen = strlen(line);
buf = cmd_capture_pane_append(buf, len, line, linelen); buf = xrealloc(buf, 1, len + linelen + 1);
memcpy(buf + len, line, linelen);
len += linelen;
buf[len++] = '\n';
gl = grid_peek_line(gd, i); xfree(line);
if (!join_lines || !(gl->flags & GRID_LINE_WRAPPED))
buf[(*len)++] = '\n';
free(line);
}
return (buf);
}
enum cmd_retval
cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c;
struct window_pane *wp;
char *buf, *cause;
const char *bufname;
size_t len;
if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
return (CMD_RETURN_ERROR);
len = 0;
if (args_has(args, 'P'))
buf = cmd_capture_pane_pending(args, wp, &len);
else
buf = cmd_capture_pane_history(args, cmdq, wp, &len);
if (buf == NULL)
return (CMD_RETURN_ERROR);
if (args_has(args, 'p')) {
c = cmdq->client;
if (c == NULL ||
(c->session != NULL && !(c->flags & CLIENT_CONTROL))) {
cmdq_error(cmdq, "can't write to stdout");
return (CMD_RETURN_ERROR);
}
evbuffer_add(c->stdout_data, buf, len);
if (args_has(args, 'P') && len > 0)
evbuffer_add(c->stdout_data, "\n", 1);
server_push_stdout(c);
} else {
bufname = NULL;
if (args_has(args, 'b'))
bufname = args_get(args, 'b');
if (paste_set(buf, len, bufname, &cause) != 0) {
cmdq_error(cmdq, "%s", cause);
free(buf);
free(cause);
return (CMD_RETURN_ERROR);
}
} }
return (CMD_RETURN_NORMAL); limit = options_get_number(&global_options, "buffer-limit");
if (!args_has(args, 'b')) {
paste_add(&global_buffers, buf, len, limit);
return (0);
}
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
ctx->error(ctx, "buffer %s", cause);
xfree(cause);
return (-1);
}
if (paste_replace(&global_buffers, buffer, buf, len) != 0) {
ctx->error(ctx, "no buffer %d", buffer);
xfree(buf);
return (-1);
}
return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -19,7 +19,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h> #include <ctype.h>
#include <stdlib.h>
#include "tmux.h" #include "tmux.h"
@@ -27,74 +26,118 @@
* Enter choice mode to choose a buffer. * Enter choice mode to choose a buffer.
*/ */
#define CHOOSE_BUFFER_TEMPLATE \ int cmd_choose_buffer_exec(struct cmd *, struct cmd_ctx *);
"#{buffer_name}: #{buffer_size} bytes: #{buffer_sample}"
enum cmd_retval cmd_choose_buffer_exec(struct cmd *, struct cmd_q *); void cmd_choose_buffer_callback(void *, int);
void cmd_choose_buffer_free(void *);
const struct cmd_entry cmd_choose_buffer_entry = { const struct cmd_entry cmd_choose_buffer_entry = {
"choose-buffer", NULL, "choose-buffer", NULL,
"F:t:", 0, 1, "t:", 0, 1,
CMD_TARGET_WINDOW_USAGE " [-F format] [template]", CMD_TARGET_WINDOW_USAGE " [template]",
0, 0,
NULL,
NULL,
cmd_choose_buffer_exec cmd_choose_buffer_exec
}; };
enum cmd_retval struct cmd_choose_buffer_data {
cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq) struct client *client;
char *template;
};
int
cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct cmd_choose_buffer_data *cdata;
struct window_choose_data *cdata;
struct winlink *wl; struct winlink *wl;
struct paste_buffer *pb; struct paste_buffer *pb;
char *action, *action_data;
const char *template;
u_int idx; u_int idx;
int utf8flag; char *tmp;
if ((c = cmd_current_client(cmdq)) == NULL) { if (ctx->curclient == NULL) {
cmdq_error(cmdq, "no client available"); ctx->error(ctx, "must be run interactively");
return (CMD_RETURN_ERROR); return (-1);
} }
if ((template = args_get(args, 'F')) == NULL) if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
template = CHOOSE_BUFFER_TEMPLATE; return (-1);
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) if (paste_get_top(&global_buffers) == NULL)
return (CMD_RETURN_ERROR); return (0);
utf8flag = options_get_number(&wl->window->options, "utf8");
if (paste_get_top() == NULL)
return (CMD_RETURN_NORMAL);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (CMD_RETURN_NORMAL); return (0);
if (args->argc != 0)
action = xstrdup(args->argv[0]);
else
action = xstrdup("paste-buffer -b '%%'");
idx = 0; idx = 0;
pb = NULL; while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) {
while ((pb = paste_walk(pb)) != NULL) { tmp = paste_print(pb, 50);
cdata = window_choose_data_create(TREE_OTHER, c, c->session); window_choose_add(wl->window->active, idx - 1,
cdata->idx = idx; "%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp);
xfree(tmp);
cdata->ft_template = xstrdup(template);
format_defaults_paste_buffer(cdata->ft, pb, utf8flag);
xasprintf(&action_data, "%s", pb->name);
cdata->command = cmd_template_replace(action, action_data, 1);
free(action_data);
window_choose_add(wl->window->active, cdata);
idx++;
} }
free(action);
window_choose_ready(wl->window->active, 0, NULL); cdata = xmalloc(sizeof *cdata);
if (args->argc != 0)
cdata->template = xstrdup(args->argv[0]);
else
cdata->template = xstrdup("paste-buffer -b '%%'");
cdata->client = ctx->curclient;
cdata->client->references++;
return (CMD_RETURN_NORMAL); window_choose_ready(wl->window->active,
0, cmd_choose_buffer_callback, cmd_choose_buffer_free, cdata);
return (0);
}
void
cmd_choose_buffer_callback(void *data, int idx)
{
struct cmd_choose_buffer_data *cdata = data;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *template, *cause, tmp[16];
if (idx == -1)
return;
if (cdata->client->flags & CLIENT_DEAD)
return;
xsnprintf(tmp, sizeof tmp, "%u", idx);
template = cmd_template_replace(cdata->template, tmp, 1);
if (cmd_string_parse(template, &cmdlist, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(cdata->client, "%s", cause);
xfree(cause);
}
xfree(template);
return;
}
xfree(template);
ctx.msgdata = NULL;
ctx.curclient = cdata->client;
ctx.error = key_bindings_error;
ctx.print = key_bindings_print;
ctx.info = key_bindings_info;
ctx.cmdclient = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist);
}
void
cmd_choose_buffer_free(void *data)
{
struct cmd_choose_buffer_data *cdata = data;
cdata->client->references--;
xfree(cdata->template);
xfree(cdata);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -19,7 +19,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h> #include <ctype.h>
#include <stdlib.h>
#include "tmux.h" #include "tmux.h"
@@ -27,102 +26,126 @@
* Enter choice mode to choose a client. * Enter choice mode to choose a client.
*/ */
#define CHOOSE_CLIENT_TEMPLATE \ int cmd_choose_client_exec(struct cmd *, struct cmd_ctx *);
"#{client_tty}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}]" \
"#{?client_utf8, (utf8),}#{?client_readonly, (ro),} " \
"(last used #{client_activity_string})"
enum cmd_retval cmd_choose_client_exec(struct cmd *, struct cmd_q *); void cmd_choose_client_callback(void *, int);
void cmd_choose_client_free(void *);
void cmd_choose_client_callback(struct window_choose_data *);
const struct cmd_entry cmd_choose_client_entry = { const struct cmd_entry cmd_choose_client_entry = {
"choose-client", NULL, "choose-client", NULL,
"F:t:", 0, 1, "t:", 0, 1,
CMD_TARGET_WINDOW_USAGE " [-F format] [template]", CMD_TARGET_WINDOW_USAGE " [template]",
0, 0,
NULL,
NULL,
cmd_choose_client_exec cmd_choose_client_exec
}; };
struct cmd_choose_client_data { struct cmd_choose_client_data {
struct client *client; struct client *client;
char *template;
}; };
enum cmd_retval int
cmd_choose_client_exec(struct cmd *self, struct cmd_q *cmdq) cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct cmd_choose_client_data *cdata;
struct client *c1;
struct window_choose_data *cdata;
struct winlink *wl; struct winlink *wl;
const char *template; struct client *c;
char *action;
u_int i, idx, cur; u_int i, idx, cur;
if ((c = cmd_current_client(cmdq)) == NULL) { if (ctx->curclient == NULL) {
cmdq_error(cmdq, "no client available"); ctx->error(ctx, "must be run interactively");
return (CMD_RETURN_ERROR); return (-1);
} }
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (CMD_RETURN_NORMAL); return (0);
if ((template = args_get(args, 'F')) == NULL)
template = CHOOSE_CLIENT_TEMPLATE;
if (args->argc != 0)
action = xstrdup(args->argv[0]);
else
action = xstrdup("detach-client -t '%%'");
cur = idx = 0; cur = idx = 0;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c1 = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);
if (c1 == NULL || c1->session == NULL || c1->tty.path == NULL) if (c == NULL || c->session == NULL)
continue; continue;
if (c1 == cmdq->client) if (c == ctx->curclient)
cur = idx; cur = idx;
idx++; idx++;
cdata = window_choose_data_create(TREE_OTHER, c, c->session); window_choose_add(wl->window->active, i,
cdata->idx = i; "%s: %s [%ux%u %s]%s", c->tty.path,
c->session->name, c->tty.sx, c->tty.sy,
cdata->ft_template = xstrdup(template); c->tty.termname, c->tty.flags & TTY_UTF8 ? " (utf8)" : "");
format_add(cdata->ft, "line", "%u", i);
format_defaults(cdata->ft, c1, NULL, NULL, NULL);
cdata->command = cmd_template_replace(action, c1->tty.path, 1);
window_choose_add(wl->window->active, cdata);
} }
free(action);
window_choose_ready(wl->window->active, cur, cdata = xmalloc(sizeof *cdata);
cmd_choose_client_callback); if (args->argc != 0)
cdata->template = xstrdup(args->argv[0]);
else
cdata->template = xstrdup("detach-client -t '%%'");
cdata->client = ctx->curclient;
cdata->client->references++;
return (CMD_RETURN_NORMAL); window_choose_ready(wl->window->active,
cur, cmd_choose_client_callback, cmd_choose_client_free, cdata);
return (0);
} }
void void
cmd_choose_client_callback(struct window_choose_data *cdata) cmd_choose_client_callback(void *data, int idx)
{ {
struct client *c; struct cmd_choose_client_data *cdata = data;
struct client *c;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *template, *cause;
if (cdata == NULL) if (idx == -1)
return; return;
if (cdata->start_client->flags & CLIENT_DEAD) if (cdata->client->flags & CLIENT_DEAD)
return; return;
if (cdata->idx > ARRAY_LENGTH(&clients) - 1) if ((u_int) idx > ARRAY_LENGTH(&clients) - 1)
return; return;
c = ARRAY_ITEM(&clients, cdata->idx); c = ARRAY_ITEM(&clients, idx);
if (c == NULL || c->session == NULL) if (c == NULL || c->session == NULL)
return; return;
template = cmd_template_replace(cdata->template, c->tty.path, 1);
window_choose_data_run(cdata); if (cmd_string_parse(template, &cmdlist, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(c, "%s", cause);
xfree(cause);
}
xfree(template);
return;
}
xfree(template);
ctx.msgdata = NULL;
ctx.curclient = cdata->client;
ctx.error = key_bindings_error;
ctx.print = key_bindings_print;
ctx.info = key_bindings_info;
ctx.cmdclient = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist);
}
void
cmd_choose_client_free(void *data)
{
struct cmd_choose_client_data *cdata = data;
cdata->client->references--;
xfree(cdata->template);
xfree(cdata);
} }

156
cmd-choose-session.c Normal file
View File

@@ -0,0 +1,156 @@
/* $Id$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include "tmux.h"
/*
* Enter choice mode to choose a session.
*/
int cmd_choose_session_exec(struct cmd *, struct cmd_ctx *);
void cmd_choose_session_callback(void *, int);
void cmd_choose_session_free(void *);
const struct cmd_entry cmd_choose_session_entry = {
"choose-session", NULL,
"t:", 0, 1,
CMD_TARGET_WINDOW_USAGE " [template]",
0,
NULL,
NULL,
cmd_choose_session_exec
};
struct cmd_choose_session_data {
struct client *client;
char *template;
};
int
cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_choose_session_data *cdata;
struct winlink *wl;
struct session *s;
struct session_group *sg;
u_int idx, sgidx, cur;
char tmp[64];
if (ctx->curclient == NULL) {
ctx->error(ctx, "must be run interactively");
return (-1);
}
if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
return (-1);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (0);
cur = idx = 0;
RB_FOREACH(s, sessions, &sessions) {
if (s == ctx->curclient->session)
cur = idx;
idx++;
sg = session_group_find(s);
if (sg == NULL)
*tmp = '\0';
else {
sgidx = session_group_index(sg);
xsnprintf(tmp, sizeof tmp, " (group %u)", sgidx);
}
window_choose_add(wl->window->active, s->idx,
"%s: %u windows [%ux%u]%s%s", s->name,
winlink_count(&s->windows), s->sx, s->sy,
tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)");
}
cdata = xmalloc(sizeof *cdata);
if (args->argc != 0)
cdata->template = xstrdup(args->argv[0]);
else
cdata->template = xstrdup("switch-client -t '%%'");
cdata->client = ctx->curclient;
cdata->client->references++;
window_choose_ready(wl->window->active,
cur, cmd_choose_session_callback, cmd_choose_session_free, cdata);
return (0);
}
void
cmd_choose_session_callback(void *data, int idx)
{
struct cmd_choose_session_data *cdata = data;
struct session *s;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *template, *cause;
if (idx == -1)
return;
if (cdata->client->flags & CLIENT_DEAD)
return;
s = session_find_by_index(idx);
if (s == NULL)
return;
template = cmd_template_replace(cdata->template, s->name, 1);
if (cmd_string_parse(template, &cmdlist, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(cdata->client, "%s", cause);
xfree(cause);
}
xfree(template);
return;
}
xfree(template);
ctx.msgdata = NULL;
ctx.curclient = cdata->client;
ctx.error = key_bindings_error;
ctx.print = key_bindings_print;
ctx.info = key_bindings_info;
ctx.cmdclient = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist);
}
void
cmd_choose_session_free(void *data)
{
struct cmd_choose_session_data *cdata = data;
cdata->client->references--;
xfree(cdata->template);
xfree(cdata);
}

View File

@@ -1,241 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
#define CMD_CHOOSE_TREE_WINDOW_ACTION "select-window -t '%%'"
#define CMD_CHOOSE_TREE_SESSION_ACTION "switch-client -t '%%'"
/*
* Enter choice mode to choose a session and/or window.
*/
#define CHOOSE_TREE_SESSION_TEMPLATE \
"#{session_name}: #{session_windows} windows" \
"#{?session_grouped, (group ,}" \
"#{session_group}#{?session_grouped,),}" \
"#{?session_attached, (attached),}"
#define CHOOSE_TREE_WINDOW_TEMPLATE \
"#{window_index}: #{window_name}#{window_flags} " \
"\"#{pane_title}\""
enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_choose_tree_entry = {
"choose-tree", NULL,
"S:W:swub:c:t:", 0, 1,
"[-suw] [-b session-template] [-c window template] [-S format] " \
"[-W format] " CMD_TARGET_WINDOW_USAGE,
0,
cmd_choose_tree_exec
};
const struct cmd_entry cmd_choose_session_entry = {
"choose-session", NULL,
"F:t:", 0, 1,
CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
0,
cmd_choose_tree_exec
};
const struct cmd_entry cmd_choose_window_entry = {
"choose-window", NULL,
"F:t:", 0, 1,
CMD_TARGET_WINDOW_USAGE "[-F format] [template]",
0,
cmd_choose_tree_exec
};
enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl, *wm;
struct session *s, *s2;
struct client *c;
struct window_choose_data *wcd = NULL;
const char *ses_template, *win_template;
char *final_win_action, *cur_win_template;
char *final_win_template_middle;
char *final_win_template_last;
const char *ses_action, *win_action;
u_int cur_win, idx_ses, win_ses, win_max;
u_int wflag, sflag;
ses_template = win_template = NULL;
ses_action = win_action = NULL;
if ((c = cmd_current_client(cmdq)) == NULL) {
cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL)
return (CMD_RETURN_ERROR);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (CMD_RETURN_NORMAL);
/* Sort out which command this is. */
wflag = sflag = 0;
if (self->entry == &cmd_choose_session_entry) {
sflag = 1;
if ((ses_template = args_get(args, 'F')) == NULL)
ses_template = CHOOSE_TREE_SESSION_TEMPLATE;
if (args->argc != 0)
ses_action = args->argv[0];
else
ses_action = CMD_CHOOSE_TREE_SESSION_ACTION;
} else if (self->entry == &cmd_choose_window_entry) {
wflag = 1;
if ((win_template = args_get(args, 'F')) == NULL)
win_template = CHOOSE_TREE_WINDOW_TEMPLATE;
if (args->argc != 0)
win_action = args->argv[0];
else
win_action = CMD_CHOOSE_TREE_WINDOW_ACTION;
} else {
wflag = args_has(args, 'w');
sflag = args_has(args, 's');
if ((ses_action = args_get(args, 'b')) == NULL)
ses_action = CMD_CHOOSE_TREE_SESSION_ACTION;
if ((win_action = args_get(args, 'c')) == NULL)
win_action = CMD_CHOOSE_TREE_WINDOW_ACTION;
if ((ses_template = args_get(args, 'S')) == NULL)
ses_template = CHOOSE_TREE_SESSION_TEMPLATE;
if ((win_template = args_get(args, 'W')) == NULL)
win_template = CHOOSE_TREE_WINDOW_TEMPLATE;
}
/*
* If not asking for windows and sessions, assume no "-ws" given and
* hence display the entire tree outright.
*/
if (!wflag && !sflag)
wflag = sflag = 1;
/*
* If we're drawing in tree mode, including sessions, then pad the
* window template, otherwise just render the windows as a flat list
* without any padding.
*/
if (wflag && sflag) {
xasprintf(&final_win_template_middle,
" \001tq\001> %s", win_template);
xasprintf(&final_win_template_last,
" \001mq\001> %s", win_template);
} else if (wflag) {
final_win_template_middle = xstrdup(win_template);
final_win_template_last = xstrdup(win_template);
} else
final_win_template_middle = final_win_template_last = NULL;
idx_ses = cur_win = -1;
RB_FOREACH(s2, sessions, &sessions) {
idx_ses++;
/*
* If we're just choosing windows, jump straight there. Note
* that this implies the current session, so only choose
* windows when the session matches this one.
*/
if (wflag && !sflag) {
if (s != s2)
continue;
goto windows_only;
}
wcd = window_choose_add_session(wl->window->active,
c, s2, ses_template, ses_action, idx_ses);
/* If we're just choosing sessions, skip choosing windows. */
if (sflag && !wflag) {
if (s == s2)
cur_win = idx_ses;
continue;
}
windows_only:
win_ses = win_max = -1;
RB_FOREACH(wm, winlinks, &s2->windows)
win_max++;
RB_FOREACH(wm, winlinks, &s2->windows) {
win_ses++;
if (sflag && wflag)
idx_ses++;
if (wm == s2->curw && s == s2) {
if (wflag && !sflag) {
/*
* Then we're only counting windows.
* So remember which is the current
* window in the list.
*/
cur_win = win_ses;
} else
cur_win = idx_ses;
}
xasprintf(&final_win_action, "%s %s %s",
wcd != NULL ? wcd->command : "",
wcd != NULL ? ";" : "", win_action);
if (win_ses != win_max)
cur_win_template = final_win_template_middle;
else
cur_win_template = final_win_template_last;
window_choose_add_window(wl->window->active,
c, s2, wm, cur_win_template,
final_win_action,
(wflag && !sflag) ? win_ses : idx_ses);
free(final_win_action);
}
/*
* If we're just drawing windows, don't consider moving on to
* other sessions as we only list windows in this session.
*/
if (wflag && !sflag)
break;
}
free(final_win_template_middle);
free(final_win_template_last);
window_choose_ready(wl->window->active, cur_win, NULL);
if (args_has(args, 'u')) {
window_choose_expand_all(wl->window->active);
window_choose_set_current(wl->window->active, cur_win);
}
return (CMD_RETURN_NORMAL);
}

169
cmd-choose-window.c Normal file
View File

@@ -0,0 +1,169 @@
/* $Id$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include "tmux.h"
/*
* Enter choice mode to choose a window.
*/
int cmd_choose_window_exec(struct cmd *, struct cmd_ctx *);
void cmd_choose_window_callback(void *, int);
void cmd_choose_window_free(void *);
const struct cmd_entry cmd_choose_window_entry = {
"choose-window", NULL,
"t:", 0, 1,
CMD_TARGET_WINDOW_USAGE " [template]",
0,
NULL,
NULL,
cmd_choose_window_exec
};
struct cmd_choose_window_data {
struct client *client;
struct session *session;
char *template;
};
int
cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_choose_window_data *cdata;
struct session *s;
struct winlink *wl, *wm;
struct window *w;
u_int idx, cur;
char *flags, *title;
const char *left, *right;
if (ctx->curclient == NULL) {
ctx->error(ctx, "must be run interactively");
return (-1);
}
s = ctx->curclient->session;
if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
return (-1);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (0);
cur = idx = 0;
RB_FOREACH(wm, winlinks, &s->windows) {
w = wm->window;
if (wm == s->curw)
cur = idx;
idx++;
flags = window_printable_flags(s, wm);
title = w->active->screen->title;
if (wm == wl)
title = w->active->base.title;
left = " \"";
right = "\"";
if (*title == '\0')
left = right = "";
window_choose_add(wl->window->active,
wm->idx, "%3d: %s%s [%ux%u] (%u panes%s)%s%s%s",
wm->idx, w->name, flags, w->sx, w->sy, window_count_panes(w),
w->active->fd == -1 ? ", dead" : "",
left, title, right);
xfree(flags);
}
cdata = xmalloc(sizeof *cdata);
if (args->argc != 0)
cdata->template = xstrdup(args->argv[0]);
else
cdata->template = xstrdup("select-window -t '%%'");
cdata->session = s;
cdata->session->references++;
cdata->client = ctx->curclient;
cdata->client->references++;
window_choose_ready(wl->window->active,
cur, cmd_choose_window_callback, cmd_choose_window_free, cdata);
return (0);
}
void
cmd_choose_window_callback(void *data, int idx)
{
struct cmd_choose_window_data *cdata = data;
struct session *s = cdata->session;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *target, *template, *cause;
if (idx == -1)
return;
if (!session_alive(s))
return;
if (cdata->client->flags & CLIENT_DEAD)
return;
xasprintf(&target, "%s:%d", s->name, idx);
template = cmd_template_replace(cdata->template, target, 1);
xfree(target);
if (cmd_string_parse(template, &cmdlist, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(cdata->client, "%s", cause);
xfree(cause);
}
xfree(template);
return;
}
xfree(template);
ctx.msgdata = NULL;
ctx.curclient = cdata->client;
ctx.error = key_bindings_error;
ctx.print = key_bindings_print;
ctx.info = key_bindings_info;
ctx.cmdclient = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist);
}
void
cmd_choose_window_free(void *data)
{
struct cmd_choose_window_data *cdata = data;
cdata->session->references--;
cdata->client->references--;
xfree(cdata->template);
xfree(cdata);
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,29 +24,31 @@
* Clear pane history. * Clear pane history.
*/ */
enum cmd_retval cmd_clear_history_exec(struct cmd *, struct cmd_q *); int cmd_clear_history_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_clear_history_entry = { const struct cmd_entry cmd_clear_history_entry = {
"clear-history", "clearhist", "clear-history", "clearhist",
"t:", 0, 0, "t:", 0, 0,
CMD_TARGET_PANE_USAGE, CMD_TARGET_PANE_USAGE,
0, 0,
NULL,
NULL,
cmd_clear_history_exec cmd_clear_history_exec
}; };
enum cmd_retval int
cmd_clear_history_exec(struct cmd *self, struct cmd_q *cmdq) cmd_clear_history_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp; struct window_pane *wp;
struct grid *gd; struct grid *gd;
if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL) if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
return (CMD_RETURN_ERROR); return (-1);
gd = wp->base.grid; gd = wp->base.grid;
grid_move_lines(gd, 0, gd->hsize, gd->sy); grid_move_lines(gd, 0, gd->hsize, gd->sy);
gd->hsize = 0; gd->hsize = 0;
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,5 +1,7 @@
/* $Id$ */
/* /*
* Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -14,48 +16,36 @@
* 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 <errno.h> #include <sys/types.h>
#include <fcntl.h>
#include <stdarg.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
/*
* Enter clock mode.
*/
int cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_clock_mode_entry = {
"clock-mode", NULL,
"t:", 0, 0,
CMD_TARGET_PANE_USAGE,
0,
NULL,
NULL,
cmd_clock_mode_exec
};
int int
openat(int fd, const char *path, int flags, ...) cmd_clock_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
mode_t mode; struct args *args = self->args;
va_list ap; struct window_pane *wp;
int dotfd, retval, saved_errno;
if (flags & O_CREAT) { if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
va_start(ap, flags); return (-1);
mode = va_arg(ap, mode_t);
va_end(ap);
} else
mode = 0;
dotfd = -1; window_pane_set_mode(wp, &window_clock_mode);
if (fd != AT_FDCWD) {
dotfd = open(".", O_RDONLY);
if (dotfd == -1)
return (-1);
if (fchdir(fd) != 0)
return (-1);
}
retval = open(path, flags, mode); return (0);
if (dotfd != -1) {
if (fchdir(dotfd) != 0) {
saved_errno = errno;
close(retval);
close(dotfd);
errno = saved_errno;
return (-1);
}
close(dotfd);
}
return (retval);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -19,7 +19,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h> #include <ctype.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
@@ -29,7 +28,9 @@
* Prompt for command in client. * Prompt for command in client.
*/ */
enum cmd_retval cmd_command_prompt_exec(struct cmd *, struct cmd_q *); void cmd_command_prompt_key_binding(struct cmd *, int);
int cmd_command_prompt_check(struct args *);
int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *);
int cmd_command_prompt_callback(void *, const char *); int cmd_command_prompt_callback(void *, const char *);
void cmd_command_prompt_free(void *); void cmd_command_prompt_free(void *);
@@ -39,6 +40,8 @@ const struct cmd_entry cmd_command_prompt_entry = {
"I:p:t:", 0, 1, "I:p:t:", 0, 1,
"[-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " [template]", "[-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " [template]",
0, 0,
cmd_command_prompt_key_binding,
NULL,
cmd_command_prompt_exec cmd_command_prompt_exec
}; };
@@ -52,8 +55,36 @@ struct cmd_command_prompt_cdata {
int idx; int idx;
}; };
enum cmd_retval void
cmd_command_prompt_exec(struct cmd *self, struct cmd_q *cmdq) cmd_command_prompt_key_binding(struct cmd *self, int key)
{
switch (key) {
case '$':
self->args = args_create(1, "rename-session '%%'");
args_set(self->args, 'I', "#S");
break;
case ',':
self->args = args_create(1, "rename-window '%%'");
args_set(self->args, 'I', "#W");
break;
case '.':
self->args = args_create(1, "move-window -t '%%'");
break;
case 'f':
self->args = args_create(1, "find-window '%%'");
break;
case '\'':
self->args = args_create(1, "select-window -t ':%%'");
args_set(self->args, 'p', "index");
break;
default:
self->args = args_create(0);
break;
}
}
int
cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
const char *inputs, *prompts; const char *inputs, *prompts;
@@ -62,11 +93,11 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_q *cmdq)
char *prompt, *ptr, *input = NULL; char *prompt, *ptr, *input = NULL;
size_t n; size_t n;
if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL) if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
return (CMD_RETURN_ERROR); return (-1);
if (c->prompt_string != NULL) if (c->prompt_string != NULL)
return (CMD_RETURN_NORMAL); return (0);
cdata = xmalloc(sizeof *cdata); cdata = xmalloc(sizeof *cdata);
cdata->c = c; cdata->c = c;
@@ -107,9 +138,9 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_q *cmdq)
status_prompt_set(c, prompt, input, cmd_command_prompt_callback, status_prompt_set(c, prompt, input, cmd_command_prompt_callback,
cmd_command_prompt_free, cdata, 0); cmd_command_prompt_free, cdata, 0);
free(prompt); xfree(prompt);
return (CMD_RETURN_NORMAL); return (0);
} }
int int
@@ -118,6 +149,7 @@ cmd_command_prompt_callback(void *data, const char *s)
struct cmd_command_prompt_cdata *cdata = data; struct cmd_command_prompt_cdata *cdata = data;
struct client *c = cdata->c; struct client *c = cdata->c;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *cause, *new_template, *prompt, *ptr; char *cause, *new_template, *prompt, *ptr;
char *input = NULL; char *input = NULL;
@@ -125,7 +157,7 @@ cmd_command_prompt_callback(void *data, const char *s)
return (0); return (0);
new_template = cmd_template_replace(cdata->template, s, cdata->idx); new_template = cmd_template_replace(cdata->template, s, cdata->idx);
free(cdata->template); xfree(cdata->template);
cdata->template = new_template; cdata->template = new_template;
/* /*
@@ -137,21 +169,30 @@ cmd_command_prompt_callback(void *data, const char *s)
input = strsep(&cdata->next_input, ","); input = strsep(&cdata->next_input, ",");
status_prompt_update(c, prompt, input); status_prompt_update(c, prompt, input);
free(prompt); xfree(prompt);
cdata->idx++; cdata->idx++;
return (1); return (1);
} }
if (cmd_string_parse(new_template, &cmdlist, NULL, 0, &cause) != 0) { if (cmd_string_parse(new_template, &cmdlist, &cause) != 0) {
if (cause != NULL) { if (cause != NULL) {
*cause = toupper((u_char) *cause); *cause = toupper((u_char) *cause);
status_message_set(c, "%s", cause); status_message_set(c, "%s", cause);
free(cause); xfree(cause);
} }
return (0); return (0);
} }
cmdq_run(c->cmdq, cmdlist); ctx.msgdata = NULL;
ctx.curclient = c;
ctx.error = key_bindings_error;
ctx.print = key_bindings_print;
ctx.info = key_bindings_info;
ctx.cmdclient = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
if (c->prompt_callbackfn != (void *) &cmd_command_prompt_callback) if (c->prompt_callbackfn != (void *) &cmd_command_prompt_callback)
@@ -164,8 +205,11 @@ cmd_command_prompt_free(void *data)
{ {
struct cmd_command_prompt_cdata *cdata = data; struct cmd_command_prompt_cdata *cdata = data;
free(cdata->inputs); if (cdata->inputs != NULL)
free(cdata->prompts); xfree(cdata->inputs);
free(cdata->template); if (cdata->prompts != NULL)
free(cdata); xfree(cdata->prompts);
if (cdata->template != NULL)
xfree(cdata->template);
xfree(cdata);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -16,10 +16,7 @@
* 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 <ctype.h> #include <ctype.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -28,26 +25,47 @@
* Asks for confirmation before executing a command. * Asks for confirmation before executing a command.
*/ */
enum cmd_retval cmd_confirm_before_exec(struct cmd *, struct cmd_q *); void cmd_confirm_before_key_binding(struct cmd *, int);
int cmd_confirm_before_exec(struct cmd *, struct cmd_ctx *);
int cmd_confirm_before_callback(void *, const char *); int cmd_confirm_before_callback(void *, const char *);
void cmd_confirm_before_free(void *); void cmd_confirm_before_free(void *);
const struct cmd_entry cmd_confirm_before_entry = { const struct cmd_entry cmd_confirm_before_entry = {
"confirm-before", "confirm", "confirm-before", "confirm",
"p:t:", 1, 1, "p:t:", 1, 1,
"[-p prompt] " CMD_TARGET_CLIENT_USAGE " command", "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
0, 0,
cmd_confirm_before_key_binding,
NULL,
cmd_confirm_before_exec cmd_confirm_before_exec
}; };
struct cmd_confirm_before_data { struct cmd_confirm_before_data {
struct client *c;
char *cmd; char *cmd;
struct client *client;
}; };
enum cmd_retval void
cmd_confirm_before_exec(struct cmd *self, struct cmd_q *cmdq) cmd_confirm_before_key_binding(struct cmd *self, int key)
{
switch (key) {
case '&':
self->args = args_create(1, "kill-window");
args_set(self->args, 'p', "kill-window #W? (y/n)");
break;
case 'x':
self->args = args_create(1, "kill-pane");
args_set(self->args, 'p', "kill-pane #P? (y/n)");
break;
default:
self->args = args_create(0);
break;
}
}
int
cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_confirm_before_data *cdata; struct cmd_confirm_before_data *cdata;
@@ -55,8 +73,13 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_q *cmdq)
char *cmd, *copy, *new_prompt, *ptr; char *cmd, *copy, *new_prompt, *ptr;
const char *prompt; const char *prompt;
if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL) if (ctx->curclient == NULL) {
return (CMD_RETURN_ERROR); ctx->error(ctx, "must be run interactively");
return (-1);
}
if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
return (-1);
if ((prompt = args_get(args, 'p')) != NULL) if ((prompt = args_get(args, 'p')) != NULL)
xasprintf(&new_prompt, "%s ", prompt); xasprintf(&new_prompt, "%s ", prompt);
@@ -64,48 +87,53 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_q *cmdq)
ptr = copy = xstrdup(args->argv[0]); ptr = copy = xstrdup(args->argv[0]);
cmd = strsep(&ptr, " \t"); cmd = strsep(&ptr, " \t");
xasprintf(&new_prompt, "Confirm '%s'? (y/n) ", cmd); xasprintf(&new_prompt, "Confirm '%s'? (y/n) ", cmd);
free(copy); xfree(copy);
} }
cdata = xmalloc(sizeof *cdata); cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(args->argv[0]); cdata->cmd = xstrdup(args->argv[0]);
cdata->c = c;
cdata->client = c; status_prompt_set(cdata->c, new_prompt, NULL,
cdata->client->references++;
status_prompt_set(c, new_prompt, NULL,
cmd_confirm_before_callback, cmd_confirm_before_free, cdata, cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
PROMPT_SINGLE); PROMPT_SINGLE);
free(new_prompt); xfree(new_prompt);
return (CMD_RETURN_NORMAL); return (1);
} }
int int
cmd_confirm_before_callback(void *data, const char *s) cmd_confirm_before_callback(void *data, const char *s)
{ {
struct cmd_confirm_before_data *cdata = data; struct cmd_confirm_before_data *cdata = data;
struct client *c = cdata->client; struct client *c = cdata->c;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *cause; char *cause;
if (c->flags & CLIENT_DEAD)
return (0);
if (s == NULL || *s == '\0') if (s == NULL || *s == '\0')
return (0); return (0);
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0') if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
return (0); return (0);
if (cmd_string_parse(cdata->cmd, &cmdlist, NULL, 0, &cause) != 0) { if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) {
if (cause != NULL) { if (cause != NULL) {
cmdq_error(c->cmdq, "%s", cause); *cause = toupper((u_char) *cause);
free(cause); status_message_set(c, "%s", cause);
xfree(cause);
} }
return (0); return (0);
} }
cmdq_run(c->cmdq, cmdlist); ctx.msgdata = NULL;
ctx.curclient = c;
ctx.error = key_bindings_error;
ctx.print = key_bindings_print;
ctx.info = key_bindings_info;
ctx.cmdclient = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
return (0); return (0);
@@ -115,10 +143,8 @@ void
cmd_confirm_before_free(void *data) cmd_confirm_before_free(void *data)
{ {
struct cmd_confirm_before_data *cdata = data; struct cmd_confirm_before_data *cdata = data;
struct client *c = cdata->client;
c->references--; if (cdata->cmd != NULL)
xfree(cdata->cmd);
free(cdata->cmd); xfree(cdata);
free(cdata);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -21,48 +21,44 @@
#include "tmux.h" #include "tmux.h"
/* /*
* Enter copy or clock mode. * Enter copy mode.
*/ */
enum cmd_retval cmd_copy_mode_exec(struct cmd *, struct cmd_q *); void cmd_copy_mode_key_binding(struct cmd *, int);
int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_copy_mode_entry = { const struct cmd_entry cmd_copy_mode_entry = {
"copy-mode", NULL, "copy-mode", NULL,
"t:u", 0, 0, "t:u", 0, 0,
"[-u] " CMD_TARGET_PANE_USAGE, "[-u] " CMD_TARGET_PANE_USAGE,
0, 0,
cmd_copy_mode_key_binding,
NULL,
cmd_copy_mode_exec cmd_copy_mode_exec
}; };
const struct cmd_entry cmd_clock_mode_entry = { void
"clock-mode", NULL, cmd_copy_mode_key_binding(struct cmd *self, int key)
"t:", 0, 0, {
CMD_TARGET_PANE_USAGE, self->args = args_create(0);
0, if (key == KEYC_PPAGE)
cmd_copy_mode_exec args_set(self->args, 'u', NULL);
}; }
enum cmd_retval int
cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq) cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp; struct window_pane *wp;
if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL) if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
return (CMD_RETURN_ERROR); return (-1);
if (self->entry == &cmd_clock_mode_entry) { if (window_pane_set_mode(wp, &window_copy_mode) != 0)
window_pane_set_mode(wp, &window_clock_mode); return (0);
return (CMD_RETURN_NORMAL); window_copy_init_from_pane(wp);
}
if (wp->mode != &window_copy_mode) {
if (window_pane_set_mode(wp, &window_copy_mode) != 0)
return (CMD_RETURN_NORMAL);
window_copy_init_from_pane(wp);
}
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); window_copy_pageup(wp);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,32 +26,41 @@
* Delete a paste buffer. * Delete a paste buffer.
*/ */
enum cmd_retval cmd_delete_buffer_exec(struct cmd *, struct cmd_q *); int cmd_delete_buffer_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_delete_buffer_entry = { const struct cmd_entry cmd_delete_buffer_entry = {
"delete-buffer", "deleteb", "delete-buffer", "deleteb",
"b:", 0, 0, "b:", 0, 0,
CMD_BUFFER_USAGE, CMD_BUFFER_USAGE,
0, 0,
NULL,
NULL,
cmd_delete_buffer_exec cmd_delete_buffer_exec
}; };
enum cmd_retval int
cmd_delete_buffer_exec(struct cmd *self, struct cmd_q *cmdq) cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
const char *bufname; char *cause;
int buffer;
if (!args_has(args, 'b')) { if (!args_has(args, 'b')) {
paste_free_top(); paste_free_top(&global_buffers);
return (CMD_RETURN_NORMAL); return (0);
}
bufname = args_get(args, 'b');
if (paste_free_name(bufname) != 0) {
cmdq_error(cmdq, "no buffer %s", bufname);
return (CMD_RETURN_ERROR);
} }
return (CMD_RETURN_NORMAL); buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
ctx->error(ctx, "buffer %s", cause);
xfree(cause);
return (-1);
}
if (paste_free_index(&global_buffers, buffer) != 0) {
ctx->error(ctx, "no buffer %d", buffer);
return (-1);
}
return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,90 +18,55 @@
#include <sys/types.h> #include <sys/types.h>
#include <string.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Detach a client. * Detach a client.
*/ */
enum cmd_retval cmd_detach_client_exec(struct cmd *, struct cmd_q *); int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_detach_client_entry = { const struct cmd_entry cmd_detach_client_entry = {
"detach-client", "detach", "detach-client", "detach",
"as:t:P", 0, 0, "s:t:P", 0, 0,
"[-P] [-a] [-s target-session] " CMD_TARGET_CLIENT_USAGE, "[-P] [-s target-session] " CMD_TARGET_CLIENT_USAGE,
CMD_READONLY, CMD_READONLY,
NULL,
NULL,
cmd_detach_client_exec cmd_detach_client_exec
}; };
const struct cmd_entry cmd_suspend_client_entry = { int
"suspend-client", "suspendc", cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx)
"t:", 0, 0,
CMD_TARGET_CLIENT_USAGE,
0,
cmd_detach_client_exec
};
enum cmd_retval
cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c, *cloop; struct client *c;
struct session *s; struct session *s;
enum msgtype msgtype; enum msgtype msgtype;
u_int i; u_int i;
if (self->entry == &cmd_suspend_client_entry) {
if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
tty_stop_tty(&c->tty);
c->flags |= CLIENT_SUSPENDED;
server_write_client(c, MSG_SUSPEND, NULL, 0);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'P')) if (args_has(args, 'P'))
msgtype = MSG_DETACHKILL; msgtype = MSG_DETACHKILL;
else else
msgtype = MSG_DETACH; msgtype = MSG_DETACH;
if (args_has(args, 's')) { if (args_has(args, 's')) {
s = cmd_find_session(cmdq, args_get(args, 's'), 0); s = cmd_find_session(ctx, args_get(args, 's'), 0);
if (s == NULL) if (s == NULL)
return (CMD_RETURN_ERROR); return (-1);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
cloop = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);
if (cloop == NULL || cloop->session != s) if (c != NULL && c->session == s)
continue; server_write_client(c, msgtype, NULL, 0);
server_write_client(cloop, msgtype,
cloop->session->name,
strlen(cloop->session->name) + 1);
} }
return (CMD_RETURN_STOP); } else {
c = cmd_find_client(ctx, args_get(args, 't'));
if (c == NULL)
return (-1);
server_write_client(c, msgtype, NULL, 0);
} }
c = cmd_find_client(cmdq, args_get(args, 't'), 0); return (0);
if (c == NULL)
return (CMD_RETURN_ERROR);
if (args_has(args, 'a')) {
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
cloop = ARRAY_ITEM(&clients, i);
if (cloop == NULL || cloop->session == NULL)
continue;
if (cloop == c)
continue;
server_write_client(cloop, msgtype,
cloop->session->name,
strlen(cloop->session->name) + 1);
}
return (CMD_RETURN_NORMAL);
}
server_write_client(c, msgtype, c->session->name,
strlen(c->session->name) + 1);
return (CMD_RETURN_STOP);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <time.h> #include <time.h>
#include "tmux.h" #include "tmux.h"
@@ -27,24 +26,20 @@
* Displays a message in the status line. * Displays a message in the status line.
*/ */
#define DISPLAY_MESSAGE_TEMPLATE \ int cmd_display_message_exec(struct cmd *, struct cmd_ctx *);
"[#{session_name}] #{window_index}:" \
"#{window_name}, current pane #{pane_index} " \
"- (%H:%M %d-%b-%y)"
enum cmd_retval cmd_display_message_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_display_message_entry = { const struct cmd_entry cmd_display_message_entry = {
"display-message", "display", "display-message", "display",
"c:pt:F:", 0, 1, "c:pt:", 0, 1,
"[-p] [-c target-client] [-F format] " CMD_TARGET_PANE_USAGE "[-p] [-c target-client] [-t target-pane] [message]",
" [message]",
0, 0,
NULL,
NULL,
cmd_display_message_exec cmd_display_message_exec
}; };
enum cmd_retval int
cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq) cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c;
@@ -53,58 +48,31 @@ cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp; struct window_pane *wp;
const char *template; const char *template;
char *msg; char *msg;
struct format_tree *ft;
char out[BUFSIZ];
time_t t;
size_t len;
if (args_has(args, 't')) { if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL)
wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); return (-1);
if (args_has(args, 't') != 0) {
wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp);
if (wl == NULL) if (wl == NULL)
return (CMD_RETURN_ERROR); return (-1);
} else { } else {
wl = cmd_find_pane(cmdq, NULL, &s, &wp); s = NULL;
if (wl == NULL) wl = NULL;
return (CMD_RETURN_ERROR); wp = NULL;
} }
if (args_has(args, 'F') && args->argc != 0) { if (args->argc == 0)
cmdq_error(cmdq, "only one of -F or argument must be given"); template = "[#S] #I:#W, current pane #P - (%H:%M %d-%b-%y)";
return (CMD_RETURN_ERROR); else
}
if (args_has(args, 'c')) {
c = cmd_find_client(cmdq, args_get(args, 'c'), 0);
if (c == NULL)
return (CMD_RETURN_ERROR);
} else {
c = cmd_current_client(cmdq);
if (c == NULL && !args_has(self->args, 'p')) {
cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}
}
template = args_get(args, 'F');
if (args->argc != 0)
template = args->argv[0]; template = args->argv[0];
if (template == NULL)
template = DISPLAY_MESSAGE_TEMPLATE;
ft = format_create(); msg = status_replace(c, s, wl, wp, template, time(NULL), 0);
format_defaults(ft, c, s, wl, wp);
t = time(NULL);
len = strftime(out, sizeof out, template, localtime(&t));
out[len] = '\0';
msg = format_expand(ft, out);
if (args_has(self->args, 'p')) if (args_has(self->args, 'p'))
cmdq_print(cmdq, "%s", msg); ctx->print(ctx, "%s", msg);
else else
status_message_set(c, "%s", msg); status_message_set(c, "%s", msg);
free(msg); xfree(msg);
format_free(ft);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,26 +24,28 @@
* Display panes on a client. * Display panes on a client.
*/ */
enum cmd_retval cmd_display_panes_exec(struct cmd *, struct cmd_q *); int cmd_display_panes_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_display_panes_entry = { const struct cmd_entry cmd_display_panes_entry = {
"display-panes", "displayp", "display-panes", "displayp",
"t:", 0, 0, "t:", 0, 0,
CMD_TARGET_CLIENT_USAGE, CMD_TARGET_CLIENT_USAGE,
0, 0,
NULL,
NULL,
cmd_display_panes_exec cmd_display_panes_exec
}; };
enum cmd_retval int
cmd_display_panes_exec(struct cmd *self, struct cmd_q *cmdq) cmd_display_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c;
if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL) if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
return (CMD_RETURN_ERROR); return (-1);
server_set_identify(c); server_set_identify(c);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -19,7 +19,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <fnmatch.h> #include <fnmatch.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -28,151 +27,94 @@
* Find window containing text. * Find window containing text.
*/ */
#define FIND_WINDOW_TEMPLATE \ int cmd_find_window_exec(struct cmd *, struct cmd_ctx *);
"#{window_index}: #{window_name} " \
"[#{window_width}x#{window_height}] " \
"(#{window_panes} panes) #{window_find_matches}"
enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmd_q *); void cmd_find_window_callback(void *, int);
void cmd_find_window_free(void *);
void cmd_find_window_callback(struct window_choose_data *);
/* Flags for determining matching behavior. */
#define CMD_FIND_WINDOW_BY_TITLE 0x1
#define CMD_FIND_WINDOW_BY_CONTENT 0x2
#define CMD_FIND_WINDOW_BY_NAME 0x4
#define CMD_FIND_WINDOW_ALL \
(CMD_FIND_WINDOW_BY_TITLE | \
CMD_FIND_WINDOW_BY_CONTENT | \
CMD_FIND_WINDOW_BY_NAME)
const struct cmd_entry cmd_find_window_entry = { const struct cmd_entry cmd_find_window_entry = {
"find-window", "findw", "find-window", "findw",
"F:CNt:T", 1, 4, "t:", 1, 1,
"[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string", CMD_TARGET_WINDOW_USAGE " match-string",
0, 0,
NULL,
NULL,
cmd_find_window_exec cmd_find_window_exec
}; };
struct cmd_find_window_data { struct cmd_find_window_data {
struct winlink *wl; struct session *session;
char *list_ctx;
u_int pane_id;
}; };
ARRAY_DECL(cmd_find_window_data_list, struct cmd_find_window_data);
u_int cmd_find_window_match_flags(struct args *); int
void cmd_find_window_match(struct cmd_find_window_data_list *, int, cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
struct winlink *, const char *, const char *);
u_int
cmd_find_window_match_flags(struct args *args)
{
u_int match_flags = 0;
/* Turn on flags based on the options. */
if (args_has(args, 'T'))
match_flags |= CMD_FIND_WINDOW_BY_TITLE;
if (args_has(args, 'C'))
match_flags |= CMD_FIND_WINDOW_BY_CONTENT;
if (args_has(args, 'N'))
match_flags |= CMD_FIND_WINDOW_BY_NAME;
/* If none of the flags were set, default to matching anything. */
if (match_flags == 0)
match_flags = CMD_FIND_WINDOW_ALL;
return (match_flags);
}
void
cmd_find_window_match(struct cmd_find_window_data_list *find_list,
int match_flags, struct winlink *wl, const char *str,
const char *searchstr)
{
struct cmd_find_window_data find_data;
struct window_pane *wp;
u_int i, line;
char *sres;
memset(&find_data, 0, sizeof find_data);
i = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
i++;
if ((match_flags & CMD_FIND_WINDOW_BY_NAME) &&
fnmatch(searchstr, wl->window->name, 0) == 0) {
find_data.list_ctx = xstrdup("");
break;
}
if ((match_flags & CMD_FIND_WINDOW_BY_TITLE) &&
fnmatch(searchstr, wp->base.title, 0) == 0) {
xasprintf(&find_data.list_ctx,
"pane %u title: \"%s\"", i - 1, wp->base.title);
break;
}
if (match_flags & CMD_FIND_WINDOW_BY_CONTENT &&
(sres = window_pane_search(wp, str, &line)) != NULL) {
xasprintf(&find_data.list_ctx,
"pane %u line %u: \"%s\"", i - 1, line + 1, sres);
free(sres);
break;
}
}
if (find_data.list_ctx != NULL) {
find_data.wl = wl;
find_data.pane_id = i - 1;
ARRAY_ADD(find_list, find_data);
}
}
enum cmd_retval
cmd_find_window_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct cmd_find_window_data *cdata;
struct window_choose_data *cdata;
struct session *s; struct session *s;
struct winlink *wl, *wm; struct winlink *wl, *wm;
struct cmd_find_window_data_list find_list; struct window *w;
char *str, *searchstr; struct window_pane *wp;
const char *template; ARRAY_DECL(, u_int) list_idx;
u_int i, match_flags; ARRAY_DECL(, char *) list_ctx;
char *str, *sres, *sctx, *searchstr;
u_int i, line;
if ((c = cmd_current_client(cmdq)) == NULL) { if (ctx->curclient == NULL) {
cmdq_error(cmdq, "no client available"); ctx->error(ctx, "must be run interactively");
return (CMD_RETURN_ERROR); return (-1);
} }
s = c->session; s = ctx->curclient->session;
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
if ((template = args_get(args, 'F')) == NULL)
template = FIND_WINDOW_TEMPLATE;
match_flags = cmd_find_window_match_flags(args);
str = args->argv[0]; str = args->argv[0];
ARRAY_INIT(&find_list); ARRAY_INIT(&list_idx);
ARRAY_INIT(&list_ctx);
xasprintf(&searchstr, "*%s*", str); xasprintf(&searchstr, "*%s*", str);
RB_FOREACH(wm, winlinks, &s->windows) RB_FOREACH(wm, winlinks, &s->windows) {
cmd_find_window_match(&find_list, match_flags, wm, str, searchstr); i = 0;
free(searchstr); TAILQ_FOREACH(wp, &wm->window->panes, entry) {
i++;
if (ARRAY_LENGTH(&find_list) == 0) { if (fnmatch(searchstr, wm->window->name, 0) == 0)
cmdq_error(cmdq, "no windows matching: %s", str); sctx = xstrdup("");
ARRAY_FREE(&find_list); else {
return (CMD_RETURN_ERROR); sres = window_pane_search(wp, str, &line);
if (sres == NULL &&
fnmatch(searchstr, wp->base.title, 0) != 0)
continue;
if (sres == NULL) {
xasprintf(&sctx,
"pane %u title: \"%s\"", i - 1,
wp->base.title);
} else {
xasprintf(&sctx,
"pane %u line %u: \"%s\"", i - 1,
line + 1, sres);
xfree(sres);
}
}
ARRAY_ADD(&list_idx, wm->idx);
ARRAY_ADD(&list_ctx, sctx);
}
}
xfree(searchstr);
if (ARRAY_LENGTH(&list_idx) == 0) {
ctx->error(ctx, "no windows matching: %s", str);
ARRAY_FREE(&list_idx);
ARRAY_FREE(&list_ctx);
return (-1);
} }
if (ARRAY_LENGTH(&find_list) == 1) { if (ARRAY_LENGTH(&list_idx) == 1) {
if (session_select(s, ARRAY_FIRST(&find_list).wl->idx) == 0) if (session_select(s, ARRAY_FIRST(&list_idx)) == 0)
server_redraw_session(s); server_redraw_session(s);
recalculate_sizes(); recalculate_sizes();
goto out; goto out;
@@ -181,52 +123,54 @@ cmd_find_window_exec(struct cmd *self, struct cmd_q *cmdq)
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
goto out; goto out;
for (i = 0; i < ARRAY_LENGTH(&find_list); i++) { for (i = 0; i < ARRAY_LENGTH(&list_idx); i++) {
wm = ARRAY_ITEM(&find_list, i).wl; wm = winlink_find_by_index(
&s->windows, ARRAY_ITEM(&list_idx, i));
w = wm->window;
cdata = window_choose_data_create(TREE_OTHER, c, c->session); sctx = ARRAY_ITEM(&list_ctx, i);
cdata->idx = wm->idx; window_choose_add(wl->window->active,
cdata->wl = wm; wm->idx, "%3d: %s [%ux%u] (%u panes) %s", wm->idx, w->name,
w->sx, w->sy, window_count_panes(w), sctx);
cdata->ft_template = xstrdup(template); xfree(sctx);
cdata->pane_id = ARRAY_ITEM(&find_list, i).pane_id;
format_add(cdata->ft, "line", "%u", i);
format_add(cdata->ft, "window_find_matches", "%s",
ARRAY_ITEM(&find_list, i).list_ctx);
format_defaults(cdata->ft, NULL, s, wm, NULL);
window_choose_add(wl->window->active, cdata);
} }
window_choose_ready(wl->window->active, 0, cmd_find_window_callback); cdata = xmalloc(sizeof *cdata);
cdata->session = s;
cdata->session->references++;
window_choose_ready(wl->window->active,
0, cmd_find_window_callback, cmd_find_window_free, cdata);
out: out:
for (i = 0; i < ARRAY_LENGTH(&find_list); i++) ARRAY_FREE(&list_idx);
free(ARRAY_ITEM(&find_list, i).list_ctx); ARRAY_FREE(&list_ctx);
ARRAY_FREE(&find_list);
return (CMD_RETURN_NORMAL); return (0);
} }
void void
cmd_find_window_callback(struct window_choose_data *cdata) cmd_find_window_callback(void *data, int idx)
{ {
struct session *s; struct cmd_find_window_data *cdata = data;
struct window_pane *wp; struct session *s = cdata->session;
if (cdata == NULL) if (idx == -1)
return; return;
s = cdata->start_session;
if (!session_alive(s)) if (!session_alive(s))
return; return;
wp = window_pane_at_index(cdata->wl->window, cdata->pane_id); if (session_select(s, idx) == 0) {
if (wp != NULL && window_pane_visible(wp))
window_set_active_pane(cdata->wl->window, wp);
if (session_select(s, cdata->idx) == 0) {
server_redraw_session(s); server_redraw_session(s);
recalculate_sizes(); recalculate_sizes();
} }
} }
void
cmd_find_window_free(void *data)
{
struct cmd_find_window_data *cdata = data;
cdata->session->references--;
xfree(cdata);
}

48
cmd-has-session.c Normal file
View File

@@ -0,0 +1,48 @@
/* $Id$ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Cause client to report an error and exit with 1 if session doesn't exist.
*/
int cmd_has_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_has_session_entry = {
"has-session", "has",
"t:", 0, 0,
CMD_TARGET_SESSION_USAGE,
0,
NULL,
NULL,
cmd_has_session_exec
};
int
cmd_has_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
if (cmd_find_session(ctx, args_get(args, 't'), 0) == NULL)
return (-1);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -20,174 +20,93 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Executes a tmux command if a shell command returns true or false. * Executes a tmux command if a shell command returns true.
*/ */
enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmd_q *); int cmd_if_shell_exec(struct cmd *, struct cmd_ctx *);
void cmd_if_shell_callback(struct job *); void cmd_if_shell_callback(struct job *);
void cmd_if_shell_done(struct cmd_q *);
void cmd_if_shell_free(void *); void cmd_if_shell_free(void *);
const struct cmd_entry cmd_if_shell_entry = { const struct cmd_entry cmd_if_shell_entry = {
"if-shell", "if", "if-shell", "if",
"bFt:", 2, 3, "", 2, 2,
"[-bF] " CMD_TARGET_PANE_USAGE " shell-command command [command]", "shell-command command",
0, 0,
NULL,
NULL,
cmd_if_shell_exec cmd_if_shell_exec
}; };
struct cmd_if_shell_data { struct cmd_if_shell_data {
char *cmd_if; char *cmd;
char *cmd_else; struct cmd_ctx ctx;
struct cmd_q *cmdq;
int bflag;
int started;
}; };
enum cmd_retval int
cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_if_shell_data *cdata; struct cmd_if_shell_data *cdata;
char *shellcmd, *cmd, *cause; const char *shellcmd = args->argv[0];
struct cmd_list *cmdlist;
struct client *c;
struct session *s = NULL;
struct winlink *wl = NULL;
struct window_pane *wp = NULL;
struct format_tree *ft;
if (args_has(args, 't'))
wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
else {
c = cmd_find_client(cmdq, NULL, 1);
if (c != NULL && c->session != NULL) {
s = c->session;
wl = s->curw;
wp = wl->window->active;
}
}
ft = format_create();
format_defaults(ft, NULL, s, wl, wp);
shellcmd = format_expand(ft, args->argv[0]);
format_free(ft);
if (args_has(args, 'F')) {
cmd = NULL;
if (*shellcmd != '0' && *shellcmd != '\0')
cmd = args->argv[1];
else if (args->argc == 3)
cmd = args->argv[2];
if (cmd == NULL)
return (CMD_RETURN_NORMAL);
if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) {
cmdq_error(cmdq, "%s", cause);
free(cause);
}
return (CMD_RETURN_ERROR);
}
cmdq_run(cmdq, cmdlist);
cmd_list_free(cmdlist);
return (CMD_RETURN_NORMAL);
}
cdata = xmalloc(sizeof *cdata); cdata = xmalloc(sizeof *cdata);
cdata->cmd_if = xstrdup(args->argv[1]); cdata->cmd = xstrdup(args->argv[1]);
if (args->argc == 3) memcpy(&cdata->ctx, ctx, sizeof cdata->ctx);
cdata->cmd_else = xstrdup(args->argv[2]);
else
cdata->cmd_else = NULL;
cdata->bflag = args_has(args, 'b');
cdata->started = 0; if (ctx->cmdclient != NULL)
cdata->cmdq = cmdq; ctx->cmdclient->references++;
cmdq->references++; if (ctx->curclient != NULL)
ctx->curclient->references++;
job_run(shellcmd, s, cmd_if_shell_callback, cmd_if_shell_free, cdata); job_run(shellcmd, cmd_if_shell_callback, cmd_if_shell_free, cdata);
free(shellcmd);
if (cdata->bflag) return (1); /* don't let client exit */
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
} }
void void
cmd_if_shell_callback(struct job *job) cmd_if_shell_callback(struct job *job)
{ {
struct cmd_if_shell_data *cdata = job->data; struct cmd_if_shell_data *cdata = job->data;
struct cmd_q *cmdq = cdata->cmdq, *cmdq1; struct cmd_ctx *ctx = &cdata->ctx;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
char *cause, *cmd; char *cause;
if (cmdq->dead)
return;
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
cmd = cdata->cmd_else;
else
cmd = cdata->cmd_if;
if (cmd == NULL)
return; return;
if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) { if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) {
if (cause != NULL) { if (cause != NULL) {
cmdq_error(cmdq, "%s", cause); ctx->error(ctx, "%s", cause);
free(cause); xfree(cause);
} }
return; return;
} }
cdata->started = 1; cmd_list_exec(cmdlist, ctx);
cmdq1 = cmdq_new(cmdq->client);
cmdq1->emptyfn = cmd_if_shell_done;
cmdq1->data = cdata;
cmdq_run(cmdq1, cmdlist);
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
} }
void
cmd_if_shell_done(struct cmd_q *cmdq1)
{
struct cmd_if_shell_data *cdata = cmdq1->data;
struct cmd_q *cmdq = cdata->cmdq;
if (cmdq1->client_exit >= 0)
cmdq->client_exit = cmdq1->client_exit;
if (!cmdq_free(cmdq) && !cdata->bflag)
cmdq_continue(cmdq);
cmdq_free(cmdq1);
free(cdata->cmd_else);
free(cdata->cmd_if);
free(cdata);
}
void void
cmd_if_shell_free(void *data) cmd_if_shell_free(void *data)
{ {
struct cmd_if_shell_data *cdata = data; struct cmd_if_shell_data *cdata = data;
struct cmd_q *cmdq = cdata->cmdq; struct cmd_ctx *ctx = &cdata->ctx;
struct msg_exit_data exitdata;
if (cdata->started) if (ctx->cmdclient != NULL) {
return; ctx->cmdclient->references--;
exitdata.retcode = ctx->cmdclient->retcode;
ctx->cmdclient->flags |= CLIENT_EXIT;
}
if (ctx->curclient != NULL)
ctx->curclient->references--;
if (!cmdq_free(cmdq) && !cdata->bflag) xfree(cdata->cmd);
cmdq_continue(cmdq); xfree(cdata);
free(cdata->cmd_else);
free(cdata->cmd_if);
free(cdata);
} }

View File

@@ -1,7 +1,6 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2011 George Nachman <tmux@georgester.com>
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
@@ -25,37 +24,38 @@
#include "tmux.h" #include "tmux.h"
/* /*
* Join or move a pane into another (like split/swap/kill). * Join a pane into another (like split/swap/kill).
*/ */
enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmd_q *); void cmd_join_pane_key_binding(struct cmd *, int);
int cmd_join_pane_exec(struct cmd *, struct cmd_ctx *);
enum cmd_retval join_pane(struct cmd *, struct cmd_q *, int);
const struct cmd_entry cmd_join_pane_entry = { const struct cmd_entry cmd_join_pane_entry = {
"join-pane", "joinp", "join-pane", "joinp",
"bdhvp:l:s:t:", 0, 0, "dhvp:l:s:t:", 0, 0,
"[-bdhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]", "[-dhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]",
0, 0,
cmd_join_pane_key_binding,
NULL,
cmd_join_pane_exec cmd_join_pane_exec
}; };
const struct cmd_entry cmd_move_pane_entry = { void
"move-pane", "movep", cmd_join_pane_key_binding(struct cmd *self, int key)
"bdhvp:l:s:t:", 0, 0,
"[-bdhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]",
0,
cmd_join_pane_exec
};
enum cmd_retval
cmd_join_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
return (join_pane(self, cmdq, self->entry == &cmd_join_pane_entry)); switch (key) {
case '%':
self->args = args_create(0);
args_set(self->args, 'h', NULL);
break;
default:
self->args = args_create(0);
break;
}
} }
enum cmd_retval int
join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window) cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *dst_s; struct session *dst_s;
@@ -67,26 +67,20 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
enum layout_type type; enum layout_type type;
struct layout_cell *lc; struct layout_cell *lc;
dst_wl = cmd_find_pane(cmdq, args_get(args, 't'), &dst_s, &dst_wp); dst_wl = cmd_find_pane(ctx, args_get(args, 't'), &dst_s, &dst_wp);
if (dst_wl == NULL) if (dst_wl == NULL)
return (CMD_RETURN_ERROR); return (-1);
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);
src_wl = cmd_find_pane(cmdq, args_get(args, 's'), NULL, &src_wp); src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp);
if (src_wl == NULL) if (src_wl == NULL)
return (CMD_RETURN_ERROR); return (-1);
src_w = src_wl->window; src_w = src_wl->window;
server_unzoom_window(src_w);
if (not_same_window && src_w == dst_w) { if (src_w == dst_w) {
cmdq_error(cmdq, "can't join a pane to its own window"); ctx->error(ctx, "can't join a pane to its own window");
return (CMD_RETURN_ERROR); return (-1);
}
if (!not_same_window && src_wp == dst_wp) {
cmdq_error(cmdq, "source and target panes must be different");
return (CMD_RETURN_ERROR);
} }
type = LAYOUT_TOPBOTTOM; type = LAYOUT_TOPBOTTOM;
@@ -97,37 +91,39 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
if (args_has(args, 'l')) { if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause); size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) { if (cause != NULL) {
cmdq_error(cmdq, "size %s", cause); ctx->error(ctx, "size %s", cause);
free(cause); xfree(cause);
return (CMD_RETURN_ERROR); return (-1);
} }
} else if (args_has(args, 'p')) { } else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, 100, &cause); percentage = args_strtonum(args, 'p', 0, 100, &cause);
if (cause != NULL) { if (cause != NULL) {
cmdq_error(cmdq, "percentage %s", cause); ctx->error(ctx, "percentage %s", cause);
free(cause); xfree(cause);
return (CMD_RETURN_ERROR); return (-1);
} }
if (type == LAYOUT_TOPBOTTOM) if (type == LAYOUT_TOPBOTTOM)
size = (dst_wp->sy * percentage) / 100; size = (dst_wp->sy * percentage) / 100;
else else
size = (dst_wp->sx * percentage) / 100; size = (dst_wp->sx * percentage) / 100;
} }
lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b'));
if (lc == NULL) { if ((lc = layout_split_pane(dst_wp, type, size)) == NULL) {
cmdq_error(cmdq, "create pane failed: pane too small"); ctx->error(ctx, "create pane failed: pane too small");
return (CMD_RETURN_ERROR); return (-1);
} }
layout_close_pane(src_wp); layout_close_pane(src_wp);
window_lost_pane(src_w, src_wp); if (src_w->active == src_wp) {
src_w->active = TAILQ_PREV(src_wp, window_panes, entry);
if (src_w->active == NULL)
src_w->active = TAILQ_NEXT(src_wp, entry);
}
TAILQ_REMOVE(&src_w->panes, src_wp, entry); TAILQ_REMOVE(&src_w->panes, src_wp, entry);
if (window_count_panes(src_w) == 0) if (window_count_panes(src_w) == 0)
server_kill_window(src_w); server_kill_window(src_w);
else
notify_window_layout_changed(src_w);
src_wp->window = dst_w; src_wp->window = dst_w;
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry); TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
@@ -145,6 +141,5 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
} else } else
server_status_session(dst_s); server_status_session(dst_s);
notify_window_layout_changed(dst_w); return (0);
return (CMD_RETURN_NORMAL);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,40 +26,44 @@
* Kill pane. * Kill pane.
*/ */
enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmd_q *); int cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_pane_entry = { const struct cmd_entry cmd_kill_pane_entry = {
"kill-pane", "killp", "kill-pane", "killp",
"at:", 0, 0, "at:", 0, 0,
"[-a] " CMD_TARGET_PANE_USAGE, "[-a] " CMD_TARGET_PANE_USAGE,
0, 0,
NULL,
NULL,
cmd_kill_pane_exec cmd_kill_pane_exec
}; };
enum cmd_retval int
cmd_kill_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl;
struct window_pane *loopwp, *tmpwp, *wp; struct window_pane *loopwp, *nextwp, *wp;
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL) if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
server_unzoom_window(wl->window);
if (window_count_panes(wl->window) == 1) { if (window_count_panes(wl->window) == 1) {
/* Only one pane, kill the window. */ /* Only one pane, kill the window. */
server_kill_window(wl->window); server_kill_window(wl->window);
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (0);
} }
if (args_has(self->args, 'a')) { if (args_has(self->args, 'a')) {
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) { loopwp = TAILQ_FIRST(&wl->window->panes);
if (loopwp == wp) while (loopwp != NULL) {
continue; nextwp = TAILQ_NEXT(loopwp, entry);
layout_close_pane(loopwp); if (loopwp != wp) {
window_remove_pane(wl->window, loopwp); layout_close_pane(loopwp);
window_remove_pane(wl->window, loopwp);
}
loopwp = nextwp;
} }
} else { } else {
layout_close_pane(wp); layout_close_pane(wp);
@@ -67,5 +71,5 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_q *cmdq)
} }
server_redraw_window(wl->window); server_redraw_window(wl->window);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,29 +27,23 @@
* Kill the server and do nothing else. * Kill the server and do nothing else.
*/ */
enum cmd_retval cmd_kill_server_exec(struct cmd *, struct cmd_q *); int cmd_kill_server_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_server_entry = { const struct cmd_entry cmd_kill_server_entry = {
"kill-server", NULL, "kill-server", NULL,
"", 0, 0, "", 0, 0,
"", "",
0, 0,
NULL,
NULL,
cmd_kill_server_exec cmd_kill_server_exec
}; };
const struct cmd_entry cmd_start_server_entry = { /* ARGSUSED */
"start-server", "start", int
"", 0, 0, cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
"",
CMD_STARTSERVER,
cmd_kill_server_exec
};
enum cmd_retval
cmd_kill_server_exec(struct cmd *self, unused struct cmd_q *cmdq)
{ {
if (self->entry == &cmd_kill_server_entry) kill(getpid(), SIGTERM);
kill(getpid(), SIGTERM);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,35 +27,29 @@
* Note this deliberately has no alias to make it hard to hit by accident. * Note this deliberately has no alias to make it hard to hit by accident.
*/ */
enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmd_q *); int cmd_kill_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_session_entry = { const struct cmd_entry cmd_kill_session_entry = {
"kill-session", NULL, "kill-session", NULL,
"at:", 0, 0, "t:", 0, 0,
"[-a] " CMD_TARGET_SESSION_USAGE, CMD_TARGET_SESSION_USAGE,
0, 0,
NULL,
NULL,
cmd_kill_session_exec cmd_kill_session_exec
}; };
enum cmd_retval int
cmd_kill_session_exec(struct cmd *self, struct cmd_q *cmdq) cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s, *s2, *s3; struct session *s;
if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL) if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
if (args_has(args, 'a')) { server_destroy_session(s);
RB_FOREACH_SAFE(s2, sessions, &sessions, s3) { session_destroy(s);
if (s != s2) {
server_destroy_session(s2); return (0);
session_destroy(s2);
}
}
} else {
server_destroy_session(s);
session_destroy(s);
}
return (CMD_RETURN_NORMAL);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,59 +24,29 @@
* Destroy window. * Destroy window.
*/ */
enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmd_q *); int cmd_kill_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_window_entry = { const struct cmd_entry cmd_kill_window_entry = {
"kill-window", "killw", "kill-window", "killw",
"at:", 0, 0, "t:", 0, 0,
"[-a] " CMD_TARGET_WINDOW_USAGE, CMD_TARGET_WINDOW_USAGE,
0, 0,
NULL,
NULL,
cmd_kill_window_exec cmd_kill_window_exec
}; };
const struct cmd_entry cmd_unlink_window_entry = { int
"unlink-window", "unlinkw", cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx)
"kt:", 0, 0,
"[-k] " CMD_TARGET_WINDOW_USAGE,
0,
cmd_kill_window_exec
};
enum cmd_retval
cmd_kill_window_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl, *wl2, *wl3; struct winlink *wl;
struct window *w;
struct session *s;
struct session_group *sg;
u_int references;
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL) if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
w = wl->window;
if (self->entry == &cmd_unlink_window_entry) {
sg = session_group_find(s);
if (sg != NULL)
references = session_group_count(sg);
else
references = 1;
if (!args_has(self->args, 'k') && w->references == references) {
cmdq_error(cmdq, "window only linked to one session");
return (CMD_RETURN_ERROR);
}
server_unlink_window(s, wl);
} else {
if (args_has(args, 'a')) {
RB_FOREACH_SAFE(wl2, winlinks, &s->windows, wl3) {
if (wl != wl2)
server_kill_window(wl2->window);
}
} else
server_kill_window(wl->window);
}
server_kill_window(wl->window);
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL);
return (0);
} }

65
cmd-link-window.c Normal file
View File

@@ -0,0 +1,65 @@
/* $Id$ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Link a window into another session.
*/
int cmd_link_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_link_window_entry = {
"link-window", "linkw",
"dks:t:", 0, 0,
"[-dk] " CMD_SRCDST_WINDOW_USAGE,
0,
NULL,
NULL,
cmd_link_window_exec
};
int
cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *src, *dst;
struct winlink *wl;
char *cause;
int idx, kflag, dflag;
if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL)
return (-1);
if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2)
return (-1);
kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd');
if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) {
ctx->error(ctx, "can't link window: %s", cause);
xfree(cause);
return (-1);
}
recalculate_sizes();
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -27,42 +26,33 @@
* List paste buffers. * List paste buffers.
*/ */
#define LIST_BUFFERS_TEMPLATE \ int cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *);
"#{buffer_name}: #{buffer_size} bytes: \"#{buffer_sample}\""
enum cmd_retval cmd_list_buffers_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_list_buffers_entry = { const struct cmd_entry cmd_list_buffers_entry = {
"list-buffers", "lsb", "list-buffers", "lsb",
"F:", 0, 0, "", 0, 0,
"[-F format]", "",
0, 0,
NULL,
NULL,
cmd_list_buffers_exec cmd_list_buffers_exec
}; };
enum cmd_retval /* ARGSUSED */
cmd_list_buffers_exec(unused struct cmd *self, struct cmd_q *cmdq) int
cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args;
struct paste_buffer *pb; struct paste_buffer *pb;
struct format_tree *ft; u_int idx;
char *line; char *tmp;
const char *template;
if ((template = args_get(args, 'F')) == NULL) idx = 0;
template = LIST_BUFFERS_TEMPLATE; while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) {
tmp = paste_print(pb, 50);
pb = NULL; ctx->print(ctx,
while ((pb = paste_walk(pb)) != NULL) { "%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp);
ft = format_create(); xfree(tmp);
format_defaults_paste_buffer(ft, pb, 0);
line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line);
free(line);
format_free(ft);
} }
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
@@ -28,60 +27,51 @@
* List all clients. * List all clients.
*/ */
#define LIST_CLIENTS_TEMPLATE \ int cmd_list_clients_exec(struct cmd *, struct cmd_ctx *);
"#{client_tty}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}]" \
"#{?client_utf8, (utf8),} #{?client_readonly, (ro),}"
enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_list_clients_entry = { const struct cmd_entry cmd_list_clients_entry = {
"list-clients", "lsc", "list-clients", "lsc",
"F:t:", 0, 0, "t:", 0, 0,
"[-F format] " CMD_TARGET_SESSION_USAGE, CMD_TARGET_SESSION_USAGE,
CMD_READONLY, 0,
NULL,
NULL,
cmd_list_clients_exec cmd_list_clients_exec
}; };
enum cmd_retval /* ARGSUSED */
cmd_list_clients_exec(struct cmd *self, struct cmd_q *cmdq) int
cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c;
struct session *s; struct session *s;
struct format_tree *ft; u_int i;
const char *template; const char *s_utf8;
u_int i;
char *line;
if (args_has(args, 't')) { if (args_has(args, 't')) {
s = cmd_find_session(cmdq, args_get(args, 't'), 0); s = cmd_find_session(ctx, args_get(args, 't'), 0);
if (s == NULL) if (s == NULL)
return (CMD_RETURN_ERROR); return (-1);
} else } else
s = NULL; s = NULL;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_CLIENTS_TEMPLATE;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL) if (c == NULL || c->session == NULL)
continue; continue;
if (c->tty.flags & TTY_UTF8)
s_utf8 = " (utf8)";
else
s_utf8 = "";
if (s != NULL && s != c->session) if (s != NULL && s != c->session)
continue; continue;
ctx->print(ctx, "%s: %s [%ux%u %s]%s", c->tty.path,
ft = format_create(); c->session->name, c->tty.sx, c->tty.sy,
format_add(ft, "line", "%u", i); c->tty.termname, s_utf8);
format_defaults(ft, c, NULL, NULL, NULL);
line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line);
free(line);
format_free(ft);
} }
return (CMD_RETURN_NORMAL); return (0);
} }

49
cmd-list-commands.c Normal file
View File

@@ -0,0 +1,49 @@
/* $Id$ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* List all commands with usages.
*/
int cmd_list_commands_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_commands_entry = {
"list-commands", "lscm",
"", 0, 0,
"",
0,
NULL,
NULL,
cmd_list_commands_exec
};
/* ARGSUSED */
int
cmd_list_commands_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{
const struct cmd_entry **entryp;
for (entryp = cmd_table; *entryp != NULL; entryp++)
ctx->print(ctx, "%s %s", (*entryp)->name, (*entryp)->usage);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,29 +26,22 @@
* List key bindings. * List key bindings.
*/ */
enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmd_q *); int cmd_list_keys_exec(struct cmd *, struct cmd_ctx *);
enum cmd_retval cmd_list_keys_table(struct cmd *, struct cmd_q *); int cmd_list_keys_table(struct cmd *, struct cmd_ctx *);
enum cmd_retval cmd_list_keys_commands(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_list_keys_entry = { const struct cmd_entry cmd_list_keys_entry = {
"list-keys", "lsk", "list-keys", "lsk",
"t:", 0, 0, "t:", 0, 0,
"[-t key-table]", "[-t key-table]",
0, 0,
NULL,
NULL,
cmd_list_keys_exec cmd_list_keys_exec
}; };
const struct cmd_entry cmd_list_commands_entry = { int
"list-commands", "lscm", cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
"", 0, 0,
"",
0,
cmd_list_keys_exec
};
enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct key_binding *bd; struct key_binding *bd;
@@ -57,15 +50,13 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
size_t used; size_t used;
int width, keywidth; int width, keywidth;
if (self->entry == &cmd_list_commands_entry)
return (cmd_list_keys_commands(self, cmdq));
if (args_has(args, 't')) if (args_has(args, 't'))
return (cmd_list_keys_table(self, cmdq)); return (cmd_list_keys_table(self, ctx));
width = 0; width = 0;
*flags = '\0';
RB_FOREACH(bd, key_bindings, &key_bindings) { SPLAY_FOREACH(bd, key_bindings, &key_bindings) {
key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); key = key_string_lookup_key(bd->key & ~KEYC_PREFIX);
if (key == NULL) if (key == NULL)
continue; continue;
@@ -82,12 +73,11 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
width = keywidth; width = keywidth;
} }
RB_FOREACH(bd, key_bindings, &key_bindings) { SPLAY_FOREACH(bd, key_bindings, &key_bindings) {
key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); key = key_string_lookup_key(bd->key & ~KEYC_PREFIX);
if (key == NULL) if (key == NULL)
continue; continue;
*flags = '\0';
if (!(bd->key & KEYC_PREFIX)) { if (!(bd->key & KEYC_PREFIX)) {
if (bd->can_repeat) if (bd->can_repeat)
xsnprintf(flags, sizeof flags, "-rn "); xsnprintf(flags, sizeof flags, "-rn ");
@@ -102,14 +92,14 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
continue; continue;
cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used); cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used);
cmdq_print(cmdq, "bind-key %s", tmp); ctx->print(ctx, "bind-key %s", tmp);
} }
return (CMD_RETURN_NORMAL); return (0);
} }
enum cmd_retval int
cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq) cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
const char *tablename; const char *tablename;
@@ -120,13 +110,13 @@ cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq)
tablename = args_get(args, 't'); tablename = args_get(args, 't');
if ((mtab = mode_key_findtable(tablename)) == NULL) { if ((mtab = mode_key_findtable(tablename)) == NULL) {
cmdq_error(cmdq, "unknown key table: %s", tablename); ctx->error(ctx, "unknown key table: %s", tablename);
return (CMD_RETURN_ERROR); return (-1);
} }
width = 0; width = 0;
any_mode = 0; any_mode = 0;
RB_FOREACH(mbind, mode_key_tree, mtab->tree) { SPLAY_FOREACH(mbind, mode_key_tree, mtab->tree) {
key = key_string_lookup_key(mbind->key); key = key_string_lookup_key(mbind->key);
if (key == NULL) if (key == NULL)
continue; continue;
@@ -139,7 +129,7 @@ cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq)
width = keywidth; width = keywidth;
} }
RB_FOREACH(mbind, mode_key_tree, mtab->tree) { SPLAY_FOREACH(mbind, mode_key_tree, mtab->tree) {
key = key_string_lookup_key(mbind->key); key = key_string_lookup_key(mbind->key);
if (key == NULL) if (key == NULL)
continue; continue;
@@ -149,33 +139,11 @@ cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq)
mode = "c"; mode = "c";
cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd); cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd);
if (cmdstr != NULL) { if (cmdstr != NULL) {
cmdq_print(cmdq, "bind-key -%st %s%s %*s %s%s%s%s", ctx->print(ctx, "bind-key -%st %s%s %*s %s",
mode, any_mode && *mode == '\0' ? " " : "", mode, any_mode && *mode == '\0' ? " " : "",
mtab->name, (int) width, key, cmdstr, mtab->name, (int) width, key, cmdstr);
mbind->arg != NULL ? " \"" : "",
mbind->arg != NULL ? mbind->arg : "",
mbind->arg != NULL ? "\"": "");
} }
} }
return (CMD_RETURN_NORMAL); return (0);
}
enum cmd_retval
cmd_list_keys_commands(unused struct cmd *self, struct cmd_q *cmdq)
{
const struct cmd_entry **entryp;
const struct cmd_entry *entry;
for (entryp = cmd_table; *entryp != NULL; entryp++) {
entry = *entryp;
if (entry->alias == NULL) {
cmdq_print(cmdq, "%s %s", entry->name, entry->usage);
continue;
}
cmdq_print(cmdq, "%s (%s) %s", entry->name, entry->alias,
entry->usage);
}
return (CMD_RETURN_NORMAL);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -27,114 +26,112 @@
* List panes on given window. * List panes on given window.
*/ */
enum cmd_retval cmd_list_panes_exec(struct cmd *, struct cmd_q *); int cmd_list_panes_exec(struct cmd *, struct cmd_ctx *);
void cmd_list_panes_server(struct cmd *, struct cmd_q *); void cmd_list_panes_server(struct cmd_ctx *);
void cmd_list_panes_session( void cmd_list_panes_session(struct session *, struct cmd_ctx *, int);
struct cmd *, struct session *, struct cmd_q *, int); void cmd_list_panes_window(
void cmd_list_panes_window(struct cmd *, struct session *, struct winlink *, struct cmd_ctx *, int);
struct session *, struct winlink *, struct cmd_q *, int);
const struct cmd_entry cmd_list_panes_entry = { const struct cmd_entry cmd_list_panes_entry = {
"list-panes", "lsp", "list-panes", "lsp",
"asF:t:", 0, 0, "ast:", 0, 0,
"[-as] [-F format] " CMD_TARGET_WINDOW_USAGE, "[-as] [-t target]",
0, 0,
NULL,
NULL,
cmd_list_panes_exec cmd_list_panes_exec
}; };
enum cmd_retval int
cmd_list_panes_exec(struct cmd *self, struct cmd_q *cmdq) cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s;
struct winlink *wl; struct winlink *wl;
if (args_has(args, 'a')) if (args_has(args, 'a'))
cmd_list_panes_server(self, cmdq); cmd_list_panes_server(ctx);
else if (args_has(args, 's')) { else if (args_has(args, 's')) {
s = cmd_find_session(cmdq, args_get(args, 't'), 0); s = cmd_find_session(ctx, args_get(args, 't'), 0);
if (s == NULL) if (s == NULL)
return (CMD_RETURN_ERROR); return (-1);
cmd_list_panes_session(self, s, cmdq, 1); cmd_list_panes_session(s, ctx, 1);
} else { } else {
wl = cmd_find_window(cmdq, args_get(args, 't'), &s); wl = cmd_find_window(ctx, args_get(args, 't'), &s);
if (wl == NULL) if (wl == NULL)
return (CMD_RETURN_ERROR); return (-1);
cmd_list_panes_window(self, s, wl, cmdq, 0); cmd_list_panes_window(s, wl, ctx, 0);
} }
return (CMD_RETURN_NORMAL); return (0);
} }
void void
cmd_list_panes_server(struct cmd *self, struct cmd_q *cmdq) cmd_list_panes_server(struct cmd_ctx *ctx)
{ {
struct session *s; struct session *s;
RB_FOREACH(s, sessions, &sessions) RB_FOREACH(s, sessions, &sessions)
cmd_list_panes_session(self, s, cmdq, 2); cmd_list_panes_session(s, ctx, 2);
} }
void void
cmd_list_panes_session( cmd_list_panes_session(struct session *s, struct cmd_ctx *ctx, int type)
struct cmd *self, struct session *s, struct cmd_q *cmdq, int type)
{ {
struct winlink *wl; struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows) RB_FOREACH(wl, winlinks, &s->windows)
cmd_list_panes_window(self, s, wl, cmdq, type); cmd_list_panes_window(s, wl, ctx, type);
} }
void void
cmd_list_panes_window(struct cmd *self, cmd_list_panes_window(
struct session *s, struct winlink *wl, struct cmd_q *cmdq, int type) struct session *s, struct winlink *wl, struct cmd_ctx *ctx, int type)
{ {
struct args *args = self->args;
struct window_pane *wp; struct window_pane *wp;
u_int n; struct grid *gd;
struct format_tree *ft; struct grid_line *gl;
const char *template; u_int i, n;
char *line; unsigned long long size;
template = args_get(args, 'F');
if (template == NULL) {
switch (type) {
case 0:
template = "#{pane_index}: "
"[#{pane_width}x#{pane_height}] [history "
"#{history_size}/#{history_limit}, "
"#{history_bytes} bytes] #{pane_id}"
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
break;
case 1:
template = "#{window_index}.#{pane_index}: "
"[#{pane_width}x#{pane_height}] [history "
"#{history_size}/#{history_limit}, "
"#{history_bytes} bytes] #{pane_id}"
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
break;
case 2:
template = "#{session_name}:#{window_index}.#{pane_index}: "
"[#{pane_width}x#{pane_height}] [history "
"#{history_size}/#{history_limit}, "
"#{history_bytes} bytes] #{pane_id}"
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
break;
}
}
n = 0; n = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) { TAILQ_FOREACH(wp, &wl->window->panes, entry) {
ft = format_create(); gd = wp->base.grid;
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, wp);
line = format_expand(ft, template); size = 0;
cmdq_print(cmdq, "%s", line); for (i = 0; i < gd->hsize; i++) {
free(line); gl = &gd->linedata[i];
size += gl->cellsize * sizeof *gl->celldata;
size += gl->utf8size * sizeof *gl->utf8data;
}
size += gd->hsize * sizeof *gd->linedata;
format_free(ft); switch (type) {
case 0:
ctx->print(ctx,
"%u: [%ux%u] [history %u/%u, %llu bytes] %%%u%s%s",
n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size,
wp->id, wp == wp->window->active ? " (active)" : "",
wp->fd == -1 ? " (dead)" : "");
break;
case 1:
ctx->print(ctx,
"%d.%u: [%ux%u] [history %u/%u, %llu bytes] "
"%%%u%s%s", wl->idx,
n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size,
wp->id, wp == wp->window->active ? " (active)" : "",
wp->fd == -1 ? " (dead)" : "");
break;
case 2:
ctx->print(ctx,
"%s:%d.%u: [%ux%u] [history %u/%u, %llu bytes] "
"%%%u%s%s", s->name, wl->idx,
n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size,
wp->id, wp == wp->window->active ? " (active)" : "",
wp->fd == -1 ? " (dead)" : "");
break;
}
n++; n++;
} }
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
@@ -28,50 +27,45 @@
* List all sessions. * List all sessions.
*/ */
#define LIST_SESSIONS_TEMPLATE \ int cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *);
"#{session_name}: #{session_windows} windows " \
"(created #{session_created_string}) " \
"[#{session_width}x#{session_height}]" \
"#{?session_grouped, (group ,}" \
"#{session_group}#{?session_grouped,),}" \
"#{?session_attached, (attached),}"
enum cmd_retval cmd_list_sessions_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_list_sessions_entry = { const struct cmd_entry cmd_list_sessions_entry = {
"list-sessions", "ls", "list-sessions", "ls",
"F:", 0, 0, "", 0, 0,
"[-F format]", "",
0, 0,
NULL,
NULL,
cmd_list_sessions_exec cmd_list_sessions_exec
}; };
enum cmd_retval /* ARGSUSED */
cmd_list_sessions_exec(struct cmd *self, struct cmd_q *cmdq) int
cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args;
struct session *s; struct session *s;
u_int n; struct session_group *sg;
struct format_tree *ft; char *tim, tmp[64];
const char *template; u_int idx;
char *line; time_t t;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_SESSIONS_TEMPLATE;
n = 0;
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
ft = format_create(); sg = session_group_find(s);
format_add(ft, "line", "%u", n); if (sg == NULL)
format_defaults(ft, NULL, s, NULL, NULL); *tmp = '\0';
else {
idx = session_group_index(sg);
xsnprintf(tmp, sizeof tmp, " (group %u)", idx);
}
line = format_expand(ft, template); t = s->creation_time.tv_sec;
cmdq_print(cmdq, "%s", line); tim = ctime(&t);
free(line); *strchr(tim, '\n') = '\0';
format_free(ft); ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s%s",
n++; s->name, winlink_count(&s->windows), tim, s->sx, s->sy,
tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)");
} }
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -27,93 +26,67 @@
* List windows on given session. * List windows on given session.
*/ */
#define LIST_WINDOWS_TEMPLATE \ int cmd_list_windows_exec(struct cmd *, struct cmd_ctx *);
"#{window_index}: #{window_name}#{window_flags} " \
"(#{window_panes} panes) " \
"[#{window_width}x#{window_height}] " \
"[layout #{window_layout}] #{window_id}" \
"#{?window_active, (active),}";
#define LIST_WINDOWS_WITH_SESSION_TEMPLATE \
"#{session_name}:" \
"#{window_index}: #{window_name}#{window_flags} " \
"(#{window_panes} panes) " \
"[#{window_width}x#{window_height}] "
enum cmd_retval cmd_list_windows_exec(struct cmd *, struct cmd_q *); void cmd_list_windows_server(struct cmd_ctx *);
void cmd_list_windows_session(struct session *, struct cmd_ctx *, int);
void cmd_list_windows_server(struct cmd *, struct cmd_q *);
void cmd_list_windows_session(struct cmd *, struct session *,
struct cmd_q *, int);
const struct cmd_entry cmd_list_windows_entry = { const struct cmd_entry cmd_list_windows_entry = {
"list-windows", "lsw", "list-windows", "lsw",
"F:at:", 0, 0, "at:", 0, 0,
"[-a] [-F format] " CMD_TARGET_SESSION_USAGE, "[-a] " CMD_TARGET_SESSION_USAGE,
0, 0,
NULL,
NULL,
cmd_list_windows_exec cmd_list_windows_exec
}; };
enum cmd_retval int
cmd_list_windows_exec(struct cmd *self, struct cmd_q *cmdq) cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s;
if (args_has(args, 'a')) if (args_has(args, 'a'))
cmd_list_windows_server(self, cmdq); cmd_list_windows_server(ctx);
else { else {
s = cmd_find_session(cmdq, args_get(args, 't'), 0); s = cmd_find_session(ctx, args_get(args, 't'), 0);
if (s == NULL) if (s == NULL)
return (CMD_RETURN_ERROR); return (-1);
cmd_list_windows_session(self, s, cmdq, 0); cmd_list_windows_session(s, ctx, 0);
} }
return (CMD_RETURN_NORMAL); return (0);
} }
void void
cmd_list_windows_server(struct cmd *self, struct cmd_q *cmdq) cmd_list_windows_server(struct cmd_ctx *ctx)
{ {
struct session *s; struct session *s;
RB_FOREACH(s, sessions, &sessions) RB_FOREACH(s, sessions, &sessions)
cmd_list_windows_session(self, s, cmdq, 1); cmd_list_windows_session(s, ctx, 1);
} }
void void
cmd_list_windows_session( cmd_list_windows_session(struct session *s, struct cmd_ctx *ctx, int type)
struct cmd *self, struct session *s, struct cmd_q *cmdq, int type)
{ {
struct args *args = self->args; struct winlink *wl;
struct winlink *wl; char *layout;
u_int n;
struct format_tree *ft;
const char *template;
char *line;
template = args_get(args, 'F');
if (template == NULL) {
switch (type) {
case 0:
template = LIST_WINDOWS_TEMPLATE;
break;
case 1:
template = LIST_WINDOWS_WITH_SESSION_TEMPLATE;
break;
}
}
n = 0;
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
ft = format_create(); layout = layout_dump(wl->window);
format_add(ft, "line", "%u", n); if (type) {
format_defaults(ft, NULL, s, wl, NULL); ctx->print(ctx, "%s:%d: %s [%ux%u] [layout %s]%s",
s->name, wl->idx, wl->window->name, wl->window->sx,
line = format_expand(ft, template); wl->window->sy, layout,
cmdq_print(cmdq, "%s", line); wl == s->curw ? " (active)" : "");
free(line); } else {
ctx->print(ctx, "%d: %s [%ux%u] [layout %s]%s",
format_free(ft); wl->idx, wl->window->name, wl->window->sx,
n++; wl->window->sy, layout,
wl == s->curw ? " (active)" : "");
}
xfree(layout);
} }
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,14 +18,12 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
struct cmd_list * struct cmd_list *
cmd_list_parse(int argc, char **argv, const char *file, u_int line, cmd_list_parse(int argc, char **argv, char **cause)
char **cause)
{ {
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd *cmd; struct cmd *cmd;
@@ -35,7 +33,7 @@ cmd_list_parse(int argc, char **argv, const char *file, u_int line,
copy_argv = cmd_copy_argv(argc, argv); copy_argv = cmd_copy_argv(argc, argv);
cmdlist = xcalloc(1, sizeof *cmdlist); cmdlist = xmalloc(sizeof *cmdlist);
cmdlist->references = 1; cmdlist->references = 1;
TAILQ_INIT(&cmdlist->list); TAILQ_INIT(&cmdlist->list);
@@ -56,7 +54,7 @@ cmd_list_parse(int argc, char **argv, const char *file, u_int line,
if (arglen != 1) if (arglen != 1)
new_argc++; new_argc++;
cmd = cmd_parse(new_argc, new_argv, file, line, cause); cmd = cmd_parse(new_argc, new_argv, cause);
if (cmd == NULL) if (cmd == NULL)
goto bad; goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry); TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
@@ -65,8 +63,7 @@ cmd_list_parse(int argc, char **argv, const char *file, u_int line,
} }
if (lastsplit != argc) { if (lastsplit != argc) {
cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit, cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit, cause);
file, line, cause);
if (cmd == NULL) if (cmd == NULL)
goto bad; goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry); TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
@@ -81,29 +78,63 @@ bad:
return (NULL); return (NULL);
} }
int
cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx)
{
struct cmd *cmd;
int n, retval;
retval = 0;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
if ((n = cmd_exec(cmd, ctx)) == -1)
return (-1);
/*
* A 1 return value means the command client is being attached
* (sent MSG_READY).
*/
if (n == 1) {
retval = 1;
/*
* The command client has been attached, so mangle the
* context to treat any following commands as if they
* were called from inside.
*/
if (ctx->curclient == NULL) {
ctx->curclient = ctx->cmdclient;
ctx->cmdclient = NULL;
ctx->error = key_bindings_error;
ctx->print = key_bindings_print;
ctx->info = key_bindings_info;
}
}
}
return (retval);
}
void void
cmd_list_free(struct cmd_list *cmdlist) cmd_list_free(struct cmd_list *cmdlist)
{ {
struct cmd *cmd, *cmd1; struct cmd *cmd;
if (--cmdlist->references != 0) if (--cmdlist->references != 0)
return; return;
TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) { while (!TAILQ_EMPTY(&cmdlist->list)) {
cmd = TAILQ_FIRST(&cmdlist->list);
TAILQ_REMOVE(&cmdlist->list, cmd, qentry); TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
args_free(cmd->args); cmd_free(cmd);
free(cmd->file);
free(cmd);
} }
xfree(cmdlist);
free(cmdlist);
} }
size_t size_t
cmd_list_print(struct cmd_list *cmdlist, char *buf, size_t len) cmd_list_print(struct cmd_list *cmdlist, char *buf, size_t len)
{ {
struct cmd *cmd; struct cmd *cmd;
size_t off, used; size_t off;
off = 0; off = 0;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
@@ -112,12 +143,8 @@ cmd_list_print(struct cmd_list *cmdlist, char *buf, size_t len)
off += cmd_print(cmd, buf + off, len - off); off += cmd_print(cmd, buf + off, len - off);
if (off >= len) if (off >= len)
break; break;
if (TAILQ_NEXT(cmd, qentry) != NULL) { if (TAILQ_NEXT(cmd, qentry) != NULL)
used = xsnprintf(buf + off, len - off, " ; "); off += xsnprintf(buf + off, len - off, " ; ");
if (used > len - off)
used = len - off;
off += used;
}
} }
return (off); return (off);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -19,7 +19,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -28,61 +27,75 @@
#include "tmux.h" #include "tmux.h"
/* /*
* Loads a paste buffer from a file. * Loads a session paste buffer from a file.
*/ */
enum cmd_retval cmd_load_buffer_exec(struct cmd *, struct cmd_q *); int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_load_buffer_callback(struct client *, int, void *); void cmd_load_buffer_callback(struct client *, void *);
const struct cmd_entry cmd_load_buffer_entry = { const struct cmd_entry cmd_load_buffer_entry = {
"load-buffer", "loadb", "load-buffer", "loadb",
"b:", 1, 1, "b:", 1, 1,
CMD_BUFFER_USAGE " path", CMD_BUFFER_USAGE " path",
0, 0,
NULL,
NULL,
cmd_load_buffer_exec cmd_load_buffer_exec
}; };
enum cmd_retval int
cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq) cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmdq->client; struct client *c = ctx->cmdclient;
struct session *s;
FILE *f; FILE *f;
const char *path, *bufname; const char *path;
char *pdata, *new_pdata, *cause; char *pdata, *new_pdata, *cause;
size_t psize; size_t psize;
int ch, error, cwd, fd; u_int limit;
int ch, buffer;
int *buffer_ptr;
bufname = NULL; if (!args_has(args, 'b'))
if (args_has(args, 'b')) buffer = -1;
bufname = args_get(args, 'b'); else {
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
ctx->error(ctx, "buffer %s", cause);
xfree(cause);
return (-1);
}
}
path = args->argv[0]; path = args->argv[0];
if (strcmp(path, "-") == 0) { if (strcmp(path, "-") == 0) {
error = server_set_stdin_callback(c, cmd_load_buffer_callback, if (c == NULL) {
(void *)bufname, &cause); ctx->error(ctx, "%s: can't read from stdin", path);
if (error != 0) { return (-1);
cmdq_error(cmdq, "%s: %s", path, cause);
free(cause);
return (CMD_RETURN_ERROR);
} }
return (CMD_RETURN_WAIT); if (c->flags & CLIENT_TERMINAL) {
ctx->error(ctx, "%s: stdin is a tty", path);
return (-1);
}
if (c->stdin_fd == -1) {
ctx->error(ctx, "%s: can't read from stdin", path);
return (-1);
}
buffer_ptr = xmalloc(sizeof *buffer_ptr);
*buffer_ptr = buffer;
c->stdin_data = buffer_ptr;
c->stdin_callback = cmd_load_buffer_callback;
c->references++;
bufferevent_enable(c->stdin_event, EV_READ);
return (1);
} }
if (c != NULL && c->session == NULL) if ((f = fopen(path, "rb")) == NULL) {
cwd = c->cwd; ctx->error(ctx, "%s: %s", path, strerror(errno));
else if ((s = cmd_current_session(cmdq, 0)) != NULL) return (-1);
cwd = s->cwd;
else
cwd = AT_FDCWD;
if ((fd = openat(cwd, path, O_RDONLY)) == -1 ||
(f = fdopen(fd, "rb")) == NULL) {
if (fd != -1)
close(fd);
cmdq_error(cmdq, "%s: %s", path, strerror(errno));
return (CMD_RETURN_ERROR);
} }
pdata = NULL; pdata = NULL;
@@ -90,14 +103,14 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
while ((ch = getc(f)) != EOF) { while ((ch = getc(f)) != EOF) {
/* Do not let the server die due to memory exhaustion. */ /* Do not let the server die due to memory exhaustion. */
if ((new_pdata = realloc(pdata, psize + 2)) == NULL) { if ((new_pdata = realloc(pdata, psize + 2)) == NULL) {
cmdq_error(cmdq, "realloc error: %s", strerror(errno)); ctx->error(ctx, "realloc error: %s", strerror(errno));
goto error; goto error;
} }
pdata = new_pdata; pdata = new_pdata;
pdata[psize++] = ch; pdata[psize++] = ch;
} }
if (ferror(f)) { if (ferror(f)) {
cmdq_error(cmdq, "%s: read error", path); ctx->error(ctx, "%s: read error", path);
goto error; goto error;
} }
if (pdata != NULL) if (pdata != NULL)
@@ -105,53 +118,57 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
fclose(f); fclose(f);
if (paste_set(pdata, psize, bufname, &cause) != 0) { limit = options_get_number(&global_options, "buffer-limit");
cmdq_error(cmdq, "%s", cause); if (buffer == -1) {
free(pdata); paste_add(&global_buffers, pdata, psize, limit);
free(cause); return (0);
return (CMD_RETURN_ERROR); }
if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) {
ctx->error(ctx, "no buffer %d", buffer);
return (-1);
} }
return (CMD_RETURN_NORMAL); return (0);
error: error:
free(pdata); if (pdata != NULL)
xfree(pdata);
if (f != NULL) if (f != NULL)
fclose(f); fclose(f);
return (CMD_RETURN_ERROR); return (-1);
} }
void void
cmd_load_buffer_callback(struct client *c, int closed, void *data) cmd_load_buffer_callback(struct client *c, void *data)
{ {
const char *bufname = data; int *buffer = data;
char *pdata, *cause; char *pdata;
size_t psize; size_t psize;
u_int limit;
if (!closed) /*
* Event callback has already checked client is not dead and reduced
* its reference count. But tell it to exit.
*/
c->flags |= CLIENT_EXIT;
psize = EVBUFFER_LENGTH(c->stdin_event->input);
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) {
xfree(data);
return; return;
c->stdin_callback = NULL; }
bufferevent_read(c->stdin_event, pdata, psize);
c->references--;
if (c->flags & CLIENT_DEAD)
return;
psize = EVBUFFER_LENGTH(c->stdin_data);
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL)
goto out;
memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize);
pdata[psize] = '\0'; pdata[psize] = '\0';
evbuffer_drain(c->stdin_data, psize);
if (paste_set(pdata, psize, bufname, &cause) != 0) { limit = options_get_number(&global_options, "buffer-limit");
if (*buffer == -1)
paste_add(&global_buffers, pdata, psize, limit);
else if (paste_replace(&global_buffers, *buffer, pdata, psize) != 0) {
/* No context so can't use server_client_msg_error. */ /* No context so can't use server_client_msg_error. */
evbuffer_add_printf(c->stderr_data, "%s", cause); evbuffer_add_printf(
server_push_stderr(c); c->stderr_event->output, "no buffer %d\n", *buffer);
free(pdata); bufferevent_enable(c->stderr_event, EV_WRITE);
free(cause);
} }
out: xfree(data);
cmdq_continue(c->cmdq);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,19 +18,25 @@
#include <sys/types.h> #include <sys/types.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Lock commands. * Lock commands.
*/ */
enum cmd_retval cmd_lock_server_exec(struct cmd *, struct cmd_q *); int cmd_lock_server_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_lock_server_entry = { const struct cmd_entry cmd_lock_server_entry = {
"lock-server", "lock", "lock-server", "lock",
"", 0, 0, "", 0, 0,
"", "",
0, 0,
NULL,
NULL,
cmd_lock_server_exec cmd_lock_server_exec
}; };
@@ -39,6 +45,8 @@ const struct cmd_entry cmd_lock_session_entry = {
"t:", 0, 0, "t:", 0, 0,
CMD_TARGET_SESSION_USAGE, CMD_TARGET_SESSION_USAGE,
0, 0,
NULL,
NULL,
cmd_lock_server_exec cmd_lock_server_exec
}; };
@@ -47,11 +55,14 @@ const struct cmd_entry cmd_lock_client_entry = {
"t:", 0, 0, "t:", 0, 0,
CMD_TARGET_CLIENT_USAGE, CMD_TARGET_CLIENT_USAGE,
0, 0,
NULL,
NULL,
cmd_lock_server_exec cmd_lock_server_exec
}; };
enum cmd_retval /* ARGSUSED */
cmd_lock_server_exec(struct cmd *self, unused struct cmd_q *cmdq) int
cmd_lock_server_exec(struct cmd *self, unused struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c;
@@ -60,17 +71,15 @@ cmd_lock_server_exec(struct cmd *self, unused struct cmd_q *cmdq)
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) {
s = cmd_find_session(cmdq, args_get(args, 't'), 0); if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
if (s == NULL) return (-1);
return (CMD_RETURN_ERROR);
server_lock_session(s); server_lock_session(s);
} else { } else {
c = cmd_find_client(cmdq, args_get(args, 't'), 0); if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
if (c == NULL) return (-1);
return (CMD_RETURN_ERROR);
server_lock_client(c); server_lock_client(c);
} }
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,60 +26,41 @@
* Move a window. * Move a window.
*/ */
enum cmd_retval cmd_move_window_exec(struct cmd *, struct cmd_q *); int cmd_move_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_move_window_entry = { const struct cmd_entry cmd_move_window_entry = {
"move-window", "movew", "move-window", "movew",
"dkrs:t:", 0, 0,
"[-dkr] " CMD_SRCDST_WINDOW_USAGE,
0,
cmd_move_window_exec
};
const struct cmd_entry cmd_link_window_entry = {
"link-window", "linkw",
"dks:t:", 0, 0, "dks:t:", 0, 0,
"[-dk] " CMD_SRCDST_WINDOW_USAGE, "[-dk] " CMD_SRCDST_WINDOW_USAGE,
0, 0,
NULL,
NULL,
cmd_move_window_exec cmd_move_window_exec
}; };
enum cmd_retval int
cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *src, *dst, *s; struct session *src, *dst;
struct winlink *wl; struct winlink *wl;
char *cause; char *cause;
int idx, kflag, dflag; int idx, kflag, dflag;
if (args_has(args, 'r')) { if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL)
s = cmd_find_session(cmdq, args_get(args, 't'), 0); return (-1);
if (s == NULL) if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2)
return (CMD_RETURN_ERROR); return (-1);
session_renumber_windows(s);
recalculate_sizes();
return (CMD_RETURN_NORMAL);
}
if ((wl = cmd_find_window(cmdq, args_get(args, 's'), &src)) == NULL)
return (CMD_RETURN_ERROR);
if ((idx = cmd_find_index(cmdq, args_get(args, 't'), &dst)) == -2)
return (CMD_RETURN_ERROR);
kflag = args_has(self->args, 'k'); kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd'); dflag = args_has(self->args, 'd');
if (server_link_window(src, wl, dst, idx, kflag, !dflag, if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) {
&cause) != 0) { ctx->error(ctx, "can't move window: %s", cause);
cmdq_error(cmdq, "can't link window: %s", cause); xfree(cause);
free(cause); return (-1);
return (CMD_RETURN_ERROR);
} }
if (self->entry == &cmd_move_window_entry) server_unlink_window(src, wl);
server_unlink_window(src, wl);
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,8 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <errno.h> #include <pwd.h>
#include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <termios.h> #include <termios.h>
@@ -31,119 +30,86 @@
* Create a new session and attach to the current terminal unless -d is given. * Create a new session and attach to the current terminal unless -d is given.
*/ */
#define NEW_SESSION_TEMPLATE "#{session_name}:" int cmd_new_session_check(struct args *);
int cmd_new_session_exec(struct cmd *, struct cmd_ctx *);
enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_new_session_entry = { const struct cmd_entry cmd_new_session_entry = {
"new-session", "new", "new-session", "new",
"Ac:dDF:n:Ps:t:x:y:", 0, -1, "dn:s:t:x:y:", 0, 1,
"[-AdDP] [-c start-directory] [-F format] [-n window-name] " "[-d] [-n window-name] [-s session-name] [-t target-session] "
"[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] " "[-x width] [-y height] [command]",
"[-y height] [command]", CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON,
CMD_STARTSERVER|CMD_CANTNEST, NULL,
cmd_new_session_check,
cmd_new_session_exec cmd_new_session_exec
}; };
const struct cmd_entry cmd_has_session_entry = { int
"has-session", "has", cmd_new_session_check(struct args *args)
"t:", 0, 0, {
CMD_TARGET_SESSION_USAGE, if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n')))
0, return (-1);
cmd_new_session_exec return (0);
}; }
enum cmd_retval int
cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmdq->client, *c0; struct session *s, *old_s, *groupwith;
struct session *s, *groupwith;
struct window *w; struct window *w;
struct window_pane *wp;
struct environ env; struct environ env;
struct termios tio, *tiop; struct termios tio, *tiop;
const char *newname, *target, *update, *errstr, *template; struct passwd *pw;
const char *path; const char *newname, *target, *update, *cwd, *errstr;
char **argv, *cmd, *cause, *cp; char *overrides, *cmd, *cause;
int detached, already_attached, idx, cwd, fd = -1; int detached, idx;
int argc; u_int sx, sy, i;
u_int sx, sy;
struct format_tree *ft;
struct environ_entry *envent;
if (self->entry == &cmd_has_session_entry) {
if (cmd_find_session(cmdq, args_get(args, 't'), 0) == NULL)
return (CMD_RETURN_ERROR);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) {
cmdq_error(cmdq, "command or window name given with target");
return (CMD_RETURN_ERROR);
}
newname = args_get(args, 's'); newname = args_get(args, 's');
if (newname != NULL) { if (newname != NULL) {
if (!session_check_name(newname)) { if (!session_check_name(newname)) {
cmdq_error(cmdq, "bad session name: %s", newname); ctx->error(ctx, "bad session name: %s", newname);
return (CMD_RETURN_ERROR); return (-1);
} }
if (session_find(newname) != NULL) { if (session_find(newname) != NULL) {
if (args_has(args, 'A')) { ctx->error(ctx, "duplicate session: %s", newname);
return (cmd_attach_session(cmdq, newname, return (-1);
args_has(args, 'D'), 0, NULL));
}
cmdq_error(cmdq, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR);
} }
} }
target = args_get(args, 't'); target = args_get(args, 't');
if (target != NULL) { if (target != NULL) {
groupwith = cmd_find_session(cmdq, target, 0); groupwith = cmd_find_session(ctx, target, 0);
if (groupwith == NULL) if (groupwith == NULL)
return (CMD_RETURN_ERROR); return (-1);
} else } else
groupwith = NULL; groupwith = NULL;
/*
* There are three cases:
*
* 1. If cmdclient is non-NULL, new-session has been called from the
* command-line - cmdclient is to become a new attached, interactive
* client. Unless -d is given, the terminal must be opened and then
* the client sent MSG_READY.
*
* 2. If cmdclient is NULL, new-session has been called from an
* existing client (such as a key binding).
*
* 3. Both are NULL, the command was in the configuration file. Treat
* this as if -d was given even if it was not.
*
* In all cases, a new additional session needs to be created and
* (unless -d) set as the current session for the client.
*/
/* Set -d if no client. */ /* Set -d if no client. */
detached = args_has(args, 'd'); detached = args_has(args, 'd');
if (c == NULL) if (ctx->cmdclient == NULL && ctx->curclient == NULL)
detached = 1; detached = 1;
/* Is this client already attached? */
already_attached = 0;
if (c != NULL && c->session != NULL)
already_attached = 1;
/* Get the new session working directory. */
if (args_has(args, 'c')) {
ft = format_create();
format_defaults(ft, cmd_find_client(cmdq, NULL, 1), NULL, NULL,
NULL);
cp = format_expand(ft, args_get(args, 'c'));
format_free(ft);
if (cp != NULL && *cp != '\0') {
fd = open(cp, O_RDONLY|O_DIRECTORY);
free(cp);
if (fd == -1) {
cmdq_error(cmdq, "bad working directory: %s",
strerror(errno));
return (CMD_RETURN_ERROR);
}
} else if (cp != NULL)
free(cp);
cwd = fd;
} else if (c != NULL && c->session == NULL)
cwd = c->cwd;
else if ((c0 = cmd_current_client(cmdq)) != NULL)
cwd = c0->session->cwd;
else {
fd = open(".", O_RDONLY);
cwd = fd;
}
/* /*
* Save the termios settings, part of which is used for new windows in * Save the termios settings, part of which is used for new windows in
* this session. * this session.
@@ -153,43 +119,66 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
* before opening the terminal as that calls tcsetattr() to prepare for * before opening the terminal as that calls tcsetattr() to prepare for
* tmux taking over. * tmux taking over.
*/ */
if (!detached && !already_attached && c->tty.fd != -1) { if (ctx->cmdclient != NULL && ctx->cmdclient->tty.fd != -1) {
if (tcgetattr(c->tty.fd, &tio) != 0) if (tcgetattr(ctx->cmdclient->tty.fd, &tio) != 0)
fatal("tcgetattr failed"); fatal("tcgetattr failed");
tiop = &tio; tiop = &tio;
} else } else
tiop = NULL; tiop = NULL;
/* Open the terminal if necessary. */ /* Open the terminal if necessary. */
if (!detached && !already_attached) { if (!detached && ctx->cmdclient != NULL) {
if (server_client_open(c, &cause) != 0) { if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) {
cmdq_error(cmdq, "open terminal failed: %s", cause); ctx->error(ctx, "not a terminal");
free(cause); return (-1);
goto error; }
overrides =
options_get_string(&global_s_options, "terminal-overrides");
if (tty_open(&ctx->cmdclient->tty, overrides, &cause) != 0) {
ctx->error(ctx, "open terminal failed: %s", cause);
xfree(cause);
return (-1);
} }
} }
/* Get the new session working directory. */
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
cwd = ctx->cmdclient->cwd;
else {
pw = getpwuid(getuid());
if (pw->pw_dir != NULL && *pw->pw_dir != '\0')
cwd = pw->pw_dir;
else
cwd = "/";
}
/* Find new session size. */ /* Find new session size. */
if (c != NULL) { if (detached) {
sx = c->tty.sx;
sy = c->tty.sy;
} else {
sx = 80; sx = 80;
sy = 24; sy = 24;
} if (args_has(args, 'x')) {
if (detached && args_has(args, 'x')) { sx = strtonum(
sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr); args_get(args, 'x'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
cmdq_error(cmdq, "width %s", errstr); ctx->error(ctx, "width %s", errstr);
goto error; return (-1);
}
} }
} if (args_has(args, 'y')) {
if (detached && args_has(args, 'y')) { sy = strtonum(
sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr); args_get(args, 'y'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
cmdq_error(cmdq, "height %s", errstr); ctx->error(ctx, "height %s", errstr);
goto error; return (-1);
}
} }
} else if (ctx->cmdclient != NULL) {
sx = ctx->cmdclient->tty.sx;
sy = ctx->cmdclient->tty.sy;
} else {
sx = ctx->curclient->tty.sx;
sy = ctx->curclient->tty.sy;
} }
if (sy > 0 && options_get_number(&global_s_options, "status")) if (sy > 0 && options_get_number(&global_s_options, "status"))
sy--; sy--;
@@ -199,51 +188,36 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
sy = 1; sy = 1;
/* Figure out the command for the new window. */ /* Figure out the command for the new window. */
argc = -1; if (target != NULL)
argv = NULL; cmd = NULL;
if (target == NULL && args->argc != 0) { else if (args->argc != 0)
argc = args->argc; cmd = args->argv[0];
argv = args->argv;
} else if (target == NULL) {
cmd = options_get_string(&global_s_options, "default-command");
if (cmd != NULL && *cmd != '\0') {
argc = 1;
argv = &cmd;
} else {
argc = 0;
argv = NULL;
}
}
path = NULL;
if (c != NULL && c->session == NULL)
envent = environ_find(&c->environ, "PATH");
else else
envent = environ_find(&global_environ, "PATH"); cmd = options_get_string(&global_s_options, "default-command");
if (envent != NULL)
path = envent->value;
/* Construct the environment. */ /* Construct the environment. */
environ_init(&env); environ_init(&env);
update = options_get_string(&global_s_options, "update-environment"); update = options_get_string(&global_s_options, "update-environment");
if (c != NULL) if (ctx->cmdclient != NULL)
environ_update(update, &c->environ, &env); environ_update(update, &ctx->cmdclient->environ, &env);
/* Create the new session. */ /* Create the new session. */
idx = -1 - options_get_number(&global_s_options, "base-index"); idx = -1 - options_get_number(&global_s_options, "base-index");
s = session_create(newname, argc, argv, path, cwd, &env, tiop, idx, sx, s = session_create(newname, cmd, cwd, &env, tiop, idx, sx, sy, &cause);
sy, &cause);
if (s == NULL) { if (s == NULL) {
cmdq_error(cmdq, "create session failed: %s", cause); ctx->error(ctx, "create session failed: %s", cause);
free(cause); xfree(cause);
goto error; return (-1);
} }
environ_free(&env); environ_free(&env);
/* Set the initial window name if one given. */ /* Set the initial window name if one given. */
if (argc >= 0 && args_has(args, 'n')) { if (cmd != NULL && args_has(args, 'n')) {
w = s->curw->window; w = s->curw->window;
window_set_name(w, args_get(args, 'n'));
xfree(w->name);
w->name = xstrdup(args_get(args, 'n'));
options_set_number(&w->options, "automatic-rename", 0); options_set_number(&w->options, "automatic-rename", 0);
} }
@@ -262,14 +236,23 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
* taking this session and needs to get MSG_READY and stay around. * taking this session and needs to get MSG_READY and stay around.
*/ */
if (!detached) { if (!detached) {
if (!already_attached) if (ctx->cmdclient != NULL) {
server_write_ready(c); server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
else if (c->session != NULL)
c->last_session = c->session; old_s = ctx->cmdclient->session;
c->session = s; if (old_s != NULL)
notify_attached_session_changed(c); ctx->cmdclient->last_session = old_s;
session_update_activity(s); ctx->cmdclient->session = s;
server_redraw_client(c); session_update_activity(s);
server_redraw_client(ctx->cmdclient);
} else {
old_s = ctx->curclient->session;
if (old_s != NULL)
ctx->curclient->last_session = old_s;
ctx->curclient->session = s;
session_update_activity(s);
server_redraw_client(ctx->curclient);
}
} }
recalculate_sizes(); recalculate_sizes();
server_update_socket(); server_update_socket();
@@ -278,34 +261,17 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
* If there are still configuration file errors to display, put the new * If there are still configuration file errors to display, put the new
* session's current window into more mode and display them now. * session's current window into more mode and display them now.
*/ */
if (cfg_finished) if (cfg_finished && !ARRAY_EMPTY(&cfg_causes)) {
cfg_show_causes(s); wp = s->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode);
/* Print if requested. */ window_copy_init_for_output(wp);
if (args_has(args, 'P')) { for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
if ((template = args_get(args, 'F')) == NULL) cause = ARRAY_ITEM(&cfg_causes, i);
template = NEW_SESSION_TEMPLATE; window_copy_add(wp, "%s", cause);
xfree(cause);
ft = format_create(); }
format_defaults(ft, cmd_find_client(cmdq, NULL, 1), s, NULL, ARRAY_FREE(&cfg_causes);
NULL);
cp = format_expand(ft, template);
cmdq_print(cmdq, "%s", cp);
free(cp);
format_free(ft);
} }
if (!detached) return (!detached); /* 1 means don't tell command client to exit */
cmdq->client_exit = 0;
if (fd != -1)
close(fd);
return (CMD_RETURN_NORMAL);
error:
if (fd != -1)
close(fd);
return (CMD_RETURN_ERROR);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,11 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -30,35 +26,31 @@
* Create a new window. * Create a new window.
*/ */
#define NEW_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" int cmd_new_window_exec(struct cmd *, struct cmd_ctx *);
enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_new_window_entry = { const struct cmd_entry cmd_new_window_entry = {
"new-window", "neww", "new-window", "neww",
"ac:dF:kn:Pt:", 0, -1, "adkn:Pt:", 0, 1,
"[-adkP] [-c start-directory] [-F format] [-n window-name] " "[-adk] [-n window-name] [-t target-window] [command]",
CMD_TARGET_WINDOW_USAGE " [command]",
0, 0,
NULL,
NULL,
cmd_new_window_exec cmd_new_window_exec
}; };
enum cmd_retval int
cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s;
struct winlink *wl; struct winlink *wl;
const char *cmd, *path, *template; char *cmd, *cwd, *cause;
char **argv, *cause, *cp; int idx, last, detached;
int argc, idx, last, detached, cwd, fd = -1;
struct format_tree *ft;
struct environ_entry *envent;
if (args_has(args, 'a')) { if (args_has(args, 'a')) {
wl = cmd_find_window(cmdq, args_get(args, 't'), &s); wl = cmd_find_window(ctx, args_get(args, 't'), &s);
if (wl == NULL) if (wl == NULL)
return (CMD_RETURN_ERROR); return (-1);
idx = wl->idx + 1; idx = wl->idx + 1;
/* Find the next free index. */ /* Find the next free index. */
@@ -67,8 +59,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
break; break;
} }
if (last == INT_MAX) { if (last == INT_MAX) {
cmdq_error(cmdq, "no free window indexes"); ctx->error(ctx, "no free window indexes");
return (CMD_RETURN_ERROR); return (-1);
} }
/* Move everything from last - 1 to idx up a bit. */ /* Move everything from last - 1 to idx up a bit. */
@@ -78,57 +70,11 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
server_unlink_window(s, wl); server_unlink_window(s, wl);
} }
} else { } else {
idx = cmd_find_index(cmdq, args_get(args, 't'), &s); if ((idx = cmd_find_index(ctx, args_get(args, 't'), &s)) == -2)
if (idx == -2) return (-1);
return (CMD_RETURN_ERROR);
} }
detached = args_has(args, 'd'); detached = args_has(args, 'd');
if (args->argc == 0) {
cmd = options_get_string(&s->options, "default-command");
if (cmd != NULL && *cmd != '\0') {
argc = 1;
argv = (char **)&cmd;
} else {
argc = 0;
argv = NULL;
}
} else {
argc = args->argc;
argv = args->argv;
}
path = NULL;
if (cmdq->client != NULL && cmdq->client->session == NULL)
envent = environ_find(&cmdq->client->environ, "PATH");
else
envent = environ_find(&s->environ, "PATH");
if (envent != NULL)
path = envent->value;
if (args_has(args, 'c')) {
ft = format_create();
format_defaults(ft, cmd_find_client(cmdq, NULL, 1), s, NULL,
NULL);
cp = format_expand(ft, args_get(args, 'c'));
format_free(ft);
if (cp != NULL && *cp != '\0') {
fd = open(cp, O_RDONLY|O_DIRECTORY);
free(cp);
if (fd == -1) {
cmdq_error(cmdq, "bad working directory: %s",
strerror(errno));
return (CMD_RETURN_ERROR);
}
} else if (cp != NULL)
free(cp);
cwd = fd;
} else if (cmdq->client != NULL && cmdq->client->session == NULL)
cwd = cmdq->client->cwd;
else
cwd = s->cwd;
wl = NULL; wl = NULL;
if (idx != -1) if (idx != -1)
wl = winlink_find_by_index(&s->windows, idx); wl = winlink_find_by_index(&s->windows, idx);
@@ -137,7 +83,6 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
* Can't use session_detach as it will destroy session if this * Can't use session_detach as it will destroy session if this
* makes it empty. * makes it empty.
*/ */
notify_window_unlinked(s, wl->window);
wl->flags &= ~WINLINK_ALERTFLAGS; wl->flags &= ~WINLINK_ALERTFLAGS;
winlink_stack_remove(&s->lastw, wl); winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl); winlink_remove(&s->windows, wl);
@@ -149,14 +94,25 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
} }
} }
if (args->argc == 0)
cmd = options_get_string(&s->options, "default-command");
else
cmd = args->argv[0];
cwd = options_get_string(&s->options, "default-path");
if (*cwd == '\0') {
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
cwd = ctx->cmdclient->cwd;
else
cwd = s->cwd;
}
if (idx == -1) if (idx == -1)
idx = -1 - options_get_number(&s->options, "base-index"); idx = -1 - options_get_number(&s->options, "base-index");
wl = session_new(s, args_get(args, 'n'), argc, argv, path, cwd, idx, wl = session_new(s, args_get(args, 'n'), cmd, cwd, idx, &cause);
&cause);
if (wl == NULL) { if (wl == NULL) {
cmdq_error(cmdq, "create window failed: %s", cause); ctx->error(ctx, "create window failed: %s", cause);
free(cause); xfree(cause);
goto error; return (-1);
} }
if (!detached) { if (!detached) {
session_select(s, wl->idx); session_select(s, wl->idx);
@@ -164,27 +120,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
} else } else
server_status_session_group(s); server_status_session_group(s);
if (args_has(args, 'P')) { if (args_has(args, 'P'))
if ((template = args_get(args, 'F')) == NULL) ctx->print(ctx, "%s:%u", s->name, wl->idx);
template = NEW_WINDOW_TEMPLATE; return (0);
ft = format_create();
format_defaults(ft, cmd_find_client(cmdq, NULL, 1), s, wl,
NULL);
cp = format_expand(ft, template);
cmdq_print(cmdq, "%s", cp);
free(cp);
format_free(ft);
}
if (fd != -1)
close(fd);
return (CMD_RETURN_NORMAL);
error:
if (fd != -1)
close(fd);
return (CMD_RETURN_ERROR);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,42 +27,53 @@
* Paste paste buffer if present. * Paste paste buffer if present.
*/ */
enum cmd_retval cmd_paste_buffer_exec(struct cmd *, struct cmd_q *); int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_paste_buffer_filter(struct window_pane *, void cmd_paste_buffer_filter(
const char *, size_t, const char *, int); struct window_pane *, const char *, size_t, const char *);
const struct cmd_entry cmd_paste_buffer_entry = { const struct cmd_entry cmd_paste_buffer_entry = {
"paste-buffer", "pasteb", "paste-buffer", "pasteb",
"db:prs:t:", 0, 0, "db:rs:t:", 0, 0,
"[-dpr] [-s separator] " CMD_BUFFER_USAGE " " CMD_TARGET_PANE_USAGE, "[-dr] [-s separator] [-b buffer-index] [-t target-pane]",
0, 0,
NULL,
NULL,
cmd_paste_buffer_exec cmd_paste_buffer_exec
}; };
enum cmd_retval int
cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq) cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp; struct window_pane *wp;
struct session *s; struct session *s;
struct paste_buffer *pb; struct paste_buffer *pb;
const char *sepstr, *bufname; const char *sepstr;
char *cause;
int buffer;
if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL) if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
return (CMD_RETURN_ERROR); return (-1);
bufname = NULL; if (!args_has(args, 'b'))
if (args_has(args, 'b')) buffer = -1;
bufname = args_get(args, 'b');
if (bufname == NULL)
pb = paste_get_top();
else { else {
pb = paste_get_name(bufname); buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
ctx->error(ctx, "buffer %s", cause);
xfree(cause);
return (-1);
}
}
if (buffer == -1)
pb = paste_get_top(&global_buffers);
else {
pb = paste_get_index(&global_buffers, buffer);
if (pb == NULL) { if (pb == NULL) {
cmdq_error(cmdq, "no buffer %s", bufname); ctx->error(ctx, "no buffer %d", buffer);
return (CMD_RETURN_ERROR); return (-1);
} }
} }
@@ -74,16 +85,37 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
else else
sepstr = "\r"; sepstr = "\r";
} }
paste_send_pane(pb, wp, sepstr, args_has(args, 'p')); cmd_paste_buffer_filter(wp, pb->data, pb->size, sepstr);
} }
/* Delete the buffer if -d. */ /* Delete the buffer if -d. */
if (args_has(args, 'd')) { if (args_has(args, 'd')) {
if (bufname == NULL) if (buffer == -1)
paste_free_top(); paste_free_top(&global_buffers);
else else
paste_free_name(bufname); paste_free_index(&global_buffers, buffer);
} }
return (CMD_RETURN_NORMAL); return (0);
}
/* Add bytes to a buffer and filter '\n' according to separator. */
void
cmd_paste_buffer_filter(
struct window_pane *wp, const char *data, size_t size, const char *sep)
{
const char *end = data + size;
const char *lf;
size_t seplen;
seplen = strlen(sep);
while ((lf = memchr(data, '\n', end - data)) != NULL) {
if (lf != data)
bufferevent_write(wp->event, data, lf - data);
bufferevent_write(wp->event, sep, seplen);
data = lf + 1;
}
if (end != data)
bufferevent_write(wp->event, data, end - data);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -21,7 +21,6 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
@@ -32,33 +31,34 @@
* Open pipe to redirect pane output. If already open, close first. * Open pipe to redirect pane output. If already open, close first.
*/ */
enum cmd_retval cmd_pipe_pane_exec(struct cmd *, struct cmd_q *); int cmd_pipe_pane_exec(struct cmd *, struct cmd_ctx *);
void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *); void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *);
const struct cmd_entry cmd_pipe_pane_entry = { const struct cmd_entry cmd_pipe_pane_entry = {
"pipe-pane", "pipep", "pipe-pane", "pipep",
"ot:", 0, 1, "ot:", 0, 1,
"[-o] " CMD_TARGET_PANE_USAGE " [command]", CMD_TARGET_PANE_USAGE "[-o] [command]",
0, 0,
NULL,
NULL,
cmd_pipe_pane_exec cmd_pipe_pane_exec
}; };
enum cmd_retval int
cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c;
struct session *s;
struct winlink *wl;
struct window_pane *wp; struct window_pane *wp;
char *cmd; char *command;
int old_fd, pipe_fd[2], null_fd; int old_fd, pipe_fd[2], null_fd;
struct format_tree *ft;
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL) if ((c = cmd_find_client(ctx, NULL)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
c = cmd_find_client(cmdq, NULL, 1);
if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
return (-1);
/* Destroy the old pipe. */ /* Destroy the old pipe. */
old_fd = wp->pipe_fd; old_fd = wp->pipe_fd;
@@ -70,7 +70,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
/* If no pipe command, that is enough. */ /* If no pipe command, that is enough. */
if (args->argc == 0 || *args->argv[0] == '\0') if (args->argc == 0 || *args->argv[0] == '\0')
return (CMD_RETURN_NORMAL); return (0);
/* /*
* With -o, only open the new pipe if there was no previous one. This * With -o, only open the new pipe if there was no previous one. This
@@ -79,27 +79,19 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
* bind ^p pipep -o 'cat >>~/output' * bind ^p pipep -o 'cat >>~/output'
*/ */
if (args_has(self->args, 'o') && old_fd != -1) if (args_has(self->args, 'o') && old_fd != -1)
return (CMD_RETURN_NORMAL); return (0);
/* Open the new pipe. */ /* Open the new pipe. */
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) { if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) {
cmdq_error(cmdq, "socketpair error: %s", strerror(errno)); ctx->error(ctx, "socketpair error: %s", strerror(errno));
return (CMD_RETURN_ERROR); return (-1);
} }
/* Expand the command. */
ft = format_create();
format_defaults(ft, c, s, wl, wp);
cmd = format_expand_time(ft, args->argv[0], time(NULL));
format_free(ft);
/* Fork the child. */ /* Fork the child. */
switch (fork()) { switch (fork()) {
case -1: case -1:
cmdq_error(cmdq, "fork error: %s", strerror(errno)); ctx->error(ctx, "fork error: %s", strerror(errno));
return (-1);
free(cmd);
return (CMD_RETURN_ERROR);
case 0: case 0:
/* Child process. */ /* Child process. */
close(pipe_fd[0]); close(pipe_fd[0]);
@@ -120,7 +112,9 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
closefrom(STDERR_FILENO + 1); closefrom(STDERR_FILENO + 1);
execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); command = status_replace(
c, NULL, NULL, NULL, args->argv[0], time(NULL), 0);
execl(_PATH_BSHELL, "sh", "-c", command, (char *) NULL);
_exit(1); _exit(1);
default: default:
/* Parent process. */ /* Parent process. */
@@ -134,12 +128,11 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
bufferevent_enable(wp->pipe_event, EV_WRITE); bufferevent_enable(wp->pipe_event, EV_WRITE);
setblocking(wp->pipe_fd, 0); setblocking(wp->pipe_fd, 0);
return (0);
free(cmd);
return (CMD_RETURN_NORMAL);
} }
} }
/* ARGSUSED */
void void
cmd_pipe_pane_error_callback( cmd_pipe_pane_error_callback(
unused struct bufferevent *bufev, unused short what, void *data) unused struct bufferevent *bufev, unused short what, void *data)

View File

@@ -1,246 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
#include "tmux.h"
/* Create new command queue. */
struct cmd_q *
cmdq_new(struct client *c)
{
struct cmd_q *cmdq;
cmdq = xcalloc(1, sizeof *cmdq);
cmdq->references = 1;
cmdq->dead = 0;
cmdq->client = c;
cmdq->client_exit = -1;
TAILQ_INIT(&cmdq->queue);
cmdq->item = NULL;
cmdq->cmd = NULL;
return (cmdq);
}
/* Free command queue */
int
cmdq_free(struct cmd_q *cmdq)
{
if (--cmdq->references != 0)
return (cmdq->dead);
cmdq_flush(cmdq);
free(cmdq);
return (1);
}
/* Show message from command. */
void
cmdq_print(struct cmd_q *cmdq, const char *fmt, ...)
{
struct client *c = cmdq->client;
struct window *w;
va_list ap;
va_start(ap, fmt);
if (c == NULL)
/* nothing */;
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
evbuffer_add_vprintf(c->stdout_data, fmt, ap);
evbuffer_add(c->stdout_data, "\n", 1);
server_push_stdout(c);
} else {
w = c->session->curw->window;
if (w->active->mode != &window_copy_mode) {
window_pane_reset_mode(w->active);
window_pane_set_mode(w->active, &window_copy_mode);
window_copy_init_for_output(w->active);
}
window_copy_vadd(w->active, fmt, ap);
}
va_end(ap);
}
/* Show error from command. */
void
cmdq_error(struct cmd_q *cmdq, const char *fmt, ...)
{
struct client *c = cmdq->client;
struct cmd *cmd = cmdq->cmd;
va_list ap;
char *msg;
size_t msglen;
va_start(ap, fmt);
msglen = xvasprintf(&msg, fmt, ap);
va_end(ap);
if (c == NULL)
cfg_add_cause("%s:%u: %s", cmd->file, cmd->line, msg);
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
evbuffer_add(c->stderr_data, msg, msglen);
evbuffer_add(c->stderr_data, "\n", 1);
server_push_stderr(c);
c->retval = 1;
} else {
*msg = toupper((u_char) *msg);
status_message_set(c, "%s", msg);
}
free(msg);
}
/* Print a guard line. */
void
cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags)
{
struct client *c = cmdq->client;
if (c == NULL || !(c->flags & CLIENT_CONTROL))
return;
evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
(long) cmdq->time, cmdq->number, flags);
server_push_stdout(c);
}
/* Add command list to queue and begin processing if needed. */
void
cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist)
{
cmdq_append(cmdq, cmdlist);
if (cmdq->item == NULL) {
cmdq->cmd = NULL;
cmdq_continue(cmdq);
}
}
/* Add command list to queue. */
void
cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist)
{
struct cmd_q_item *item;
item = xcalloc(1, sizeof *item);
item->cmdlist = cmdlist;
TAILQ_INSERT_TAIL(&cmdq->queue, item, qentry);
cmdlist->references++;
}
/* Continue processing command queue. Returns 1 if finishes empty. */
int
cmdq_continue(struct cmd_q *cmdq)
{
struct cmd_q_item *next;
enum cmd_retval retval;
int empty, flags;
char s[1024];
cmdq->references++;
notify_disable();
empty = TAILQ_EMPTY(&cmdq->queue);
if (empty)
goto empty;
if (cmdq->item == NULL) {
cmdq->item = TAILQ_FIRST(&cmdq->queue);
cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
} else
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
do {
while (cmdq->cmd != NULL) {
cmd_print(cmdq->cmd, s, sizeof s);
log_debug("cmdq %p: %s (client %d)", cmdq, s,
cmdq->client != NULL ? cmdq->client->ibuf.fd : -1);
cmdq->time = time(NULL);
cmdq->number++;
flags = !!(cmdq->cmd->flags & CMD_CONTROL);
cmdq_guard(cmdq, "begin", flags);
retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq);
if (retval == CMD_RETURN_ERROR)
cmdq_guard(cmdq, "error", flags);
else
cmdq_guard(cmdq, "end", flags);
if (retval == CMD_RETURN_ERROR)
break;
if (retval == CMD_RETURN_WAIT)
goto out;
if (retval == CMD_RETURN_STOP) {
cmdq_flush(cmdq);
goto empty;
}
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
}
next = TAILQ_NEXT(cmdq->item, qentry);
TAILQ_REMOVE(&cmdq->queue, cmdq->item, qentry);
cmd_list_free(cmdq->item->cmdlist);
free(cmdq->item);
cmdq->item = next;
if (cmdq->item != NULL)
cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
} while (cmdq->item != NULL);
empty:
if (cmdq->client_exit > 0)
cmdq->client->flags |= CLIENT_EXIT;
if (cmdq->emptyfn != NULL)
cmdq->emptyfn(cmdq);
empty = 1;
out:
notify_enable();
cmdq_free(cmdq);
return (empty);
}
/* Flush command queue. */
void
cmdq_flush(struct cmd_q *cmdq)
{
struct cmd_q_item *item, *item1;
TAILQ_FOREACH_SAFE(item, &cmdq->queue, qentry, item1) {
TAILQ_REMOVE(&cmdq->queue, item, qentry);
cmd_list_free(item->cmdlist);
free(item);
}
cmdq->item = NULL;
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,52 +24,28 @@
* Refresh client. * Refresh client.
*/ */
enum cmd_retval cmd_refresh_client_exec(struct cmd *, struct cmd_q *); int cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_refresh_client_entry = { const struct cmd_entry cmd_refresh_client_entry = {
"refresh-client", "refresh", "refresh-client", "refresh",
"C:St:", 0, 0, "t:", 0, 0,
"[-S] [-C size] " CMD_TARGET_CLIENT_USAGE, CMD_TARGET_CLIENT_USAGE,
0, 0,
NULL,
NULL,
cmd_refresh_client_exec cmd_refresh_client_exec
}; };
enum cmd_retval int
cmd_refresh_client_exec(struct cmd *self, struct cmd_q *cmdq) cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c;
const char *size;
u_int w, h;
if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL) if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
return (CMD_RETURN_ERROR); return (-1);
if (args_has(args, 'C')) { server_redraw_client(c);
if ((size = args_get(args, 'C')) == NULL) {
cmdq_error(cmdq, "missing size");
return (CMD_RETURN_ERROR);
}
if (sscanf(size, "%u,%u", &w, &h) != 2) {
cmdq_error(cmdq, "bad size argument");
return (CMD_RETURN_ERROR);
}
if (w < PANE_MINIMUM || w > 5000 ||
h < PANE_MINIMUM || h > 5000) {
cmdq_error(cmdq, "size too small or too big");
return (CMD_RETURN_ERROR);
}
if (!(c->flags & CLIENT_CONTROL)) {
cmdq_error(cmdq, "not a control client");
return (CMD_RETURN_ERROR);
}
if (tty_set_size(&c->tty, w, h))
recalculate_sizes();
} else if (args_has(args, 'S')) {
status_update_jobs(c);
server_status_client(c);
} else
server_redraw_client(c);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,18 +26,20 @@
* Change session name. * Change session name.
*/ */
enum cmd_retval cmd_rename_session_exec(struct cmd *, struct cmd_q *); int cmd_rename_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_rename_session_entry = { const struct cmd_entry cmd_rename_session_entry = {
"rename-session", "rename", "rename-session", "rename",
"t:", 1, 1, "t:", 1, 1,
CMD_TARGET_SESSION_USAGE " new-name", CMD_TARGET_SESSION_USAGE " new-name",
0, 0,
NULL,
NULL,
cmd_rename_session_exec cmd_rename_session_exec
}; };
enum cmd_retval int
cmd_rename_session_exec(struct cmd *self, struct cmd_q *cmdq) cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s;
@@ -45,24 +47,23 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_q *cmdq)
newname = args->argv[0]; newname = args->argv[0];
if (!session_check_name(newname)) { if (!session_check_name(newname)) {
cmdq_error(cmdq, "bad session name: %s", newname); ctx->error(ctx, "bad session name: %s", newname);
return (CMD_RETURN_ERROR); return (-1);
} }
if (session_find(newname) != NULL) { if (session_find(newname) != NULL) {
cmdq_error(cmdq, "duplicate session: %s", newname); ctx->error(ctx, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR); return (-1);
} }
if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL) if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
RB_REMOVE(sessions, &sessions, s); RB_REMOVE(sessions, &sessions, s);
free(s->name); xfree(s->name);
s->name = xstrdup(newname); s->name = xstrdup(newname);
RB_INSERT(sessions, &sessions, s); RB_INSERT(sessions, &sessions, s);
server_status_session(s); server_status_session(s);
notify_session_renamed(s);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,30 +26,33 @@
* Rename a window. * Rename a window.
*/ */
enum cmd_retval cmd_rename_window_exec(struct cmd *, struct cmd_q *); int cmd_rename_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_rename_window_entry = { const struct cmd_entry cmd_rename_window_entry = {
"rename-window", "renamew", "rename-window", "renamew",
"t:", 1, 1, "t:", 1, 1,
CMD_TARGET_WINDOW_USAGE " new-name", CMD_TARGET_WINDOW_USAGE " new-name",
0, 0,
NULL,
NULL,
cmd_rename_window_exec cmd_rename_window_exec
}; };
enum cmd_retval int
cmd_rename_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s;
struct winlink *wl; struct winlink *wl;
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL) if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
window_set_name(wl->window, args->argv[0]); xfree(wl->window->name);
wl->window->name = xstrdup(args->argv[0]);
options_set_number(&wl->window->options, "automatic-rename", 0); options_set_number(&wl->window->options, "automatic-rename", 0);
server_status_window(wl->window); server_status_window(wl->window);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,74 +26,83 @@
* Increase or decrease pane size. * Increase or decrease pane size.
*/ */
enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmd_q *); void cmd_resize_pane_key_binding(struct cmd *, int);
int cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_resize_pane_entry = { const struct cmd_entry cmd_resize_pane_entry = {
"resize-pane", "resizep", "resize-pane", "resizep",
"DLRt:Ux:y:Z", 0, 1, "DLRt:U", 0, 1,
"[-DLRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " [adjustment]", "[-DLRU] " CMD_TARGET_PANE_USAGE " [adjustment]",
0, 0,
cmd_resize_pane_key_binding,
NULL,
cmd_resize_pane_exec cmd_resize_pane_exec
}; };
enum cmd_retval void
cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_resize_pane_key_binding(struct cmd *self, int key)
{
switch (key) {
case KEYC_UP | KEYC_CTRL:
self->args = args_create(0);
args_set(self->args, 'U', NULL);
break;
case KEYC_DOWN | KEYC_CTRL:
self->args = args_create(0);
args_set(self->args, 'D', NULL);
break;
case KEYC_LEFT | KEYC_CTRL:
self->args = args_create(0);
args_set(self->args, 'L', NULL);
break;
case KEYC_RIGHT | KEYC_CTRL:
self->args = args_create(0);
args_set(self->args, 'R', NULL);
break;
case KEYC_UP | KEYC_ESCAPE:
self->args = args_create(1, "5");
args_set(self->args, 'U', NULL);
break;
case KEYC_DOWN | KEYC_ESCAPE:
self->args = args_create(1, "5");
args_set(self->args, 'D', NULL);
break;
case KEYC_LEFT | KEYC_ESCAPE:
self->args = args_create(1, "5");
args_set(self->args, 'L', NULL);
break;
case KEYC_RIGHT | KEYC_ESCAPE:
self->args = args_create(1, "5");
args_set(self->args, 'R', NULL);
break;
default:
self->args = args_create(0);
break;
}
}
int
cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl;
struct window *w;
const char *errstr; const char *errstr;
char *cause;
struct window_pane *wp; struct window_pane *wp;
u_int adjust; u_int adjust;
int x, y;
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL) if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
w = wl->window;
if (args_has(args, 'Z')) {
if (w->flags & WINDOW_ZOOMED)
window_unzoom(w);
else
window_zoom(wp);
server_redraw_window(w);
server_status_window(w);
return (CMD_RETURN_NORMAL);
}
server_unzoom_window(w);
if (args->argc == 0) if (args->argc == 0)
adjust = 1; adjust = 1;
else { else {
adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr); adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
cmdq_error(cmdq, "adjustment %s", errstr); ctx->error(ctx, "adjustment %s", errstr);
return (CMD_RETURN_ERROR); return (-1);
} }
} }
if (args_has(self->args, 'x')) {
x = args_strtonum(self->args, 'x', PANE_MINIMUM, INT_MAX,
&cause);
if (cause != NULL) {
cmdq_error(cmdq, "width %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
}
if (args_has(self->args, 'y')) {
y = args_strtonum(self->args, 'y', PANE_MINIMUM, INT_MAX,
&cause);
if (cause != NULL) {
cmdq_error(cmdq, "height %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
}
if (args_has(self->args, 'L')) if (args_has(self->args, 'L'))
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust); layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust);
else if (args_has(self->args, 'R')) else if (args_has(self->args, 'R'))
@@ -104,5 +113,5 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq)
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust); layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust);
server_redraw_window(wl->window); server_redraw_window(wl->window);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -19,7 +19,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -28,18 +27,20 @@
* Respawn a pane (restart the command). Kill existing if -k given. * Respawn a pane (restart the command). Kill existing if -k given.
*/ */
enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmd_q *); int cmd_respawn_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_respawn_pane_entry = { const struct cmd_entry cmd_respawn_pane_entry = {
"respawn-pane", "respawnp", "respawn-pane", "respawnp",
"kt:", 0, -1, "kt:", 0, 1,
"[-k] " CMD_TARGET_PANE_USAGE " [command]", "[-k] " CMD_TARGET_PANE_USAGE " [command]",
0, 0,
NULL,
NULL,
cmd_respawn_pane_exec cmd_respawn_pane_exec
}; };
enum cmd_retval int
cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl;
@@ -47,21 +48,17 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp; struct window_pane *wp;
struct session *s; struct session *s;
struct environ env; struct environ env;
const char *path; const char *cmd;
char *cause; char *cause;
u_int idx;
struct environ_entry *envent;
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL) if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
w = wl->window; w = wl->window;
if (!args_has(self->args, 'k') && wp->fd != -1) { if (!args_has(self->args, 'k') && wp->fd != -1) {
if (window_pane_index(wp, &idx) != 0) ctx->error(ctx, "pane still active: %s:%u.%u",
fatalx("index not found"); s->name, wl->idx, window_pane_index(w, wp));
cmdq_error(cmdq, "pane still active: %s:%u.%u", return (-1);
s->name, wl->idx, idx);
return (CMD_RETURN_ERROR);
} }
environ_init(&env); environ_init(&env);
@@ -73,24 +70,19 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq)
screen_reinit(&wp->base); screen_reinit(&wp->base);
input_init(wp); input_init(wp);
path = NULL; if (args->argc != 0)
if (cmdq->client != NULL && cmdq->client->session == NULL) cmd = args->argv[0];
envent = environ_find(&cmdq->client->environ, "PATH");
else else
envent = environ_find(&s->environ, "PATH"); cmd = NULL;
if (envent != NULL) if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) {
path = envent->value; ctx->error(ctx, "respawn pane failed: %s", cause);
xfree(cause);
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, -1, &env,
s->tio, &cause) != 0) {
cmdq_error(cmdq, "respawn pane failed: %s", cause);
free(cause);
environ_free(&env); environ_free(&env);
return (CMD_RETURN_ERROR); return (-1);
} }
wp->flags |= PANE_REDRAW; wp->flags |= PANE_REDRAW;
server_status_window(w); server_status_window(w);
environ_free(&env); environ_free(&env);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -27,18 +26,20 @@
* Respawn a window (restart the command). Kill existing if -k given. * Respawn a window (restart the command). Kill existing if -k given.
*/ */
enum cmd_retval cmd_respawn_window_exec(struct cmd *, struct cmd_q *); int cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_respawn_window_entry = { const struct cmd_entry cmd_respawn_window_entry = {
"respawn-window", "respawnw", "respawn-window", "respawnw",
"kt:", 0, -1, "kt:", 0, 1,
"[-k] " CMD_TARGET_WINDOW_USAGE " [command]", "[-k] " CMD_TARGET_WINDOW_USAGE " [command]",
0, 0,
NULL,
NULL,
cmd_respawn_window_exec cmd_respawn_window_exec
}; };
enum cmd_retval int
cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl;
@@ -46,21 +47,20 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp; struct window_pane *wp;
struct session *s; struct session *s;
struct environ env; struct environ env;
const char *path; const char *cmd;
char *cause; char *cause;
struct environ_entry *envent;
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL) if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
w = wl->window; w = wl->window;
if (!args_has(self->args, 'k')) { if (!args_has(self->args, 'k')) {
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd == -1) if (wp->fd == -1)
continue; continue;
cmdq_error(cmdq, ctx->error(ctx,
"window still active: %s:%d", s->name, wl->idx); "window still active: %s:%d", s->name, wl->idx);
return (CMD_RETURN_ERROR); return (-1);
} }
} }
@@ -75,24 +75,18 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
window_destroy_panes(w); window_destroy_panes(w);
TAILQ_INSERT_HEAD(&w->panes, wp, entry); TAILQ_INSERT_HEAD(&w->panes, wp, entry);
window_pane_resize(wp, w->sx, w->sy); window_pane_resize(wp, w->sx, w->sy);
if (args->argc != 0)
path = NULL; cmd = args->argv[0];
if (cmdq->client != NULL && cmdq->client->session == NULL)
envent = environ_find(&cmdq->client->environ, "PATH");
else else
envent = environ_find(&s->environ, "PATH"); cmd = NULL;
if (envent != NULL) if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) {
path = envent->value; ctx->error(ctx, "respawn window failed: %s", cause);
xfree(cause);
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, -1, &env,
s->tio, &cause) != 0) {
cmdq_error(cmdq, "respawn window failed: %s", cause);
free(cause);
environ_free(&env); environ_free(&env);
server_destroy_pane(wp); server_destroy_pane(wp);
return (CMD_RETURN_ERROR); return (-1);
} }
layout_init(w, wp); layout_init(w);
window_pane_reset_mode(wp); window_pane_reset_mode(wp);
screen_reinit(&wp->base); screen_reinit(&wp->base);
input_init(wp); input_init(wp);
@@ -102,5 +96,5 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
server_redraw_window(w); server_redraw_window(w);
environ_free(&env); environ_free(&env);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,18 +24,29 @@
* Rotate the panes in a window. * Rotate the panes in a window.
*/ */
enum cmd_retval cmd_rotate_window_exec(struct cmd *, struct cmd_q *); void cmd_rotate_window_key_binding(struct cmd *, int);
int cmd_rotate_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_rotate_window_entry = { const struct cmd_entry cmd_rotate_window_entry = {
"rotate-window", "rotatew", "rotate-window", "rotatew",
"Dt:U", 0, 0, "Dt:U", 0, 0,
"[-DU] " CMD_TARGET_WINDOW_USAGE, "[-DU] " CMD_TARGET_WINDOW_USAGE,
0, 0,
cmd_rotate_window_key_binding,
NULL,
cmd_rotate_window_exec cmd_rotate_window_exec
}; };
enum cmd_retval void
cmd_rotate_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_rotate_window_key_binding(struct cmd *self, int key)
{
self->args = args_create(0);
if (key == ('o' | KEYC_ESCAPE))
args_set(self->args, 'D', NULL);
}
int
cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl;
@@ -44,8 +55,8 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct layout_cell *lc; struct layout_cell *lc;
u_int sx, sy, xoff, yoff; u_int sx, sy, xoff, yoff;
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
w = wl->window; w = wl->window;
if (args_has(self->args, 'D')) { if (args_has(self->args, 'D')) {
@@ -104,5 +115,5 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_q *cmdq)
server_redraw_window(w); server_redraw_window(w);
} }
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -20,7 +20,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -29,108 +28,66 @@
* Runs a command without a window. * Runs a command without a window.
*/ */
enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmd_q *); int cmd_run_shell_exec(struct cmd *, struct cmd_ctx *);
void cmd_run_shell_callback(struct job *); void cmd_run_shell_callback(struct job *);
void cmd_run_shell_free(void *); void cmd_run_shell_free(void *);
void cmd_run_shell_print(struct job *, const char *);
const struct cmd_entry cmd_run_shell_entry = { const struct cmd_entry cmd_run_shell_entry = {
"run-shell", "run", "run-shell", "run",
"bt:", 1, 1, "", 1, 1,
"[-b] " CMD_TARGET_PANE_USAGE " shell-command", "command",
0, 0,
NULL,
NULL,
cmd_run_shell_exec cmd_run_shell_exec
}; };
struct cmd_run_shell_data { struct cmd_run_shell_data {
char *cmd; char *cmd;
struct cmd_q *cmdq; struct cmd_ctx ctx;
int bflag;
int wp_id;
}; };
void int
cmd_run_shell_print(struct job *job, const char *msg) cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_run_shell_data *cdata = job->data;
struct window_pane *wp = NULL;
if (cdata->wp_id != -1)
wp = window_pane_find_by_id(cdata->wp_id);
if (wp == NULL) {
cmdq_print(cdata->cmdq, "%s", msg);
return;
}
if (window_pane_set_mode(wp, &window_copy_mode) == 0)
window_copy_init_for_output(wp);
if (wp->mode == &window_copy_mode)
window_copy_add(wp, "%s", msg);
}
enum cmd_retval
cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_run_shell_data *cdata; struct cmd_run_shell_data *cdata;
char *shellcmd; const char *shellcmd = args->argv[0];
struct client *c;
struct session *s = NULL;
struct winlink *wl = NULL;
struct window_pane *wp = NULL;
struct format_tree *ft;
if (args_has(args, 't'))
wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
else {
c = cmd_find_client(cmdq, NULL, 1);
if (c != NULL && c->session != NULL) {
s = c->session;
wl = s->curw;
wp = wl->window->active;
}
}
ft = format_create();
format_defaults(ft, NULL, s, wl, wp);
shellcmd = format_expand(ft, args->argv[0]);
format_free(ft);
cdata = xmalloc(sizeof *cdata); cdata = xmalloc(sizeof *cdata);
cdata->cmd = shellcmd; cdata->cmd = xstrdup(args->argv[0]);
cdata->bflag = args_has(args, 'b'); memcpy(&cdata->ctx, ctx, sizeof cdata->ctx);
cdata->wp_id = wp != NULL ? (int) wp->id : -1;
cdata->cmdq = cmdq; if (ctx->cmdclient != NULL)
cmdq->references++; ctx->cmdclient->references++;
if (ctx->curclient != NULL)
ctx->curclient->references++;
job_run(shellcmd, s, cmd_run_shell_callback, cmd_run_shell_free, cdata); job_run(shellcmd, cmd_run_shell_callback, cmd_run_shell_free, cdata);
if (cdata->bflag) return (1); /* don't let client exit */
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
} }
void void
cmd_run_shell_callback(struct job *job) cmd_run_shell_callback(struct job *job)
{ {
struct cmd_run_shell_data *cdata = job->data; struct cmd_run_shell_data *cdata = job->data;
struct cmd_q *cmdq = cdata->cmdq; struct cmd_ctx *ctx = &cdata->ctx;
char *cmd, *msg, *line; char *cmd, *msg, *line;
size_t size; size_t size;
int retcode; int retcode;
u_int lines; u_int lines;
if (cmdq->dead) if (ctx->cmdclient != NULL && ctx->cmdclient->flags & CLIENT_DEAD)
return;
if (ctx->curclient != NULL && ctx->curclient->flags & CLIENT_DEAD)
return; return;
cmd = cdata->cmd;
lines = 0; lines = 0;
do { do {
if ((line = evbuffer_readline(job->event->input)) != NULL) { if ((line = evbuffer_readline(job->event->input)) != NULL) {
cmd_run_shell_print(job, line); ctx->print(ctx, "%s", line);
free(line);
lines++; lines++;
} }
} while (line != NULL); } while (line != NULL);
@@ -141,12 +98,14 @@ cmd_run_shell_callback(struct job *job)
memcpy(line, EVBUFFER_DATA(job->event->input), size); memcpy(line, EVBUFFER_DATA(job->event->input), size);
line[size] = '\0'; line[size] = '\0';
cmd_run_shell_print(job, line); ctx->print(ctx, "%s", line);
lines++; lines++;
free(line); xfree(line);
} }
cmd = cdata->cmd;
msg = NULL; msg = NULL;
if (WIFEXITED(job->status)) { if (WIFEXITED(job->status)) {
if ((retcode = WEXITSTATUS(job->status)) != 0) if ((retcode = WEXITSTATUS(job->status)) != 0)
@@ -155,20 +114,28 @@ cmd_run_shell_callback(struct job *job)
retcode = WTERMSIG(job->status); retcode = WTERMSIG(job->status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode); xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
} }
if (msg != NULL) if (msg != NULL) {
cmd_run_shell_print(job, msg); if (lines != 0)
free(msg); ctx->print(ctx, "%s", msg);
else
ctx->info(ctx, "%s", msg);
xfree(msg);
}
} }
void void
cmd_run_shell_free(void *data) cmd_run_shell_free(void *data)
{ {
struct cmd_run_shell_data *cdata = data; struct cmd_run_shell_data *cdata = data;
struct cmd_q *cmdq = cdata->cmdq; struct cmd_ctx *ctx = &cdata->ctx;
if (!cmdq_free(cmdq) && !cdata->bflag) if (ctx->cmdclient != NULL) {
cmdq_continue(cmdq); ctx->cmdclient->references--;
ctx->cmdclient->flags |= CLIENT_EXIT;
}
if (ctx->curclient != NULL)
ctx->curclient->references--;
free(cdata->cmd); xfree(cdata->cmd);
free(cdata); xfree(cdata);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -20,138 +20,83 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Saves a paste buffer to a file. * Saves a session paste buffer to a file.
*/ */
enum cmd_retval cmd_save_buffer_exec(struct cmd *, struct cmd_q *); int cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_save_buffer_entry = { const struct cmd_entry cmd_save_buffer_entry = {
"save-buffer", "saveb", "save-buffer", "saveb",
"ab:", 1, 1, "ab:", 1, 1,
"[-a] " CMD_BUFFER_USAGE " path", "[-a] " CMD_BUFFER_USAGE,
0, 0,
NULL,
NULL,
cmd_save_buffer_exec cmd_save_buffer_exec
}; };
const struct cmd_entry cmd_show_buffer_entry = { int
"show-buffer", "showb", cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
"b:", 0, 0,
CMD_BUFFER_USAGE,
0,
cmd_save_buffer_exec
};
enum cmd_retval
cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmdq->client; struct client *c = ctx->cmdclient;
struct session *s;
struct paste_buffer *pb; struct paste_buffer *pb;
const char *path, *bufname; const char *path;
char *start, *end, *msg; char *cause;
size_t size, used, msglen; int buffer;
int cwd, fd; mode_t mask;
FILE *f; FILE *f;
if (!args_has(args, 'b')) { if (!args_has(args, 'b')) {
if ((pb = paste_get_top()) == NULL) { if ((pb = paste_get_top(&global_buffers)) == NULL) {
cmdq_error(cmdq, "no buffers"); ctx->error(ctx, "no buffers");
return (CMD_RETURN_ERROR); return (-1);
} }
} else { } else {
bufname = args_get(args, 'b'); buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
pb = paste_get_name(bufname); if (cause != NULL) {
ctx->error(ctx, "buffer %s", cause);
xfree(cause);
return (-1);
}
pb = paste_get_index(&global_buffers, buffer);
if (pb == NULL) { if (pb == NULL) {
cmdq_error(cmdq, "no buffer %s", bufname); ctx->error(ctx, "no buffer %d", buffer);
return (CMD_RETURN_ERROR); return (-1);
} }
} }
if (self->entry == &cmd_show_buffer_entry) path = args->argv[0];
path = "-";
else
path = args->argv[0];
if (strcmp(path, "-") == 0) { if (strcmp(path, "-") == 0) {
if (c == NULL) { if (c == NULL) {
cmdq_error(cmdq, "can't write to stdout"); ctx->error(ctx, "%s: can't write to stdout", path);
return (CMD_RETURN_ERROR); return (-1);
} }
if (c->session == NULL || (c->flags & CLIENT_CONTROL)) bufferevent_write(c->stdout_event, pb->data, pb->size);
goto do_stdout;
goto do_print;
}
if (c != NULL && c->session == NULL)
cwd = c->cwd;
else if ((s = cmd_current_session(cmdq, 0)) != NULL)
cwd = s->cwd;
else
cwd = AT_FDCWD;
f = NULL;
if (args_has(self->args, 'a')) {
fd = openat(cwd, path, O_CREAT|O_RDWR|O_APPEND, 0600);
if (fd != -1)
f = fdopen(fd, "ab");
} else { } else {
fd = openat(cwd, path, O_CREAT|O_RDWR|O_TRUNC, 0600); mask = umask(S_IRWXG | S_IRWXO);
if (fd != -1) if (args_has(self->args, 'a'))
f = fdopen(fd, "wb"); f = fopen(path, "ab");
}
if (f == NULL) {
if (fd != -1)
close(fd);
cmdq_error(cmdq, "%s: %s", path, strerror(errno));
return (CMD_RETURN_ERROR);
}
if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
cmdq_error(cmdq, "%s: fwrite error", path);
fclose(f);
return (CMD_RETURN_ERROR);
}
fclose(f);
return (CMD_RETURN_NORMAL);
do_stdout:
evbuffer_add(c->stdout_data, pb->data, pb->size);
server_push_stdout(c);
return (CMD_RETURN_NORMAL);
do_print:
if (pb->size > (INT_MAX / 4) - 1) {
cmdq_error(cmdq, "buffer too big");
return (CMD_RETURN_ERROR);
}
msg = NULL;
used = 0;
while (used != pb->size) {
start = pb->data + used;
end = memchr(start, '\n', pb->size - used);
if (end != NULL)
size = end - start;
else else
size = pb->size - used; f = fopen(path, "wb");
umask(mask);
msglen = size * 4 + 1; if (f == NULL) {
msg = xrealloc(msg, msglen); ctx->error(ctx, "%s: %s", path, strerror(errno));
return (-1);
strvisx(msg, start, size, VIS_OCTAL|VIS_TAB); }
cmdq_print(cmdq, "%s", msg); if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
ctx->error(ctx, "%s: fwrite error", path);
used += size + (end != NULL); fclose(f);
return (-1);
}
fclose(f);
} }
free(msg); return (0);
return (CMD_RETURN_NORMAL);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,13 +24,16 @@
* Switch window to selected layout. * Switch window to selected layout.
*/ */
enum cmd_retval cmd_select_layout_exec(struct cmd *, struct cmd_q *); void cmd_select_layout_key_binding(struct cmd *, int);
int cmd_select_layout_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_select_layout_entry = { const struct cmd_entry cmd_select_layout_entry = {
"select-layout", "selectl", "select-layout", "selectl",
"npt:", 0, 1, "npt:", 0, 1,
"[-np] " CMD_TARGET_WINDOW_USAGE " [layout-name]", "[-np] " CMD_TARGET_WINDOW_USAGE " [layout-name]",
0, 0,
cmd_select_layout_key_binding,
NULL,
cmd_select_layout_exec cmd_select_layout_exec
}; };
@@ -39,6 +42,8 @@ const struct cmd_entry cmd_next_layout_entry = {
"t:", 0, 0, "t:", 0, 0,
CMD_TARGET_WINDOW_USAGE, CMD_TARGET_WINDOW_USAGE,
0, 0,
NULL,
NULL,
cmd_select_layout_exec cmd_select_layout_exec
}; };
@@ -47,20 +52,46 @@ const struct cmd_entry cmd_previous_layout_entry = {
"t:", 0, 0, "t:", 0, 0,
CMD_TARGET_WINDOW_USAGE, CMD_TARGET_WINDOW_USAGE,
0, 0,
NULL,
NULL,
cmd_select_layout_exec cmd_select_layout_exec
}; };
enum cmd_retval void
cmd_select_layout_exec(struct cmd *self, struct cmd_q *cmdq) cmd_select_layout_key_binding(struct cmd *self, int key)
{
switch (key) {
case '1' | KEYC_ESCAPE:
self->args = args_create(1, "even-horizontal");
break;
case '2' | KEYC_ESCAPE:
self->args = args_create(1, "even-vertical");
break;
case '3' | KEYC_ESCAPE:
self->args = args_create(1, "main-horizontal");
break;
case '4' | KEYC_ESCAPE:
self->args = args_create(1, "main-vertical");
break;
case '5' | KEYC_ESCAPE:
self->args = args_create(1, "tiled");
break;
default:
self->args = args_create(0);
break;
}
}
int
cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl;
const char *layoutname; const char *layoutname;
int next, previous, layout; int next, previous, layout;
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
server_unzoom_window(wl->window);
next = self->entry == &cmd_next_layout_entry; next = self->entry == &cmd_next_layout_entry;
if (args_has(self->args, 'n')) if (args_has(self->args, 'n'))
@@ -74,8 +105,8 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_q *cmdq)
layout = layout_set_next(wl->window); layout = layout_set_next(wl->window);
else else
layout = layout_set_previous(wl->window); layout = layout_set_previous(wl->window);
server_redraw_window(wl->window); ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
return (CMD_RETURN_NORMAL); return (0);
} }
if (args->argc == 0) if (args->argc == 0)
@@ -84,17 +115,19 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_q *cmdq)
layout = layout_set_lookup(args->argv[0]); layout = layout_set_lookup(args->argv[0]);
if (layout != -1) { if (layout != -1) {
layout = layout_set_select(wl->window, layout); layout = layout_set_select(wl->window, layout);
server_redraw_window(wl->window); ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
return (CMD_RETURN_NORMAL); return (0);
} }
if (args->argc != 0) { if (args->argc != 0) {
layoutname = args->argv[0]; layoutname = args->argv[0];
if (layout_parse(wl->window, layoutname) == -1) { if (layout_parse(wl->window, layoutname) == -1) {
cmdq_error(cmdq, "can't set layout: %s", layoutname); ctx->error(ctx, "can't set layout: %s", layoutname);
return (CMD_RETURN_ERROR); return (-1);
} }
server_redraw_window(wl->window); ctx->info(ctx, "arranging in: %s", layoutname);
return (0);
} }
return (CMD_RETURN_NORMAL);
return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,62 +24,75 @@
* Select pane. * Select pane.
*/ */
enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmd_q *); void cmd_select_pane_key_binding(struct cmd *, int);
int cmd_select_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_select_pane_entry = { const struct cmd_entry cmd_select_pane_entry = {
"select-pane", "selectp", "select-pane", "selectp",
"DdeLlRt:U", 0, 0, "lDLRt:U", 0, 0,
"[-DdeLlRU] " CMD_TARGET_PANE_USAGE, "[-lDLRU] " CMD_TARGET_PANE_USAGE,
0, 0,
cmd_select_pane_key_binding,
NULL,
cmd_select_pane_exec cmd_select_pane_exec
}; };
const struct cmd_entry cmd_last_pane_entry = { const struct cmd_entry cmd_last_pane_entry = {
"last-pane", "lastp", "last-pane", "lastp",
"det:", 0, 0, "t:", 0, 0,
"[-de] " CMD_TARGET_WINDOW_USAGE, CMD_TARGET_WINDOW_USAGE,
0, 0,
NULL,
NULL,
cmd_select_pane_exec cmd_select_pane_exec
}; };
enum cmd_retval void
cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_select_pane_key_binding(struct cmd *self, int key)
{
self->args = args_create(0);
if (key == KEYC_UP)
args_set(self->args, 'U', NULL);
if (key == KEYC_DOWN)
args_set(self->args, 'D', NULL);
if (key == KEYC_LEFT)
args_set(self->args, 'L', NULL);
if (key == KEYC_RIGHT)
args_set(self->args, 'R', NULL);
if (key == 'o')
args_set(self->args, 't', ":.+");
}
int
cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl;
struct window_pane *wp; struct window_pane *wp;
if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) { if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
wl = cmd_find_window(cmdq, args_get(args, 't'), NULL); wl = cmd_find_window(ctx, args_get(args, 't'), NULL);
if (wl == NULL) if (wl == NULL)
return (CMD_RETURN_ERROR); return (-1);
if (wl->window->last == NULL) { if (wl->window->last == NULL) {
cmdq_error(cmdq, "no last pane"); ctx->error(ctx, "no last pane");
return (CMD_RETURN_ERROR); return (-1);
} }
if (args_has(self->args, 'e')) window_set_active_pane(wl->window, wl->window->last);
wl->window->last->flags &= ~PANE_INPUTOFF; server_status_window(wl->window);
else if (args_has(self->args, 'd')) server_redraw_window_borders(wl->window);
wl->window->last->flags |= PANE_INPUTOFF;
else {
server_unzoom_window(wl->window);
window_set_active_pane(wl->window, wl->window->last);
server_status_window(wl->window);
server_redraw_window_borders(wl->window);
}
return (CMD_RETURN_NORMAL); return (0);
} }
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL) if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
server_unzoom_window(wp->window);
if (!window_pane_visible(wp)) { if (!window_pane_visible(wp)) {
cmdq_error(cmdq, "pane not visible"); ctx->error(ctx, "pane not visible");
return (CMD_RETURN_ERROR); return (-1);
} }
if (args_has(self->args, 'L')) if (args_has(self->args, 'L'))
@@ -91,18 +104,13 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
else if (args_has(self->args, 'D')) else if (args_has(self->args, 'D'))
wp = window_pane_find_down(wp); wp = window_pane_find_down(wp);
if (wp == NULL) { if (wp == NULL) {
cmdq_error(cmdq, "pane not found"); ctx->error(ctx, "pane not found");
return (CMD_RETURN_ERROR); return (-1);
} }
if (args_has(self->args, 'e')) window_set_active_pane(wl->window, wp);
wp->flags &= ~PANE_INPUTOFF; server_status_window(wl->window);
else if (args_has(self->args, 'd')) server_redraw_window_borders(wl->window);
wp->flags |= PANE_INPUTOFF;
else if (window_set_active_pane(wl->window, wp)) {
server_status_window(wl->window);
server_redraw_window_borders(wl->window);
}
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,13 +26,16 @@
* Select window by index. * Select window by index.
*/ */
enum cmd_retval cmd_select_window_exec(struct cmd *, struct cmd_q *); void cmd_select_window_key_binding(struct cmd *, int);
int cmd_select_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_select_window_entry = { const struct cmd_entry cmd_select_window_entry = {
"select-window", "selectw", "select-window", "selectw",
"lnpTt:", 0, 0, "lnpt:", 0, 0,
"[-lnpT] " CMD_TARGET_WINDOW_USAGE, "[-lnp] " CMD_TARGET_WINDOW_USAGE,
0, 0,
cmd_select_window_key_binding,
NULL,
cmd_select_window_exec cmd_select_window_exec
}; };
@@ -41,6 +44,8 @@ const struct cmd_entry cmd_next_window_entry = {
"at:", 0, 0, "at:", 0, 0,
"[-a] " CMD_TARGET_SESSION_USAGE, "[-a] " CMD_TARGET_SESSION_USAGE,
0, 0,
cmd_select_window_key_binding,
NULL,
cmd_select_window_exec cmd_select_window_exec
}; };
@@ -49,6 +54,8 @@ const struct cmd_entry cmd_previous_window_entry = {
"at:", 0, 0, "at:", 0, 0,
"[-a] " CMD_TARGET_SESSION_USAGE, "[-a] " CMD_TARGET_SESSION_USAGE,
0, 0,
cmd_select_window_key_binding,
NULL,
cmd_select_window_exec cmd_select_window_exec
}; };
@@ -57,11 +64,27 @@ const struct cmd_entry cmd_last_window_entry = {
"t:", 0, 0, "t:", 0, 0,
CMD_TARGET_SESSION_USAGE, CMD_TARGET_SESSION_USAGE,
0, 0,
NULL,
NULL,
cmd_select_window_exec cmd_select_window_exec
}; };
enum cmd_retval void
cmd_select_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_select_window_key_binding(struct cmd *self, int key)
{
char tmp[16];
self->args = args_create(0);
if (key >= '0' && key <= '9') {
xsnprintf(tmp, sizeof tmp, ":%d", key - '0');
args_set(self->args, 't', tmp);
}
if (key == ('n' | KEYC_ESCAPE) || key == ('p' | KEYC_ESCAPE))
args_set(self->args, 'a', NULL);
}
int
cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl;
@@ -79,48 +102,38 @@ cmd_select_window_exec(struct cmd *self, struct cmd_q *cmdq)
last = 1; last = 1;
if (next || previous || last) { if (next || previous || last) {
s = cmd_find_session(cmdq, args_get(args, 't'), 0); s = cmd_find_session(ctx, args_get(args, 't'), 0);
if (s == NULL) if (s == NULL)
return (CMD_RETURN_ERROR); return (-1);
activity = args_has(self->args, 'a'); activity = args_has(self->args, 'a');
if (next) { if (next) {
if (session_next(s, activity) != 0) { if (session_next(s, activity) != 0) {
cmdq_error(cmdq, "no next window"); ctx->error(ctx, "no next window");
return (CMD_RETURN_ERROR); return (-1);
} }
} else if (previous) { } else if (previous) {
if (session_previous(s, activity) != 0) { if (session_previous(s, activity) != 0) {
cmdq_error(cmdq, "no previous window"); ctx->error(ctx, "no previous window");
return (CMD_RETURN_ERROR); return (-1);
} }
} else { } else {
if (session_last(s) != 0) { if (session_last(s) != 0) {
cmdq_error(cmdq, "no last window"); ctx->error(ctx, "no last window");
return (CMD_RETURN_ERROR); return (-1);
} }
} }
server_redraw_session(s); server_redraw_session(s);
} else { } else {
wl = cmd_find_window(cmdq, args_get(args, 't'), &s); wl = cmd_find_window(ctx, args_get(args, 't'), &s);
if (wl == NULL) if (wl == NULL)
return (CMD_RETURN_ERROR); return (-1);
/* if (session_select(s, wl->idx) == 0)
* If -T and select-window is invoked on same window as
* current, switch to previous window.
*/
if (args_has(self->args, 'T') && wl == s->curw) {
if (session_last(s) != 0) {
cmdq_error(cmdq, "no last window");
return (-1);
}
server_redraw_session(s);
} else if (session_select(s, wl->idx) == 0)
server_redraw_session(s); server_redraw_session(s);
} }
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -19,7 +19,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -27,67 +26,34 @@
* Send keys to client. * Send keys to client.
*/ */
enum cmd_retval cmd_send_keys_exec(struct cmd *, struct cmd_q *); int cmd_send_keys_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_send_keys_entry = { const struct cmd_entry cmd_send_keys_entry = {
"send-keys", "send", "send-keys", "send",
"lRt:", 0, -1, "t:", 0, -1,
"[-lR] " CMD_TARGET_PANE_USAGE " key ...", "[-t target-pane] key ...",
0, 0,
NULL,
NULL,
cmd_send_keys_exec cmd_send_keys_exec
}; };
const struct cmd_entry cmd_send_prefix_entry = { int
"send-prefix", NULL, cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
"2t:", 0, 0,
"[-2] " CMD_TARGET_PANE_USAGE,
0,
cmd_send_keys_exec
};
enum cmd_retval
cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp; struct window_pane *wp;
struct session *s; struct session *s;
struct input_ctx *ictx; const char *str;
const u_char *str;
int i, key; int i, key;
if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL) if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
return (CMD_RETURN_ERROR); return (-1);
if (self->entry == &cmd_send_prefix_entry) {
if (args_has(args, '2'))
key = options_get_number(&s->options, "prefix2");
else
key = options_get_number(&s->options, "prefix");
window_pane_key(wp, s, key);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'R')) {
ictx = &wp->ictx;
memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
ictx->old_cx = 0;
ictx->old_cy = 0;
if (wp->mode == NULL)
screen_write_start(&ictx->ctx, wp, &wp->base);
else
screen_write_start(&ictx->ctx, NULL, &wp->base);
screen_write_reset(&ictx->ctx);
screen_write_stop(&ictx->ctx);
}
for (i = 0; i < args->argc; i++) { for (i = 0; i < args->argc; i++) {
str = args->argv[i]; str = args->argv[i];
if (!args_has(args, 'l') && if ((key = key_string_lookup_string(str)) != KEYC_NONE) {
(key = key_string_lookup_string(str)) != KEYC_NONE) {
window_pane_key(wp, s, key); window_pane_key(wp, s, key);
} else { } else {
for (; *str != '\0'; str++) for (; *str != '\0'; str++)
@@ -95,5 +61,5 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq)
} }
} }
return (CMD_RETURN_NORMAL); return (0);
} }

54
cmd-send-prefix.c Normal file
View File

@@ -0,0 +1,54 @@
/* $Id$ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Send prefix key as a key.
*/
int cmd_send_prefix_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_send_prefix_entry = {
"send-prefix", NULL,
"t:", 0, 0,
CMD_TARGET_PANE_USAGE,
0,
NULL,
NULL,
cmd_send_prefix_exec
};
int
cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s;
struct window_pane *wp;
struct keylist *keylist;
if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
return (-1);
keylist = options_get_data(&s->options, "prefix");
window_pane_key(wp, s, ARRAY_FIRST(keylist));
return (0);
}

183
cmd-server-info.c Normal file
View File

@@ -0,0 +1,183 @@
/* $Id$ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/utsname.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "tmux.h"
/*
* Show various information about server.
*/
int cmd_server_info_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_server_info_entry = {
"server-info", "info",
"", 0, 0,
"",
0,
NULL,
NULL,
cmd_server_info_exec
};
/* ARGSUSED */
int
cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{
struct tty_term *term;
struct client *c;
struct session *s;
struct winlink *wl;
struct window *w;
struct window_pane *wp;
struct tty_code *code;
const struct tty_term_code_entry *ent;
struct utsname un;
struct job *job;
struct grid *gd;
struct grid_line *gl;
u_int i, j, k;
char out[80];
char *tim;
time_t t;
u_int lines, ulines;
size_t size, usize;
tim = ctime(&start_time);
*strchr(tim, '\n') = '\0';
ctx->print(ctx,
"tmux " VERSION ", pid %ld, started %s", (long) getpid(), tim);
ctx->print(
ctx, "socket path %s, debug level %d", socket_path, debug_level);
if (uname(&un) >= 0) {
ctx->print(ctx, "system is %s %s %s %s",
un.sysname, un.release, un.version, un.machine);
}
if (cfg_file != NULL)
ctx->print(ctx, "configuration file is %s", cfg_file);
else
ctx->print(ctx, "configuration file not specified");
ctx->print(ctx, "protocol version is %d", PROTOCOL_VERSION);
ctx->print(ctx, "%s", "");
ctx->print(ctx, "Clients:");
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
continue;
ctx->print(ctx,"%2d: %s (%d, %d): %s [%ux%u %s bs=%hho] "
"[flags=0x%x/0x%x, references=%u]", i, c->tty.path,
c->ibuf.fd, c->tty.fd, c->session->name,
c->tty.sx, c->tty.sy, c->tty.termname,
c->tty.tio.c_cc[VERASE], c->flags,
c->tty.flags, c->references);
}
ctx->print(ctx, "%s", "");
ctx->print(ctx, "Sessions: [%zu/%zu]",
sizeof (struct grid_cell), sizeof (struct grid_utf8));
RB_FOREACH(s, sessions, &sessions) {
t = s->creation_time.tv_sec;
tim = ctime(&t);
*strchr(tim, '\n') = '\0';
ctx->print(ctx, "%2u: %s: %u windows (created %s) [%ux%u] "
"[flags=0x%x]", s->idx, s->name,
winlink_count(&s->windows), tim, s->sx, s->sy, s->flags);
RB_FOREACH(wl, winlinks, &s->windows) {
w = wl->window;
ctx->print(ctx, "%4u: %s [%ux%u] [flags=0x%x, "
"references=%u, last layout=%d]", wl->idx, w->name,
w->sx, w->sy, w->flags, w->references,
w->lastlayout);
j = 0;
TAILQ_FOREACH(wp, &w->panes, entry) {
lines = ulines = size = usize = 0;
gd = wp->base.grid;
for (k = 0; k < gd->hsize + gd->sy; k++) {
gl = &gd->linedata[k];
if (gl->celldata != NULL) {
lines++;
size += gl->cellsize *
sizeof *gl->celldata;
}
if (gl->utf8data != NULL) {
ulines++;
usize += gl->utf8size *
sizeof *gl->utf8data;
}
}
ctx->print(ctx, "%6u: %s %lu %d %u/%u, %zu "
"bytes; UTF-8 %u/%u, %zu bytes", j,
wp->tty, (u_long) wp->pid, wp->fd, lines,
gd->hsize + gd->sy, size, ulines,
gd->hsize + gd->sy, usize);
j++;
}
}
}
ctx->print(ctx, "%s", "");
ctx->print(ctx, "Terminals:");
LIST_FOREACH(term, &tty_terms, entry) {
ctx->print(ctx, "%s [references=%u, flags=0x%x]:",
term->name, term->references, term->flags);
for (i = 0; i < NTTYCODE; i++) {
ent = &tty_term_codes[i];
code = &term->codes[ent->code];
switch (code->type) {
case TTYCODE_NONE:
ctx->print(ctx, "%2u: %s: [missing]",
ent->code, ent->name);
break;
case TTYCODE_STRING:
strnvis(out, code->value.string, sizeof out,
VIS_OCTAL|VIS_TAB|VIS_NL);
ctx->print(ctx, "%2u: %s: (string) %s",
ent->code, ent->name, out);
break;
case TTYCODE_NUMBER:
ctx->print(ctx, "%2u: %s: (number) %d",
ent->code, ent->name, code->value.number);
break;
case TTYCODE_FLAG:
ctx->print(ctx, "%2u: %s: (flag) %s",
ent->code, ent->name,
code->value.flag ? "true" : "false");
break;
}
}
}
ctx->print(ctx, "%s", "");
ctx->print(ctx, "Jobs:");
LIST_FOREACH(job, &all_jobs, lentry) {
ctx->print(ctx, "%s [fd=%d, pid=%d, status=%d]",
job->cmd, job->fd, job->pid, job->status);
}
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,101 +18,58 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Add, set, or append to a paste buffer. * Add or set a session paste buffer.
*/ */
enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmd_q *); int cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_set_buffer_entry = { const struct cmd_entry cmd_set_buffer_entry = {
"set-buffer", "setb", "set-buffer", "setb",
"ab:n:", 0, 1, "b:", 1, 1,
"[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data", CMD_BUFFER_USAGE " data",
0, 0,
NULL,
NULL,
cmd_set_buffer_exec cmd_set_buffer_exec
}; };
enum cmd_retval int
cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq) cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct paste_buffer *pb; u_int limit;
char *pdata, *cause; char *pdata, *cause;
const char *bufname; size_t psize;
size_t psize, newsize; int buffer;
bufname = NULL; limit = options_get_number(&global_options, "buffer-limit");
if (args_has(args, 'n')) { pdata = xstrdup(args->argv[0]);
if (args->argc > 0) { psize = strlen(pdata);
cmdq_error(cmdq, "don't provide data with n flag");
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'b')) if (!args_has(args, 'b')) {
bufname = args_get(args, 'b'); paste_add(&global_buffers, pdata, psize, limit);
return (0);
if (bufname == NULL) {
pb = paste_get_top();
if (pb == NULL) {
cmdq_error(cmdq, "no buffer");
return (CMD_RETURN_ERROR);
}
bufname = pb->name;
}
if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) {
cmdq_error(cmdq, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
} }
if (args->argc != 1) { buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
cmdq_error(cmdq, "no data specified"); if (cause != NULL) {
return (CMD_RETURN_ERROR); ctx->error(ctx, "buffer %s", cause);
xfree(cause);
xfree(pdata);
return (-1);
} }
psize = 0; if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) {
pdata = NULL; ctx->error(ctx, "no buffer %d", buffer);
xfree(pdata);
pb = NULL; return (-1);
if ((newsize = strlen(args->argv[0])) == 0)
return (CMD_RETURN_NORMAL);
if (args_has(args, 'b')) {
bufname = args_get(args, 'b');
pb = paste_get_name(bufname);
} else if (args_has(args, 'a')) {
pb = paste_get_top();
if (pb != NULL)
bufname = pb->name;
} }
if (args_has(args, 'a') && pb != NULL) { return (0);
psize = pb->size;
pdata = xmalloc(psize);
memcpy(pdata, pb->data, psize);
}
pdata = xrealloc(pdata, psize + newsize);
memcpy(pdata + psize, args->argv[0], newsize);
psize += newsize;
if (paste_set(pdata, psize, bufname, &cause) != 0) {
cmdq_error(cmdq, "%s", cause);
free(pdata);
free(cause);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,18 +27,20 @@
* Set an environment variable. * Set an environment variable.
*/ */
enum cmd_retval cmd_set_environment_exec(struct cmd *, struct cmd_q *); int cmd_set_environment_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_set_environment_entry = { const struct cmd_entry cmd_set_environment_entry = {
"set-environment", "setenv", "set-environment", "setenv",
"grt:u", 1, 2, "grt:u", 1, 2,
"[-gru] " CMD_TARGET_SESSION_USAGE " name [value]", "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
0, 0,
NULL,
NULL,
cmd_set_environment_exec cmd_set_environment_exec
}; };
enum cmd_retval int
cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq) cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s;
@@ -47,15 +49,15 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq)
name = args->argv[0]; name = args->argv[0];
if (*name == '\0') { if (*name == '\0') {
cmdq_error(cmdq, "empty variable name"); ctx->error(ctx, "empty variable name");
return (CMD_RETURN_ERROR); return (-1);
} }
if (strchr(name, '=') != NULL) { if (strchr(name, '=') != NULL) {
cmdq_error(cmdq, "variable name contains ="); ctx->error(ctx, "variable name contains =");
return (CMD_RETURN_ERROR); return (-1);
} }
if (args->argc < 2) if (args->argc < 1)
value = NULL; value = NULL;
else else
value = args->argv[1]; value = args->argv[1];
@@ -63,30 +65,30 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(self->args, 'g')) if (args_has(self->args, 'g'))
env = &global_environ; env = &global_environ;
else { else {
if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL) if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
env = &s->environ; env = &s->environ;
} }
if (args_has(self->args, 'u')) { if (args_has(self->args, 'u')) {
if (value != NULL) { if (value != NULL) {
cmdq_error(cmdq, "can't specify a value with -u"); ctx->error(ctx, "can't specify a value with -u");
return (CMD_RETURN_ERROR); return (-1);
} }
environ_unset(env, name); environ_unset(env, name);
} else if (args_has(self->args, 'r')) { } else if (args_has(self->args, 'r')) {
if (value != NULL) { if (value != NULL) {
cmdq_error(cmdq, "can't specify a value with -r"); ctx->error(ctx, "can't specify a value with -r");
return (CMD_RETURN_ERROR); return (-1);
} }
environ_set(env, name, NULL); environ_set(env, name, NULL);
} else { } else {
if (value == NULL) { if (value == NULL) {
cmdq_error(cmdq, "no value specified"); ctx->error(ctx, "no value specified");
return (CMD_RETURN_ERROR); return (-1);
} }
environ_set(env, name, value); environ_set(env, name, value);
} }
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,61 +27,95 @@
* Set an option. * Set an option.
*/ */
enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmd_q *); int cmd_set_option_exec(struct cmd *, struct cmd_ctx *);
enum cmd_retval cmd_set_option_user(struct cmd *, struct cmd_q *, int cmd_set_option_find(const char *, const struct options_table_entry **,
const char *, const char *); const struct options_table_entry **);
int cmd_set_option_unset(struct cmd *, struct cmd_q *, int cmd_set_option_unset(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *, const struct options_table_entry *, struct options *,
const char *); const char *);
int cmd_set_option_set(struct cmd *, struct cmd_q *, int cmd_set_option_set(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *, const struct options_table_entry *, struct options *,
const char *); const char *);
struct options_entry *cmd_set_option_string(struct cmd *, struct cmd_q *, struct options_entry *cmd_set_option_string(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *, const struct options_table_entry *, struct options *,
const char *); const char *);
struct options_entry *cmd_set_option_number(struct cmd *, struct cmd_q *, struct options_entry *cmd_set_option_number(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *, const struct options_table_entry *, struct options *,
const char *); const char *);
struct options_entry *cmd_set_option_key(struct cmd *, struct cmd_q *, struct options_entry *cmd_set_option_keys(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *, const struct options_table_entry *, struct options *,
const char *); const char *);
struct options_entry *cmd_set_option_colour(struct cmd *, struct cmd_q *, struct options_entry *cmd_set_option_colour(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *, const struct options_table_entry *, struct options *,
const char *); const char *);
struct options_entry *cmd_set_option_attributes(struct cmd *, struct cmd_q *, struct options_entry *cmd_set_option_attributes(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *, const struct options_table_entry *, struct options *,
const char *); const char *);
struct options_entry *cmd_set_option_flag(struct cmd *, struct cmd_q *, struct options_entry *cmd_set_option_flag(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *, const struct options_table_entry *, struct options *,
const char *); const char *);
struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_q *, struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_style(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *, const struct options_table_entry *, struct options *,
const char *); const char *);
const struct cmd_entry cmd_set_option_entry = { const struct cmd_entry cmd_set_option_entry = {
"set-option", "set", "set-option", "set",
"agoqst:uw", 1, 2, "agst:uw", 1, 2,
"[-agosquw] [-t target-session|target-window] option [value]", "[-agsuw] [-t target-session|target-window] option [value]",
0, 0,
NULL,
NULL,
cmd_set_option_exec cmd_set_option_exec
}; };
const struct cmd_entry cmd_set_window_option_entry = { const struct cmd_entry cmd_set_window_option_entry = {
"set-window-option", "setw", "set-window-option", "setw",
"agoqt:u", 1, 2, "agt:u", 1, 2,
"[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]", "[-agu] " CMD_TARGET_WINDOW_USAGE " option [value]",
0, 0,
NULL,
NULL,
cmd_set_option_exec cmd_set_option_exec
}; };
enum cmd_retval /* Look for an option in all three tables. */
cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq) int
cmd_set_option_find(
const char *optstr, const struct options_table_entry **table,
const struct options_table_entry **oe)
{
static const struct options_table_entry *tables[] = {
server_options_table,
window_options_table,
session_options_table
};
const struct options_table_entry *oe_loop;
u_int i;
for (i = 0; i < nitems(tables); i++) {
for (oe_loop = tables[i]; oe_loop->name != NULL; oe_loop++) {
if (strncmp(oe_loop->name, optstr, strlen(optstr)) != 0)
continue;
/* If already found, ambiguous. */
if (*oe != NULL)
return (-1);
*oe = oe_loop;
*table = tables[i];
/* Bail now if an exact match. */
if (strcmp((*oe)->name, optstr) == 0)
break;
}
}
return (0);
}
int
cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
const struct options_table_entry *table, *oe; const struct options_table_entry *table, *oe;
@@ -89,37 +123,29 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq)
struct winlink *wl; struct winlink *wl;
struct client *c; struct client *c;
struct options *oo; struct options *oo;
struct window *w;
const char *optstr, *valstr; const char *optstr, *valstr;
u_int i; u_int i;
/* Get the option name and value. */ /* Get the option name and value. */
optstr = args->argv[0]; optstr = args->argv[0];
if (*optstr == '\0') { if (*optstr == '\0') {
cmdq_error(cmdq, "invalid option"); ctx->error(ctx, "invalid option");
return (CMD_RETURN_ERROR); return (-1);
} }
if (args->argc < 2) if (args->argc < 2)
valstr = NULL; valstr = NULL;
else else
valstr = args->argv[1]; valstr = args->argv[1];
/* Is this a user option? */
if (*optstr == '@')
return (cmd_set_option_user(self, cmdq, optstr, valstr));
/* Find the option entry, try each table. */ /* Find the option entry, try each table. */
table = oe = NULL; table = oe = NULL;
if (options_table_find(optstr, &table, &oe) != 0) { if (cmd_set_option_find(optstr, &table, &oe) != 0) {
cmdq_error(cmdq, "ambiguous option: %s", optstr); ctx->error(ctx, "ambiguous option: %s", optstr);
return (CMD_RETURN_ERROR); return (-1);
} }
if (oe == NULL) { if (oe == NULL) {
if (!args_has(args, 'q')) { ctx->error(ctx, "unknown option: %s", optstr);
cmdq_error(cmdq, "unknown option: %s", optstr); return (-1);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
} }
/* Work out the tree from the table. */ /* Work out the tree from the table. */
@@ -129,61 +155,32 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(self->args, 'g')) if (args_has(self->args, 'g'))
oo = &global_w_options; oo = &global_w_options;
else { else {
wl = cmd_find_window(cmdq, args_get(args, 't'), NULL); wl = cmd_find_window(ctx, args_get(args, 't'), NULL);
if (wl == NULL) { if (wl == NULL)
cmdq_error(cmdq, return (-1);
"couldn't set '%s'%s", optstr,
(!args_has(args, 't') && !args_has(args,
'g')) ? " need target window or -g" : "");
return (CMD_RETURN_ERROR);
}
oo = &wl->window->options; oo = &wl->window->options;
} }
} else if (table == session_options_table) { } else if (table == session_options_table) {
if (args_has(self->args, 'g')) if (args_has(self->args, 'g'))
oo = &global_s_options; oo = &global_s_options;
else { else {
s = cmd_find_session(cmdq, args_get(args, 't'), 0); s = cmd_find_session(ctx, args_get(args, 't'), 0);
if (s == NULL) { if (s == NULL)
cmdq_error(cmdq, return (-1);
"couldn't set '%s'%s", optstr,
(!args_has(args, 't') && !args_has(args,
'g')) ? " need target session or -g" : "");
return (CMD_RETURN_ERROR);
}
oo = &s->options; oo = &s->options;
} }
} else { } else {
cmdq_error(cmdq, "unknown table"); ctx->error(ctx, "unknown table");
return (CMD_RETURN_ERROR); return (-1);
} }
/* Unset or set the option. */ /* Unset or set the option. */
if (args_has(args, 'u')) { if (args_has(args, 'u')) {
if (cmd_set_option_unset(self, cmdq, oe, oo, valstr) != 0) if (cmd_set_option_unset(self, ctx, oe, oo, valstr) != 0)
return (CMD_RETURN_ERROR); return (-1);
} else { } else {
if (args_has(args, 'o') && options_find1(oo, optstr) != NULL) { if (cmd_set_option_set(self, ctx, oe, oo, valstr) != 0)
if (!args_has(args, 'q')) { return (-1);
cmdq_error(cmdq, "already set: %s", optstr);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
if (cmd_set_option_set(self, cmdq, oe, oo, valstr) != 0)
return (CMD_RETURN_ERROR);
}
/* Start or stop timers when automatic-rename changed. */
if (strcmp(oe->name, "automatic-rename") == 0) {
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
if ((w = ARRAY_ITEM(&windows, i)) == NULL)
continue;
if (options_get_number(&w->options, "automatic-rename"))
queue_window_name(w);
else if (event_initialized(&w->name_timer))
evtimer_del(&w->name_timer);
}
} }
/* Update sizes and redraw. May not need it but meh. */ /* Update sizes and redraw. May not need it but meh. */
@@ -194,151 +191,81 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq)
server_redraw_client(c); server_redraw_client(c);
} }
return (CMD_RETURN_NORMAL); return (0);
} }
/* Set user option. */
enum cmd_retval
cmd_set_option_user(struct cmd *self, struct cmd_q *cmdq, const char *optstr,
const char *valstr)
{
struct args *args = self->args;
struct session *s;
struct winlink *wl;
struct options *oo;
if (args_has(args, 's'))
oo = &global_options;
else if (args_has(self->args, 'w') ||
self->entry == &cmd_set_window_option_entry) {
if (args_has(self->args, 'g'))
oo = &global_w_options;
else {
wl = cmd_find_window(cmdq, args_get(args, 't'), NULL);
if (wl == NULL)
return (CMD_RETURN_ERROR);
oo = &wl->window->options;
}
} else {
if (args_has(self->args, 'g'))
oo = &global_s_options;
else {
s = cmd_find_session(cmdq, args_get(args, 't'), 0);
if (s == NULL)
return (CMD_RETURN_ERROR);
oo = &s->options;
}
}
if (args_has(args, 'u')) {
if (options_find1(oo, optstr) == NULL) {
if (!args_has(args, 'q')) {
cmdq_error(cmdq, "unknown option: %s", optstr);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
if (valstr != NULL) {
cmdq_error(cmdq, "value passed to unset option: %s",
optstr);
return (CMD_RETURN_ERROR);
}
options_remove(oo, optstr);
} else {
if (valstr == NULL) {
cmdq_error(cmdq, "empty value");
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'o') && options_find1(oo, optstr) != NULL) {
if (!args_has(args, 'q')) {
cmdq_error(cmdq, "already set: %s", optstr);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
options_set_string(oo, optstr, "%s", valstr);
}
return (CMD_RETURN_NORMAL);
}
/* Unset an option. */ /* Unset an option. */
int int
cmd_set_option_unset(struct cmd *self, struct cmd_q *cmdq, cmd_set_option_unset(struct cmd *self, struct cmd_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const struct options_table_entry *oe, struct options *oo, const char *value)
const char *value)
{ {
struct args *args = self->args; struct args *args = self->args;
if (args_has(args, 'g')) { if (args_has(args, 'g')) {
cmdq_error(cmdq, "can't unset global option: %s", oe->name); ctx->error(ctx, "can't unset global option: %s", oe->name);
return (-1); return (-1);
} }
if (value != NULL) { if (value != NULL) {
cmdq_error(cmdq, "value passed to unset option: %s", oe->name); ctx->error(ctx, "value passed to unset option: %s", oe->name);
return (-1); return (-1);
} }
options_remove(oo, oe->name); options_remove(oo, oe->name);
ctx->info(ctx, "unset option: %s", oe->name);
return (0); return (0);
} }
/* Set an option. */ /* Set an option. */
int int
cmd_set_option_set(struct cmd *self, struct cmd_q *cmdq, cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const struct options_table_entry *oe, struct options *oo, const char *value)
const char *value)
{ {
struct options_entry *o; struct options_entry *o;
const char *s;
if (oe->type != OPTIONS_TABLE_FLAG && value == NULL) { if (oe->type != OPTIONS_TABLE_FLAG && value == NULL) {
cmdq_error(cmdq, "empty value"); ctx->error(ctx, "empty value");
return (-1); return (-1);
} }
o = NULL; o = NULL;
switch (oe->type) { switch (oe->type) {
case OPTIONS_TABLE_STRING: case OPTIONS_TABLE_STRING:
o = cmd_set_option_string(self, cmdq, oe, oo, value); o = cmd_set_option_string(self, ctx, oe, oo, value);
break; break;
case OPTIONS_TABLE_NUMBER: case OPTIONS_TABLE_NUMBER:
o = cmd_set_option_number(self, cmdq, oe, oo, value); o = cmd_set_option_number(self, ctx, oe, oo, value);
break; break;
case OPTIONS_TABLE_KEY: case OPTIONS_TABLE_KEYS:
o = cmd_set_option_key(self, cmdq, oe, oo, value); o = cmd_set_option_keys(self, ctx, oe, oo, value);
break; break;
case OPTIONS_TABLE_COLOUR: case OPTIONS_TABLE_COLOUR:
o = cmd_set_option_colour(self, cmdq, oe, oo, value); o = cmd_set_option_colour(self, ctx, oe, oo, value);
if (o != NULL)
style_update_new(oo, o->name, oe->style);
break; break;
case OPTIONS_TABLE_ATTRIBUTES: case OPTIONS_TABLE_ATTRIBUTES:
o = cmd_set_option_attributes(self, cmdq, oe, oo, value); o = cmd_set_option_attributes(self, ctx, oe, oo, value);
if (o != NULL)
style_update_new(oo, o->name, oe->style);
break; break;
case OPTIONS_TABLE_FLAG: case OPTIONS_TABLE_FLAG:
o = cmd_set_option_flag(self, cmdq, oe, oo, value); o = cmd_set_option_flag(self, ctx, oe, oo, value);
break; break;
case OPTIONS_TABLE_CHOICE: case OPTIONS_TABLE_CHOICE:
o = cmd_set_option_choice(self, cmdq, oe, oo, value); o = cmd_set_option_choice(self, ctx, oe, oo, value);
break;
case OPTIONS_TABLE_STYLE:
o = cmd_set_option_style(self, cmdq, oe, oo, value);
break; break;
} }
if (o == NULL) if (o == NULL)
return (-1); return (-1);
s = options_table_print_entry(oe, o);
ctx->info(ctx, "set option: %s -> %s", oe->name, s);
return (0); return (0);
} }
/* Set a string option. */ /* Set a string option. */
struct options_entry * struct options_entry *
cmd_set_option_string(struct cmd *self, unused struct cmd_q *cmdq, cmd_set_option_string(struct cmd *self, unused struct cmd_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const struct options_table_entry *oe, struct options *oo, const char *value)
const char *value)
{ {
struct args *args = self->args; struct args *args = self->args;
struct options_entry *o; struct options_entry *o;
char *oldval, *newval; char *oldval, *newval;
@@ -350,54 +277,63 @@ cmd_set_option_string(struct cmd *self, unused struct cmd_q *cmdq,
o = options_set_string(oo, oe->name, "%s", newval); o = options_set_string(oo, oe->name, "%s", newval);
free(newval); xfree(newval);
return (o); return (o);
} }
/* Set a number option. */ /* Set a number option. */
struct options_entry * struct options_entry *
cmd_set_option_number(unused struct cmd *self, struct cmd_q *cmdq, cmd_set_option_number(unused struct cmd *self, struct cmd_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const struct options_table_entry *oe, struct options *oo, const char *value)
const char *value)
{ {
long long ll; long long ll;
const char *errstr; const char *errstr;
ll = strtonum(value, oe->minimum, oe->maximum, &errstr); ll = strtonum(value, oe->minimum, oe->maximum, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
cmdq_error(cmdq, "value is %s: %s", errstr, value); ctx->error(ctx, "value is %s: %s", errstr, value);
return (NULL); return (NULL);
} }
return (options_set_number(oo, oe->name, ll)); return (options_set_number(oo, oe->name, ll));
} }
/* Set a key option. */ /* Set a keys option. */
struct options_entry * struct options_entry *
cmd_set_option_key(unused struct cmd *self, struct cmd_q *cmdq, cmd_set_option_keys(unused struct cmd *self, struct cmd_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const struct options_table_entry *oe, struct options *oo, const char *value)
const char *value)
{ {
int key; struct keylist *keylist;
char *copy, *ptr, *s;
int key;
if ((key = key_string_lookup_string(value)) == KEYC_NONE) { keylist = xmalloc(sizeof *keylist);
cmdq_error(cmdq, "bad key: %s", value); ARRAY_INIT(keylist);
return (NULL);
ptr = copy = xstrdup(value);
while ((s = strsep(&ptr, ",")) != NULL) {
if ((key = key_string_lookup_string(s)) == KEYC_NONE) {
ctx->error(ctx, "unknown key: %s", s);
xfree(copy);
xfree(keylist);
return (NULL);
}
ARRAY_ADD(keylist, key);
} }
xfree(copy);
return (options_set_number(oo, oe->name, key)); return (options_set_data(oo, oe->name, keylist, xfree));
} }
/* Set a colour option. */ /* Set a colour option. */
struct options_entry * struct options_entry *
cmd_set_option_colour(unused struct cmd *self, struct cmd_q *cmdq, cmd_set_option_colour(unused struct cmd *self, struct cmd_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const struct options_table_entry *oe, struct options *oo, const char *value)
const char *value)
{ {
int colour; int colour;
if ((colour = colour_fromstring(value)) == -1) { if ((colour = colour_fromstring(value)) == -1) {
cmdq_error(cmdq, "bad colour: %s", value); ctx->error(ctx, "bad colour: %s", value);
return (NULL); return (NULL);
} }
@@ -406,14 +342,13 @@ cmd_set_option_colour(unused struct cmd *self, struct cmd_q *cmdq,
/* Set an attributes option. */ /* Set an attributes option. */
struct options_entry * struct options_entry *
cmd_set_option_attributes(unused struct cmd *self, struct cmd_q *cmdq, cmd_set_option_attributes(unused struct cmd *self, struct cmd_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const struct options_table_entry *oe, struct options *oo, const char *value)
const char *value)
{ {
int attr; int attr;
if ((attr = attributes_fromstring(value)) == -1) { if ((attr = attributes_fromstring(value)) == -1) {
cmdq_error(cmdq, "bad attributes: %s", value); ctx->error(ctx, "bad attributes: %s", value);
return (NULL); return (NULL);
} }
@@ -422,9 +357,8 @@ cmd_set_option_attributes(unused struct cmd *self, struct cmd_q *cmdq,
/* Set a flag option. */ /* Set a flag option. */
struct options_entry * struct options_entry *
cmd_set_option_flag(unused struct cmd *self, struct cmd_q *cmdq, cmd_set_option_flag(unused struct cmd *self, struct cmd_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const struct options_table_entry *oe, struct options *oo, const char *value)
const char *value)
{ {
int flag; int flag;
@@ -440,7 +374,7 @@ cmd_set_option_flag(unused struct cmd *self, struct cmd_q *cmdq,
strcasecmp(value, "no") == 0) strcasecmp(value, "no") == 0)
flag = 0; flag = 0;
else { else {
cmdq_error(cmdq, "bad value: %s", value); ctx->error(ctx, "bad value: %s", value);
return (NULL); return (NULL);
} }
} }
@@ -450,9 +384,8 @@ cmd_set_option_flag(unused struct cmd *self, struct cmd_q *cmdq,
/* Set a choice option. */ /* Set a choice option. */
struct options_entry * struct options_entry *
cmd_set_option_choice(unused struct cmd *self, struct cmd_q *cmdq, cmd_set_option_choice(unused struct cmd *self, struct cmd_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const struct options_table_entry *oe, struct options *oo, const char *value)
const char *value)
{ {
const char **choicep; const char **choicep;
int n, choice = -1; int n, choice = -1;
@@ -464,35 +397,15 @@ cmd_set_option_choice(unused struct cmd *self, struct cmd_q *cmdq,
continue; continue;
if (choice != -1) { if (choice != -1) {
cmdq_error(cmdq, "ambiguous value: %s", value); ctx->error(ctx, "ambiguous value: %s", value);
return (NULL); return (NULL);
} }
choice = n - 1; choice = n - 1;
} }
if (choice == -1) { if (choice == -1) {
cmdq_error(cmdq, "unknown value: %s", value); ctx->error(ctx, "unknown value: %s", value);
return (NULL); return (NULL);
} }
return (options_set_number(oo, oe->name, choice)); return (options_set_number(oo, oe->name, choice));
} }
/* Set a style option. */
struct options_entry *
cmd_set_option_style(struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
struct args *args = self->args;
struct options_entry *o;
int append;
append = args_has(args, 'a');
if ((o = options_set_style(oo, oe->name, value, append)) == NULL) {
cmdq_error(cmdq, "bad style: %s", value);
return (NULL);
}
style_update_old(oo, oe->name, &o->style);
return (o);
}

109
cmd-show-buffer.c Normal file
View File

@@ -0,0 +1,109 @@
/* $Id$ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Show a session paste buffer.
*/
int cmd_show_buffer_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_show_buffer_entry = {
"show-buffer", "showb",
"b:", 0, 0,
CMD_BUFFER_USAGE,
0,
NULL,
NULL,
cmd_show_buffer_exec
};
int
cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s;
struct paste_buffer *pb;
int buffer;
char *in, *buf, *ptr, *cause;
size_t size, len;
u_int width;
if ((s = cmd_find_session(ctx, NULL, 0)) == NULL)
return (-1);
if (!args_has(args, 'b')) {
if ((pb = paste_get_top(&global_buffers)) == NULL) {
ctx->error(ctx, "no buffers");
return (-1);
}
} else {
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
ctx->error(ctx, "buffer %s", cause);
xfree(cause);
return (-1);
}
pb = paste_get_index(&global_buffers, buffer);
if (pb == NULL) {
ctx->error(ctx, "no buffer %d", buffer);
return (-1);
}
}
size = pb->size;
if (size > SIZE_MAX / 4 - 1)
size = SIZE_MAX / 4 - 1;
in = xmalloc(size * 4 + 1);
strvisx(in, pb->data, size, VIS_OCTAL|VIS_TAB);
width = s->sx;
if (ctx->cmdclient != NULL)
width = ctx->cmdclient->tty.sx;
buf = xmalloc(width + 1);
len = 0;
ptr = in;
do {
buf[len++] = *ptr++;
if (len == width || buf[len - 1] == '\n') {
if (buf[len - 1] == '\n')
len--;
buf[len] = '\0';
ctx->print(ctx, "%s", buf);
len = 0;
}
} while (*ptr != '\0');
if (len != 0) {
buf[len] = '\0';
ctx->print(ctx, "%s", buf);
}
xfree(buf);
xfree(in);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,18 +27,20 @@
* Show environment. * Show environment.
*/ */
enum cmd_retval cmd_show_environment_exec(struct cmd *, struct cmd_q *); int cmd_show_environment_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_show_environment_entry = { const struct cmd_entry cmd_show_environment_entry = {
"show-environment", "showenv", "show-environment", "showenv",
"gt:", 0, 1, "gt:", 0, 0,
"[-g] " CMD_TARGET_SESSION_USAGE " [name]", "[-g] " CMD_TARGET_SESSION_USAGE,
0, 0,
NULL,
NULL,
cmd_show_environment_exec cmd_show_environment_exec
}; };
enum cmd_retval int
cmd_show_environment_exec(struct cmd *self, struct cmd_q *cmdq) cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s;
@@ -48,30 +50,17 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(self->args, 'g')) if (args_has(self->args, 'g'))
env = &global_environ; env = &global_environ;
else { else {
if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL) if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
env = &s->environ; env = &s->environ;
} }
if (args->argc != 0) {
envent = environ_find(env, args->argv[0]);
if (envent == NULL) {
cmdq_error(cmdq, "unknown variable: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
if (envent->value != NULL)
cmdq_print(cmdq, "%s=%s", envent->name, envent->value);
else
cmdq_print(cmdq, "-%s", envent->name);
return (CMD_RETURN_NORMAL);
}
RB_FOREACH(envent, environ, env) { RB_FOREACH(envent, environ, env) {
if (envent->value != NULL) if (envent->value != NULL)
cmdq_print(cmdq, "%s=%s", envent->name, envent->value); ctx->print(ctx, "%s=%s", envent->name, envent->value);
else else
cmdq_print(cmdq, "-%s", envent->name); ctx->print(ctx, "-%s", envent->name);
} }
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -20,7 +20,6 @@
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -28,132 +27,29 @@
* Show client message log. * Show client message log.
*/ */
enum cmd_retval cmd_show_messages_exec(struct cmd *, struct cmd_q *); int cmd_show_messages_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_show_messages_entry = { const struct cmd_entry cmd_show_messages_entry = {
"show-messages", "showmsgs", "show-messages", "showmsgs",
"IJTt:", 0, 0, "t:", 0, 0,
"[-IJT] " CMD_TARGET_CLIENT_USAGE, CMD_TARGET_CLIENT_USAGE,
0, 0,
NULL,
NULL,
cmd_show_messages_exec cmd_show_messages_exec
}; };
const struct cmd_entry cmd_server_info_entry = { int
"server-info", "info", cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx)
"", 0, 0,
"",
0,
cmd_show_messages_exec
};
void cmd_show_messages_server(struct cmd_q *);
void cmd_show_messages_terminals(struct cmd_q *);
void cmd_show_messages_jobs(struct cmd_q *);
void
cmd_show_messages_server(struct cmd_q *cmdq)
{
char *tim;
tim = ctime(&start_time);
*strchr(tim, '\n') = '\0';
cmdq_print(cmdq, "started %s", tim);
cmdq_print(cmdq, "socket path %s", socket_path);
cmdq_print(cmdq, "debug level %d", debug_level);
cmdq_print(cmdq, "protocol version %d", PROTOCOL_VERSION);
}
void
cmd_show_messages_terminals(struct cmd_q *cmdq)
{
struct tty_term *term;
const struct tty_term_code_entry *ent;
struct tty_code *code;
u_int i, n;
char out[80];
n = 0;
LIST_FOREACH(term, &tty_terms, entry) {
cmdq_print(cmdq,
"Terminal %u: %s [references=%u, flags=0x%x]:",
n, term->name, term->references, term->flags);
n++;
for (i = 0; i < NTTYCODE; i++) {
ent = &tty_term_codes[i];
code = &term->codes[ent->code];
switch (code->type) {
case TTYCODE_NONE:
cmdq_print(cmdq, "%4u: %s: [missing]",
ent->code, ent->name);
break;
case TTYCODE_STRING:
strnvis(out, code->value.string, sizeof out,
VIS_OCTAL|VIS_TAB|VIS_NL);
cmdq_print(cmdq, "%4u: %s: (string) %s",
ent->code, ent->name, out);
break;
case TTYCODE_NUMBER:
cmdq_print(cmdq, "%4u: %s: (number) %d",
ent->code, ent->name, code->value.number);
break;
case TTYCODE_FLAG:
cmdq_print(cmdq, "%4u: %s: (flag) %s",
ent->code, ent->name,
code->value.flag ? "true" : "false");
break;
}
}
}
}
void
cmd_show_messages_jobs(struct cmd_q *cmdq)
{
struct job *job;
u_int n;
n = 0;
LIST_FOREACH(job, &all_jobs, lentry) {
cmdq_print(cmdq,
"Job %u: %s [fd=%d, pid=%d, status=%d]",
n, job->cmd, job->fd, job->pid, job->status);
n++;
}
}
enum cmd_retval
cmd_show_messages_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c;
struct message_entry *msg; struct message_entry *msg;
char *tim; char *tim;
u_int i; u_int i;
int done;
done = 0; if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
if (args_has(args, 'I') || self->entry == &cmd_server_info_entry) { return (-1);
cmd_show_messages_server(cmdq);
done = 1;
}
if (args_has(args, 'T') || self->entry == &cmd_server_info_entry) {
if (done)
cmdq_print(cmdq, "%s", "");
cmd_show_messages_terminals(cmdq);
done = 1;
}
if (args_has(args, 'J') || self->entry == &cmd_server_info_entry) {
if (done)
cmdq_print(cmdq, "%s", "");
cmd_show_messages_jobs(cmdq);
done = 1;
}
if (done)
return (CMD_RETURN_NORMAL);
if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) { for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) {
msg = &ARRAY_ITEM(&c->message_log, i); msg = &ARRAY_ITEM(&c->message_log, i);
@@ -161,8 +57,8 @@ cmd_show_messages_exec(struct cmd *self, struct cmd_q *cmdq)
tim = ctime(&msg->msg_time); tim = ctime(&msg->msg_time);
*strchr(tim, '\n') = '\0'; *strchr(tim, '\n') = '\0';
cmdq_print(cmdq, "%s %s", tim, msg->msg); ctx->print(ctx, "%s %s", tim, msg->msg);
} }
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,38 +27,38 @@
* Show options. * Show options.
*/ */
enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmd_q *); int cmd_show_options_exec(struct cmd *, struct cmd_ctx *);
enum cmd_retval cmd_show_options_one(struct cmd *, struct cmd_q *,
struct options *, int);
enum cmd_retval cmd_show_options_all(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *);
const struct cmd_entry cmd_show_options_entry = { const struct cmd_entry cmd_show_options_entry = {
"show-options", "show", "show-options", "show",
"gqst:vw", 0, 1, "gst:w", 0, 0,
"[-gqsvw] [-t target-session|target-window] [option]", "[-gsw] [-t target-session|target-window]",
0, 0,
NULL,
NULL,
cmd_show_options_exec cmd_show_options_exec
}; };
const struct cmd_entry cmd_show_window_options_entry = { const struct cmd_entry cmd_show_window_options_entry = {
"show-window-options", "showw", "show-window-options", "showw",
"gvt:", 0, 1, "gt:", 0, 0,
"[-gv] " CMD_TARGET_WINDOW_USAGE " [option]", "[-g] " CMD_TARGET_WINDOW_USAGE,
0, 0,
NULL,
NULL,
cmd_show_options_exec cmd_show_options_exec
}; };
enum cmd_retval int
cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq) cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
const struct options_table_entry *table, *oe;
struct session *s; struct session *s;
struct winlink *wl; struct winlink *wl;
const struct options_table_entry *table;
struct options *oo; struct options *oo;
int quiet; struct options_entry *o;
const char *optval;
if (args_has(self->args, 's')) { if (args_has(self->args, 's')) {
oo = &global_options; oo = &global_options;
@@ -69,9 +69,9 @@ cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(self->args, 'g')) if (args_has(self->args, 'g'))
oo = &global_w_options; oo = &global_w_options;
else { else {
wl = cmd_find_window(cmdq, args_get(args, 't'), NULL); wl = cmd_find_window(ctx, args_get(args, 't'), NULL);
if (wl == NULL) if (wl == NULL)
return (CMD_RETURN_ERROR); return (-1);
oo = &wl->window->options; oo = &wl->window->options;
} }
} else { } else {
@@ -79,99 +79,19 @@ cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(self->args, 'g')) if (args_has(self->args, 'g'))
oo = &global_s_options; oo = &global_s_options;
else { else {
s = cmd_find_session(cmdq, args_get(args, 't'), 0); s = cmd_find_session(ctx, args_get(args, 't'), 0);
if (s == NULL) if (s == NULL)
return (CMD_RETURN_ERROR); return (-1);
oo = &s->options; oo = &s->options;
} }
} }
quiet = args_has(self->args, 'q');
if (args->argc == 0)
return (cmd_show_options_all(self, cmdq, table, oo));
else
return (cmd_show_options_one(self, cmdq, oo, quiet));
}
enum cmd_retval
cmd_show_options_one(struct cmd *self, struct cmd_q *cmdq,
struct options *oo, int quiet)
{
struct args *args = self->args;
const char *name = args->argv[0];
const struct options_table_entry *table, *oe;
struct options_entry *o;
const char *optval;
retry:
if (*name == '@') {
if ((o = options_find1(oo, name)) == NULL) {
if (quiet)
return (CMD_RETURN_NORMAL);
cmdq_error(cmdq, "unknown option: %s", name);
return (CMD_RETURN_ERROR);
}
if (args_has(self->args, 'v'))
cmdq_print(cmdq, "%s", o->str);
else
cmdq_print(cmdq, "%s \"%s\"", o->name, o->str);
return (CMD_RETURN_NORMAL);
}
table = oe = NULL;
if (options_table_find(name, &table, &oe) != 0) {
cmdq_error(cmdq, "ambiguous option: %s", name);
return (CMD_RETURN_ERROR);
}
if (oe == NULL) {
if (quiet)
return (CMD_RETURN_NORMAL);
cmdq_error(cmdq, "unknown option: %s", name);
return (CMD_RETURN_ERROR);
}
if (oe->style != NULL) {
name = oe->style;
goto retry;
}
if ((o = options_find1(oo, oe->name)) == NULL)
return (CMD_RETURN_NORMAL);
optval = options_table_print_entry(oe, o, args_has(self->args, 'v'));
if (args_has(self->args, 'v'))
cmdq_print(cmdq, "%s", optval);
else
cmdq_print(cmdq, "%s %s", oe->name, optval);
return (CMD_RETURN_NORMAL);
}
enum cmd_retval
cmd_show_options_all(struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *table, struct options *oo)
{
const struct options_table_entry *oe;
struct options_entry *o;
const char *optval;
RB_FOREACH(o, options_tree, &oo->tree) {
if (*o->name == '@') {
if (args_has(self->args, 'v'))
cmdq_print(cmdq, "%s", o->str);
else
cmdq_print(cmdq, "%s \"%s\"", o->name, o->str);
}
}
for (oe = table; oe->name != NULL; oe++) { for (oe = table; oe->name != NULL; oe++) {
if (oe->style != NULL)
continue;
if ((o = options_find1(oo, oe->name)) == NULL) if ((o = options_find1(oo, oe->name)) == NULL)
continue; continue;
optval = options_table_print_entry(oe, o, optval = options_table_print_entry(oe, o);
args_has(self->args, 'v')); ctx->print(ctx, "%s %s", oe->name, optval);
if (args_has(self->args, 'v'))
cmdq_print(cmdq, "%s", optval);
else
cmdq_print(cmdq, "%s %s", oe->name, optval);
} }
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2008 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2008 Tiago Cunha <me@tiagocunha.org>
@@ -18,79 +18,57 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Sources a configuration file. * Sources a configuration file.
*/ */
enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmd_q *); int cmd_source_file_exec(struct cmd *, struct cmd_ctx *);
void cmd_source_file_done(struct cmd_q *);
const struct cmd_entry cmd_source_file_entry = { const struct cmd_entry cmd_source_file_entry = {
"source-file", "source", "source-file", "source",
"", 1, 1, "", 1, 1,
"path", "path",
0, 0,
NULL,
NULL,
cmd_source_file_exec cmd_source_file_exec
}; };
enum cmd_retval int
cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq) cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_q *cmdq1; struct causelist causes;
char *cause; char *cause;
struct window_pane *wp;
int retval;
u_int i;
cmdq1 = cmdq_new(NULL); ARRAY_INIT(&causes);
cmdq1->client = cmdq->client;
cmdq1->emptyfn = cmd_source_file_done;
cmdq1->data = cmdq;
switch (load_cfg(args->argv[0], cmdq1, &cause)) { retval = load_cfg(args->argv[0], ctx, &causes);
case -1: if (ARRAY_EMPTY(&causes))
if (cfg_references == 0) { return (retval);
cmdq_free(cmdq1);
cmdq_error(cmdq, "%s", cause); if (retval == 1 && !RB_EMPTY(&sessions) && ctx->cmdclient != NULL) {
free(cause); wp = RB_MIN(sessions, &sessions)->curw->window->active;
return (CMD_RETURN_ERROR); window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp);
for (i = 0; i < ARRAY_LENGTH(&causes); i++) {
cause = ARRAY_ITEM(&causes, i);
window_copy_add(wp, "%s", cause);
xfree(cause);
}
} else {
for (i = 0; i < ARRAY_LENGTH(&causes); i++) {
cause = ARRAY_ITEM(&causes, i);
ctx->print(ctx, "%s", cause);
xfree(cause);
} }
cfg_add_cause("%s", cause);
free(cause);
/* FALLTHROUGH */
case 0:
if (cfg_references == 0)
cfg_print_causes(cmdq);
cmdq_free(cmdq1);
return (CMD_RETURN_NORMAL);
} }
ARRAY_FREE(&causes);
cmdq->references++; return (retval);
cfg_references++;
cmdq_continue(cmdq1);
return (CMD_RETURN_WAIT);
}
void
cmd_source_file_done(struct cmd_q *cmdq1)
{
struct cmd_q *cmdq = cmdq1->data;
if (cmdq1->client_exit >= 0)
cmdq->client_exit = cmdq1->client_exit;
cmdq_free(cmdq1);
cfg_references--;
if (cmdq_free(cmdq))
return;
if (cfg_references == 0)
cfg_print_causes(cmdq);
cmdq_continue(cmdq);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,10 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -30,21 +27,29 @@
* Split a window (add a new pane). * Split a window (add a new pane).
*/ */
#define SPLIT_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" void cmd_split_window_key_binding(struct cmd *, int);
int cmd_split_window_exec(struct cmd *, struct cmd_ctx *);
enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_split_window_entry = { const struct cmd_entry cmd_split_window_entry = {
"split-window", "splitw", "split-window", "splitw",
"bc:dF:l:hp:Pt:v", 0, -1, "dl:hp:Pt:v", 0, 1,
"[-bdhvP] [-c start-directory] [-F format] [-p percentage|-l size] " "[-dhvP] [-p percentage|-l size] [-t target-pane] [command]",
CMD_TARGET_PANE_USAGE " [command]",
0, 0,
cmd_split_window_key_binding,
NULL,
cmd_split_window_exec cmd_split_window_exec
}; };
enum cmd_retval void
cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_split_window_key_binding(struct cmd *self, int key)
{
self->args = args_create(0);
if (key == '%')
args_set(self->args, 'h', NULL);
}
int
cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s;
@@ -52,61 +57,33 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct window *w; struct window *w;
struct window_pane *wp, *new_wp = NULL; struct window_pane *wp, *new_wp = NULL;
struct environ env; struct environ env;
const char *cmd, *path, *shell, *template; char *cmd, *cwd, *cause;
char **argv, *cause, *new_cause, *cp; const char *shell;
u_int hlimit; u_int hlimit, paneidx;
int argc, size, percentage, cwd, fd = -1; int size, percentage;
enum layout_type type; enum layout_type type;
struct layout_cell *lc; struct layout_cell *lc;
struct format_tree *ft;
struct environ_entry *envent;
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL) if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
w = wl->window; w = wl->window;
server_unzoom_window(w);
environ_init(&env); environ_init(&env);
environ_copy(&global_environ, &env); environ_copy(&global_environ, &env);
environ_copy(&s->environ, &env); environ_copy(&s->environ, &env);
server_fill_environ(s, &env); server_fill_environ(s, &env);
if (args->argc == 0) { if (args->argc == 0)
cmd = options_get_string(&s->options, "default-command"); cmd = options_get_string(&s->options, "default-command");
if (cmd != NULL && *cmd != '\0') {
argc = 1;
argv = (char **)&cmd;
} else {
argc = 0;
argv = NULL;
}
} else {
argc = args->argc;
argv = args->argv;
}
if (args_has(args, 'c')) {
ft = format_create();
format_defaults(ft, cmd_find_client(cmdq, NULL, 1), s, NULL,
NULL);
cp = format_expand(ft, args_get(args, 'c'));
format_free(ft);
if (cp != NULL && *cp != '\0') {
fd = open(cp, O_RDONLY|O_DIRECTORY);
free(cp);
if (fd == -1) {
cmdq_error(cmdq, "bad working directory: %s",
strerror(errno));
return (CMD_RETURN_ERROR);
}
} else if (cp != NULL)
free(cp);
cwd = fd;
} else if (cmdq->client != NULL && cmdq->client->session == NULL)
cwd = cmdq->client->cwd;
else else
cwd = s->cwd; cmd = args->argv[0];
cwd = options_get_string(&s->options, "default-path");
if (*cwd == '\0') {
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
cwd = ctx->cmdclient->cwd;
else
cwd = s->cwd;
}
type = LAYOUT_TOPBOTTOM; type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h')) if (args_has(args, 'h'))
@@ -116,18 +93,16 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(args, 'l')) { if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause); size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) { if (cause != NULL) {
xasprintf(&new_cause, "size %s", cause); ctx->error(ctx, "size %s", cause);
free(cause); xfree(cause);
cause = new_cause; return (-1);
goto error;
} }
} else if (args_has(args, 'p')) { } else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause); percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause);
if (cause != NULL) { if (cause != NULL) {
xasprintf(&new_cause, "percentage %s", cause); ctx->error(ctx, "percentage %s", cause);
free(cause); xfree(cause);
cause = new_cause; return (-1);
goto error;
} }
if (type == LAYOUT_TOPBOTTOM) if (type == LAYOUT_TOPBOTTOM)
size = (wp->sy * percentage) / 100; size = (wp->sy * percentage) / 100;
@@ -140,23 +115,13 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
if (*shell == '\0' || areshell(shell)) if (*shell == '\0' || areshell(shell))
shell = _PATH_BSHELL; shell = _PATH_BSHELL;
lc = layout_split_pane(wp, type, size, args_has(args, 'b')); if ((lc = layout_split_pane(wp, type, size)) == NULL) {
if (lc == NULL) {
cause = xstrdup("pane too small"); cause = xstrdup("pane too small");
goto error; goto error;
} }
new_wp = window_add_pane(w, hlimit); new_wp = window_add_pane(w, hlimit);
if (window_pane_spawn(
path = NULL; new_wp, cmd, shell, cwd, &env, s->tio, &cause) != 0)
if (cmdq->client != NULL && cmdq->client->session == NULL)
envent = environ_find(&cmdq->client->environ, "PATH");
else
envent = environ_find(&s->environ, "PATH");
if (envent != NULL)
path = envent->value;
if (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, &env,
s->tio, &cause) != 0)
goto error; goto error;
layout_assign_pane(lc, new_wp); layout_assign_pane(lc, new_wp);
@@ -172,32 +137,16 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
environ_free(&env); environ_free(&env);
if (args_has(args, 'P')) { if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL) paneidx = window_pane_index(wl->window, new_wp);
template = SPLIT_WINDOW_TEMPLATE; ctx->print(ctx, "%s:%u.%u", s->name, wl->idx, paneidx);
ft = format_create();
format_defaults(ft, cmd_find_client(cmdq, NULL, 1), s, wl,
new_wp);
cp = format_expand(ft, template);
cmdq_print(cmdq, "%s", cp);
free(cp);
format_free(ft);
} }
notify_window_layout_changed(w); return (0);
if (fd != -1)
close(fd);
return (CMD_RETURN_NORMAL);
error: error:
environ_free(&env); environ_free(&env);
if (new_wp != NULL) if (new_wp != NULL)
window_remove_pane(w, new_wp); window_remove_pane(w, new_wp);
cmdq_error(cmdq, "create pane failed: %s", cause); ctx->error(ctx, "create pane failed: %s", cause);
free(cause); xfree(cause);
if (fd != -1) return (-1);
close(fd);
return (CMD_RETURN_ERROR);
} }

View File

@@ -1,6 +1,7 @@
/* $Id$ */
/* /*
* Copyright (c) 2013 Dagobert Michelsen * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
* Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -15,16 +16,29 @@
* 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 <string.h> #include <sys/types.h>
#include "tmux.h" #include "tmux.h"
void /*
cfmakeraw(struct termios *tio) * Start the server and do nothing else.
*/
int cmd_start_server_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_start_server_entry = {
"start-server", "start",
"", 0, 0,
"",
CMD_STARTSERVER,
NULL,
NULL,
cmd_start_server_exec
};
/* ARGSUSED */
int
cmd_start_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
{ {
tio->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); return (0);
tio->c_oflag &= ~OPOST;
tio->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
tio->c_cflag &= ~(CSIZE|PARENB);
tio->c_cflag |= CS8;
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,12 +31,11 @@
* Parse a command from a string. * Parse a command from a string.
*/ */
int cmd_string_getc(const char *, size_t *); int cmd_string_getc(const char *, size_t *);
void cmd_string_ungetc(size_t *); void cmd_string_ungetc(size_t *);
void cmd_string_copy(char **, char *, size_t *); char *cmd_string_string(const char *, size_t *, char, int);
char *cmd_string_string(const char *, size_t *, char, int); char *cmd_string_variable(const char *, size_t *);
char *cmd_string_variable(const char *, size_t *); char *cmd_string_expand_tilde(const char *, size_t *);
char *cmd_string_expand_tilde(const char *, size_t *);
int int
cmd_string_getc(const char *s, size_t *p) cmd_string_getc(const char *s, size_t *p)
@@ -59,8 +58,7 @@ cmd_string_ungetc(size_t *p)
* string, or NULL for empty command. * string, or NULL for empty command.
*/ */
int int
cmd_string_parse(const char *s, struct cmd_list **cmdlist, const char *file, cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
u_int line, char **cause)
{ {
size_t p; size_t p;
int ch, i, argc, rval; int ch, i, argc, rval;
@@ -86,17 +84,26 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, const char *file,
case '\'': case '\'':
if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL) if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL)
goto error; goto error;
cmd_string_copy(&buf, t, &len); buf = xrealloc(buf, 1, len + strlen(t) + 1);
strlcpy(buf + len, t, strlen(t) + 1);
len += strlen(t);
xfree(t);
break; break;
case '"': case '"':
if ((t = cmd_string_string(s, &p, '"', 1)) == NULL) if ((t = cmd_string_string(s, &p, '"', 1)) == NULL)
goto error; goto error;
cmd_string_copy(&buf, t, &len); buf = xrealloc(buf, 1, len + strlen(t) + 1);
strlcpy(buf + len, t, strlen(t) + 1);
len += strlen(t);
xfree(t);
break; break;
case '$': case '$':
if ((t = cmd_string_variable(s, &p)) == NULL) if ((t = cmd_string_variable(s, &p)) == NULL)
goto error; goto error;
cmd_string_copy(&buf, t, &len); buf = xrealloc(buf, 1, len + strlen(t) + 1);
strlcpy(buf + len, t, strlen(t) + 1);
len += strlen(t);
xfree(t);
break; break;
case '#': case '#':
/* Comment: discard rest of line. */ /* Comment: discard rest of line. */
@@ -107,11 +114,10 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, const char *file,
case ' ': case ' ':
case '\t': case '\t':
if (buf != NULL) { if (buf != NULL) {
buf = xrealloc(buf, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len] = '\0'; buf[len] = '\0';
argv = xreallocarray(argv, argc + 1, argv = xrealloc(argv, argc + 1, sizeof *argv);
sizeof *argv);
argv[argc++] = buf; argv[argc++] = buf;
buf = NULL; buf = NULL;
@@ -133,7 +139,7 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, const char *file,
if (argc == 0) if (argc == 0)
goto out; goto out;
*cmdlist = cmd_list_parse(argc, argv, file, line, cause); *cmdlist = cmd_list_parse(argc, argv, cause);
if (*cmdlist == NULL) if (*cmdlist == NULL)
goto out; goto out;
@@ -141,10 +147,12 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, const char *file,
goto out; goto out;
case '~': case '~':
if (buf == NULL) { if (buf == NULL) {
t = cmd_string_expand_tilde(s, &p); if ((t = cmd_string_expand_tilde(s, &p)) == NULL)
if (t == NULL)
goto error; goto error;
cmd_string_copy(&buf, t, &len); buf = xrealloc(buf, 1, len + strlen(t) + 1);
strlcpy(buf + len, t, strlen(t) + 1);
len += strlen(t);
xfree(t);
break; break;
} }
/* FALLTHROUGH */ /* FALLTHROUGH */
@@ -152,7 +160,7 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, const char *file,
if (len >= SIZE_MAX - 2) if (len >= SIZE_MAX - 2)
goto error; goto error;
buf = xrealloc(buf, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len++] = ch; buf[len++] = ch;
break; break;
} }
@@ -162,31 +170,18 @@ error:
xasprintf(cause, "invalid or unknown command: %s", s); xasprintf(cause, "invalid or unknown command: %s", s);
out: out:
free(buf); if (buf != NULL)
xfree(buf);
if (argv != NULL) { if (argv != NULL) {
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
free(argv[i]); xfree(argv[i]);
free(argv); xfree(argv);
} }
return (rval); return (rval);
} }
void
cmd_string_copy(char **dst, char *src, size_t *len)
{
size_t srclen;
srclen = strlen(src);
*dst = xrealloc(*dst, *len + srclen + 1);
strlcpy(*dst + *len, src, srclen + 1);
*len += srclen;
free(src);
}
char * char *
cmd_string_string(const char *s, size_t *p, char endch, int esc) cmd_string_string(const char *s, size_t *p, char endch, int esc)
{ {
@@ -226,22 +221,26 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc)
break; break;
if ((t = cmd_string_variable(s, p)) == NULL) if ((t = cmd_string_variable(s, p)) == NULL)
goto error; goto error;
cmd_string_copy(&buf, t, &len); buf = xrealloc(buf, 1, len + strlen(t) + 1);
strlcpy(buf + len, t, strlen(t) + 1);
len += strlen(t);
xfree(t);
continue; continue;
} }
if (len >= SIZE_MAX - 2) if (len >= SIZE_MAX - 2)
goto error; goto error;
buf = xrealloc(buf, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len++] = ch; buf[len++] = ch;
} }
buf = xrealloc(buf, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len] = '\0'; buf[len] = '\0';
return (buf); return (buf);
error: error:
free(buf); if (buf != NULL)
xfree(buf);
return (NULL); return (NULL);
} }
@@ -279,7 +278,7 @@ cmd_string_variable(const char *s, size_t *p)
return (t); return (t);
} }
buf = xrealloc(buf, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len++] = ch; buf[len++] = ch;
for (;;) { for (;;) {
@@ -289,7 +288,7 @@ cmd_string_variable(const char *s, size_t *p)
else { else {
if (len >= SIZE_MAX - 3) if (len >= SIZE_MAX - 3)
goto error; goto error;
buf = xrealloc(buf, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len++] = ch; buf[len++] = ch;
} }
} }
@@ -300,17 +299,18 @@ cmd_string_variable(const char *s, size_t *p)
if (ch != EOF && fch != '{') if (ch != EOF && fch != '{')
cmd_string_ungetc(p); /* ch */ cmd_string_ungetc(p); /* ch */
buf = xrealloc(buf, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len] = '\0'; buf[len] = '\0';
envent = environ_find(&global_environ, buf); envent = environ_find(&global_environ, buf);
free(buf); xfree(buf);
if (envent == NULL) if (envent == NULL)
return (xstrdup("")); return (xstrdup(""));
return (xstrdup(envent->value)); return (xstrdup(envent->value));
error: error:
free(buf); if (buf != NULL)
xfree(buf);
return (NULL); return (NULL);
} }
@@ -319,13 +319,10 @@ cmd_string_expand_tilde(const char *s, size_t *p)
{ {
struct passwd *pw; struct passwd *pw;
struct environ_entry *envent; struct environ_entry *envent;
char *home, *path, *user, *cp; char *home, *path, *username;
int last;
home = NULL; home = NULL;
if (cmd_string_getc(s, p) == '/') {
last = cmd_string_getc(s, p);
if (last == EOF || last == '/' || last == ' '|| last == '\t') {
envent = environ_find(&global_environ, "HOME"); envent = environ_find(&global_environ, "HOME");
if (envent != NULL && *envent->value != '\0') if (envent != NULL && *envent->value != '\0')
home = envent->value; home = envent->value;
@@ -333,27 +330,15 @@ cmd_string_expand_tilde(const char *s, size_t *p)
home = pw->pw_dir; home = pw->pw_dir;
} else { } else {
cmd_string_ungetc(p); cmd_string_ungetc(p);
if ((username = cmd_string_string(s, p, '/', 0)) == NULL)
cp = user = xmalloc(strlen(s)); return (NULL);
for (;;) { if ((pw = getpwnam(username)) != NULL)
last = cmd_string_getc(s, p);
if (last == EOF || last == '/' || last == ' '|| last == '\t')
break;
*cp++ = last;
}
*cp = '\0';
if ((pw = getpwnam(user)) != NULL)
home = pw->pw_dir; home = pw->pw_dir;
free(user); xfree(username);
} }
if (home == NULL) if (home == NULL)
return (NULL); return (NULL);
if (last != EOF) xasprintf(&path, "%s/", home);
xasprintf(&path, "%s%c", home, last);
else
xasprintf(&path, "%s", home);
return (path); return (path);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2012 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,38 +18,39 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
/* Get cell width. */ /*
u_int * Suspend client with SIGTSTP.
grid_cell_width(const struct grid_cell *gc) */
{
return (gc->xstate >> 4);
}
/* Get cell data. */ int cmd_suspend_client_exec(struct cmd *, struct cmd_ctx *);
void
grid_cell_get(const struct grid_cell *gc, struct utf8_data *ud)
{
ud->size = gc->xstate & 0xf;
ud->width = gc->xstate >> 4;
memcpy(ud->data, gc->xdata, ud->size);
}
/* Set cell data. */ const struct cmd_entry cmd_suspend_client_entry = {
void "suspend-client", "suspendc",
grid_cell_set(struct grid_cell *gc, const struct utf8_data *ud) "t:", 0, 0,
{ CMD_TARGET_CLIENT_USAGE,
memcpy(gc->xdata, ud->data, ud->size); 0,
gc->xstate = (ud->width << 4) | ud->size; NULL,
} NULL,
cmd_suspend_client_exec
};
/* Set a single character as cell data. */ int
void cmd_suspend_client_exec(struct cmd *self, struct cmd_ctx *ctx)
grid_cell_one(struct grid_cell *gc, u_char ch)
{ {
*gc->xdata = ch; struct args *args = self->args;
gc->xstate = (1 << 4) | 1; struct client *c;
if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
return (-1);
tty_stop_tty(&c->tty);
c->flags |= CLIENT_SUSPENDED;
server_write_client(c, MSG_SUSPEND, NULL, 0);
return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,18 +26,31 @@
* Swap two panes. * Swap two panes.
*/ */
enum cmd_retval cmd_swap_pane_exec(struct cmd *, struct cmd_q *); void cmd_swap_pane_key_binding(struct cmd *, int);
int cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_swap_pane_entry = { const struct cmd_entry cmd_swap_pane_entry = {
"swap-pane", "swapp", "swap-pane", "swapp",
"dDs:t:U", 0, 0, "dDs:t:U", 0, 0,
"[-dDU] " CMD_SRCDST_PANE_USAGE, "[-dDU] " CMD_SRCDST_PANE_USAGE,
0, 0,
cmd_swap_pane_key_binding,
NULL,
cmd_swap_pane_exec cmd_swap_pane_exec
}; };
enum cmd_retval void
cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_swap_pane_key_binding(struct cmd *self, int key)
{
self->args = args_create(0);
if (key == '{')
args_set(self->args, 'U', NULL);
else if (key == '}')
args_set(self->args, 'D', NULL);
}
int
cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *src_wl, *dst_wl; struct winlink *src_wl, *dst_wl;
@@ -46,11 +59,10 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq)
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_wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &dst_wp); dst_wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &dst_wp);
if (dst_wl == NULL) if (dst_wl == NULL)
return (CMD_RETURN_ERROR); return (-1);
dst_w = dst_wl->window; dst_w = dst_wl->window;
server_unzoom_window(dst_w);
if (!args_has(args, 's')) { if (!args_has(args, 's')) {
src_w = dst_w; src_w = dst_w;
@@ -62,22 +74,17 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq)
src_wp = TAILQ_PREV(dst_wp, window_panes, entry); src_wp = TAILQ_PREV(dst_wp, window_panes, entry);
if (src_wp == NULL) if (src_wp == NULL)
src_wp = TAILQ_LAST(&dst_w->panes, window_panes); src_wp = TAILQ_LAST(&dst_w->panes, window_panes);
} else { } else
src_wl = cmd_find_pane(cmdq, NULL, NULL, &src_wp); return (0);
if (src_wl == NULL)
return (CMD_RETURN_ERROR);
src_w = src_wl->window;
}
} else { } else {
src_wl = cmd_find_pane(cmdq, args_get(args, 's'), NULL, &src_wp); src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp);
if (src_wl == NULL) if (src_wl == NULL)
return (CMD_RETURN_ERROR); return (-1);
src_w = src_wl->window; src_w = src_wl->window;
} }
server_unzoom_window(src_w);
if (src_wp == dst_wp) if (src_wp == dst_wp)
return (CMD_RETURN_NORMAL); return (0);
tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry); tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry);
TAILQ_REMOVE(&dst_w->panes, dst_wp, entry); TAILQ_REMOVE(&dst_w->panes, dst_wp, entry);
@@ -131,5 +138,5 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq)
server_redraw_window(src_w); server_redraw_window(src_w);
server_redraw_window(dst_w); server_redraw_window(dst_w);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,18 +26,20 @@
* Swap one window with another. * Swap one window with another.
*/ */
enum cmd_retval cmd_swap_window_exec(struct cmd *, struct cmd_q *); int cmd_swap_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_swap_window_entry = { const struct cmd_entry cmd_swap_window_entry = {
"swap-window", "swapw", "swap-window", "swapw",
"ds:t:", 0, 0, "ds:t:", 0, 0,
"[-d] " CMD_SRCDST_WINDOW_USAGE, "[-d] " CMD_SRCDST_WINDOW_USAGE,
0, 0,
NULL,
NULL,
cmd_swap_window_exec cmd_swap_window_exec
}; };
enum cmd_retval int
cmd_swap_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
const char *target_src, *target_dst; const char *target_src, *target_dst;
@@ -47,22 +49,22 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct window *w; struct window *w;
target_src = args_get(args, 's'); target_src = args_get(args, 's');
if ((wl_src = cmd_find_window(cmdq, target_src, &src)) == NULL) if ((wl_src = cmd_find_window(ctx, target_src, &src)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
target_dst = args_get(args, 't'); target_dst = args_get(args, 't');
if ((wl_dst = cmd_find_window(cmdq, target_dst, &dst)) == NULL) if ((wl_dst = cmd_find_window(ctx, target_dst, &dst)) == NULL)
return (CMD_RETURN_ERROR); return (-1);
sg_src = session_group_find(src); sg_src = session_group_find(src);
sg_dst = session_group_find(dst); sg_dst = session_group_find(dst);
if (src != dst && if (src != dst &&
sg_src != NULL && sg_dst != NULL && sg_src == sg_dst) { sg_src != NULL && sg_dst != NULL && sg_src == sg_dst) {
cmdq_error(cmdq, "can't move window, sessions are grouped"); ctx->error(ctx, "can't move window, sessions are grouped");
return (CMD_RETURN_ERROR); return (-1);
} }
if (wl_dst->window == wl_src->window) if (wl_dst->window == wl_src->window)
return (CMD_RETURN_NORMAL); return (0);
w = wl_dst->window; w = wl_dst->window;
wl_dst->window = wl_src->window; wl_dst->window = wl_src->window;
@@ -81,5 +83,5 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_q *cmdq)
} }
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,82 +27,68 @@
* Switch client to a different session. * Switch client to a different session.
*/ */
enum cmd_retval cmd_switch_client_exec(struct cmd *, struct cmd_q *); void cmd_switch_client_key_binding(struct cmd *, int);
int cmd_switch_client_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_switch_client_entry = { const struct cmd_entry cmd_switch_client_entry = {
"switch-client", "switchc", "switch-client", "switchc",
"lc:npt:r", 0, 0, "lc:npt:", 0, 0,
"[-lnpr] [-c target-client] [-t target-session]", "[-lnp] [-c target-client] [-t target-session]",
CMD_READONLY, 0,
cmd_switch_client_key_binding,
NULL,
cmd_switch_client_exec cmd_switch_client_exec
}; };
enum cmd_retval void
cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq) cmd_switch_client_key_binding(struct cmd *self, int key)
{ {
struct args *args = self->args; self->args = args_create(0);
struct client *c; switch (key) {
struct session *s = NULL; case '(':
struct winlink *wl = NULL; args_set(self->args, 'p', NULL);
struct window *w = NULL; break;
struct window_pane *wp = NULL; case ')':
const char *tflag; args_set(self->args, 'n', NULL);
break;
if ((c = cmd_find_client(cmdq, args_get(args, 'c'), 0)) == NULL) case 'L':
return (CMD_RETURN_ERROR); args_set(self->args, 'l', NULL);
break;
if (args_has(args, 'r')) {
if (c->flags & CLIENT_READONLY)
c->flags &= ~CLIENT_READONLY;
else
c->flags |= CLIENT_READONLY;
} }
}
tflag = args_get(args, 't'); int
cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c;
struct session *s;
if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL)
return (-1);
s = NULL;
if (args_has(args, 'n')) { if (args_has(args, 'n')) {
if ((s = session_next_session(c->session)) == NULL) { if ((s = session_next_session(c->session)) == NULL) {
cmdq_error(cmdq, "can't find next session"); ctx->error(ctx, "can't find next session");
return (CMD_RETURN_ERROR); return (-1);
} }
} else if (args_has(args, 'p')) { } else if (args_has(args, 'p')) {
if ((s = session_previous_session(c->session)) == NULL) { if ((s = session_previous_session(c->session)) == NULL) {
cmdq_error(cmdq, "can't find previous session"); ctx->error(ctx, "can't find previous session");
return (CMD_RETURN_ERROR); return (-1);
} }
} else if (args_has(args, 'l')) { } else if (args_has(args, 'l')) {
if (c->last_session != NULL && session_alive(c->last_session)) if (c->last_session != NULL && session_alive(c->last_session))
s = c->last_session; s = c->last_session;
if (s == NULL) { if (s == NULL) {
cmdq_error(cmdq, "can't find last session"); ctx->error(ctx, "can't find last session");
return (CMD_RETURN_ERROR); return (-1);
} }
} else { } else
if (tflag == NULL) { s = cmd_find_session(ctx, args_get(args, 't'), 0);
if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) if (s == NULL)
return (CMD_RETURN_ERROR); return (-1);
} else if (tflag[strcspn(tflag, ":.")] != '\0') {
if ((wl = cmd_find_pane(cmdq, tflag, &s, &wp)) == NULL)
return (CMD_RETURN_ERROR);
} else {
if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL)
return (CMD_RETURN_ERROR);
w = cmd_lookup_windowid(tflag);
if (w == NULL &&
(wp = cmd_lookup_paneid(tflag)) != NULL)
w = wp->window;
if (w != NULL)
wl = winlink_find_by_window(&s->windows, w);
}
if (cmdq->client == NULL)
return (CMD_RETURN_NORMAL);
if (wl != NULL) {
if (wp != NULL)
window_set_active_pane(wp->window, wp);
session_set_current(s, wl);
}
}
if (c->session != NULL) if (c->session != NULL)
c->last_session = c->session; c->last_session = c->session;
@@ -112,7 +98,6 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
recalculate_sizes(); recalculate_sizes();
server_check_unattached(); server_check_unattached();
server_redraw_client(c); server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,69 +18,71 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Unbind key from command. * Unbind key from command.
*/ */
enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmd_q *); int cmd_unbind_key_check(struct args *);
enum cmd_retval cmd_unbind_key_mode_table(struct cmd *, struct cmd_q *, int); int cmd_unbind_key_exec(struct cmd *, struct cmd_ctx *);
int cmd_unbind_key_table(struct cmd *, struct cmd_ctx *, int);
const struct cmd_entry cmd_unbind_key_entry = { const struct cmd_entry cmd_unbind_key_entry = {
"unbind-key", "unbind", "unbind-key", "unbind",
"acnt:", 0, 1, "acnt:", 0, 1,
"[-acn] [-t mode-table] key", "[-acn] [-t key-table] key",
0, 0,
NULL,
cmd_unbind_key_check,
cmd_unbind_key_exec cmd_unbind_key_exec
}; };
enum cmd_retval int
cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) cmd_unbind_key_check(struct args *args)
{
if (args_has(args, 'a') && (args->argc != 0 || args_has(args, 't')))
return (-1);
if (!args_has(args, 'a') && args->argc != 1)
return (-1);
return (0);
}
int
cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct key_binding *bd; struct key_binding *bd;
int key; int key;
if (!args_has(args, 'a')) { if (args_has(args, 'a')) {
if (args->argc != 1) { while (!SPLAY_EMPTY(&key_bindings)) {
cmdq_error(cmdq, "missing key"); bd = SPLAY_ROOT(&key_bindings);
return (CMD_RETURN_ERROR); SPLAY_REMOVE(key_bindings, &key_bindings, bd);
cmd_list_free(bd->cmdlist);
xfree(bd);
} }
key = key_string_lookup_string(args->argv[0]); return (0);
if (key == KEYC_NONE) { }
cmdq_error(cmdq, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR); key = key_string_lookup_string(args->argv[0]);
} if (key == KEYC_NONE) {
} else { ctx->error(ctx, "unknown key: %s", args->argv[0]);
if (args->argc != 0) { return (-1);
cmdq_error(cmdq, "key given with -a");
return (CMD_RETURN_ERROR);
}
key = KEYC_NONE;
} }
if (args_has(args, 't')) if (args_has(args, 't'))
return (cmd_unbind_key_mode_table(self, cmdq, key)); return (cmd_unbind_key_table(self, ctx, key));
if (key == KEYC_NONE) {
while (!RB_EMPTY(&key_bindings)) {
bd = RB_ROOT(&key_bindings);
key_bindings_remove(bd->key);
}
return (CMD_RETURN_NORMAL);
}
if (!args_has(args, 'n')) if (!args_has(args, 'n'))
key |= KEYC_PREFIX; key |= KEYC_PREFIX;
key_bindings_remove(key); key_bindings_remove(key);
return (CMD_RETURN_NORMAL); return (0);
} }
enum cmd_retval int
cmd_unbind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, int key) cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
{ {
struct args *args = self->args; struct args *args = self->args;
const char *tablename; const char *tablename;
@@ -89,24 +91,15 @@ cmd_unbind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, int key)
tablename = args_get(args, 't'); tablename = args_get(args, 't');
if ((mtab = mode_key_findtable(tablename)) == NULL) { if ((mtab = mode_key_findtable(tablename)) == NULL) {
cmdq_error(cmdq, "unknown key table: %s", tablename); ctx->error(ctx, "unknown key table: %s", tablename);
return (CMD_RETURN_ERROR); return (-1);
}
if (key == KEYC_NONE) {
while (!RB_EMPTY(mtab->tree)) {
mbind = RB_ROOT(mtab->tree);
RB_REMOVE(mode_key_tree, mtab->tree, mbind);
free(mbind);
}
return (CMD_RETURN_NORMAL);
} }
mtmp.key = key; mtmp.key = key;
mtmp.mode = !!args_has(args, 'c'); mtmp.mode = !!args_has(args, 'c');
if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { if ((mbind = SPLAY_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) {
RB_REMOVE(mode_key_tree, mtab->tree, mbind); SPLAY_REMOVE(mode_key_tree, mtab->tree, mbind);
free(mbind); xfree(mbind);
} }
return (CMD_RETURN_NORMAL); return (0);
} }

70
cmd-unlink-window.c Normal file
View File

@@ -0,0 +1,70 @@
/* $Id$ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Unlink a window, unless it would be destroyed by doing so (only one link).
*/
int cmd_unlink_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_unlink_window_entry = {
"unlink-window", "unlinkw",
"kt:", 0, 0,
"[-k] " CMD_TARGET_WINDOW_USAGE,
0,
NULL,
NULL,
cmd_unlink_window_exec
};
int
cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct winlink *wl;
struct window *w;
struct session *s, *s2;
struct session_group *sg;
u_int references;
if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL)
return (-1);
w = wl->window;
sg = session_group_find(s);
if (sg != NULL) {
references = 0;
TAILQ_FOREACH(s2, &sg->sessions, gentry)
references++;
} else
references = 1;
if (!args_has(self->args, 'k') && w->references == references) {
ctx->error(ctx, "window is only linked to one session");
return (-1);
}
server_unlink_window(s, wl);
recalculate_sizes();
return (0);
}

View File

@@ -1,217 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net>
* Copyright (c) 2013 Thiago de Arruda <tpadilha84@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Block or wake a client on a named wait channel.
*/
enum cmd_retval cmd_wait_for_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_wait_for_entry = {
"wait-for", "wait",
"LSU", 1, 1,
"[-L|-S|-U] channel",
0,
cmd_wait_for_exec
};
struct wait_channel {
const char *name;
int locked;
TAILQ_HEAD(, cmd_q) waiters;
TAILQ_HEAD(, cmd_q) lockers;
RB_ENTRY(wait_channel) entry;
};
RB_HEAD(wait_channels, wait_channel);
struct wait_channels wait_channels = RB_INITIALIZER(wait_channels);
int wait_channel_cmp(struct wait_channel *, struct wait_channel *);
RB_PROTOTYPE(wait_channels, wait_channel, entry, wait_channel_cmp);
RB_GENERATE(wait_channels, wait_channel, entry, wait_channel_cmp);
int
wait_channel_cmp(struct wait_channel *wc1, struct wait_channel *wc2)
{
return (strcmp(wc1->name, wc2->name));
}
enum cmd_retval cmd_wait_for_signal(struct cmd_q *, const char *,
struct wait_channel *);
enum cmd_retval cmd_wait_for_wait(struct cmd_q *, const char *,
struct wait_channel *);
enum cmd_retval cmd_wait_for_lock(struct cmd_q *, const char *,
struct wait_channel *);
enum cmd_retval cmd_wait_for_unlock(struct cmd_q *, const char *,
struct wait_channel *);
enum cmd_retval
cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
const char *name = args->argv[0];
struct wait_channel *wc, wc0;
wc0.name = name;
wc = RB_FIND(wait_channels, &wait_channels, &wc0);
if (args_has(args, 'S'))
return (cmd_wait_for_signal(cmdq, name, wc));
if (args_has(args, 'L'))
return (cmd_wait_for_lock(cmdq, name, wc));
if (args_has(args, 'U'))
return (cmd_wait_for_unlock(cmdq, name, wc));
return (cmd_wait_for_wait(cmdq, name, wc));
}
enum cmd_retval
cmd_wait_for_signal(struct cmd_q *cmdq, const char *name,
struct wait_channel *wc)
{
struct cmd_q *wq, *wq1;
if (wc == NULL || TAILQ_EMPTY(&wc->waiters)) {
cmdq_error(cmdq, "no waiting clients on %s", name);
return (CMD_RETURN_ERROR);
}
TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) {
TAILQ_REMOVE(&wc->waiters, wq, waitentry);
if (!cmdq_free(wq))
cmdq_continue(wq);
}
if (!wc->locked) {
RB_REMOVE(wait_channels, &wait_channels, wc);
free((void *)wc->name);
free(wc);
}
return (CMD_RETURN_NORMAL);
}
enum cmd_retval
cmd_wait_for_wait(struct cmd_q *cmdq, const char *name,
struct wait_channel *wc)
{
if (cmdq->client == NULL || cmdq->client->session != NULL) {
cmdq_error(cmdq, "not able to wait");
return (CMD_RETURN_ERROR);
}
if (wc == NULL) {
wc = xmalloc(sizeof *wc);
wc->name = xstrdup(name);
wc->locked = 0;
TAILQ_INIT(&wc->waiters);
TAILQ_INIT(&wc->lockers);
RB_INSERT(wait_channels, &wait_channels, wc);
}
TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry);
cmdq->references++;
return (CMD_RETURN_WAIT);
}
enum cmd_retval
cmd_wait_for_lock(struct cmd_q *cmdq, const char *name,
struct wait_channel *wc)
{
if (cmdq->client == NULL || cmdq->client->session != NULL) {
cmdq_error(cmdq, "not able to lock");
return (CMD_RETURN_ERROR);
}
if (wc == NULL) {
wc = xmalloc(sizeof *wc);
wc->name = xstrdup(name);
wc->locked = 0;
TAILQ_INIT(&wc->waiters);
TAILQ_INIT(&wc->lockers);
RB_INSERT(wait_channels, &wait_channels, wc);
}
if (wc->locked) {
TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry);
cmdq->references++;
return (CMD_RETURN_WAIT);
}
wc->locked = 1;
return (CMD_RETURN_NORMAL);
}
enum cmd_retval
cmd_wait_for_unlock(struct cmd_q *cmdq, const char *name,
struct wait_channel *wc)
{
struct cmd_q *wq;
if (wc == NULL || !wc->locked) {
cmdq_error(cmdq, "channel %s not locked", name);
return (CMD_RETURN_ERROR);
}
if ((wq = TAILQ_FIRST(&wc->lockers)) != NULL) {
TAILQ_REMOVE(&wc->lockers, wq, waitentry);
if (!cmdq_free(wq))
cmdq_continue(wq);
} else {
wc->locked = 0;
if (TAILQ_EMPTY(&wc->waiters)) {
RB_REMOVE(wait_channels, &wait_channels, wc);
free((void *)wc->name);
free(wc);
}
}
return (CMD_RETURN_NORMAL);
}
void
cmd_wait_for_flush(void)
{
struct wait_channel *wc, *wc1;
struct cmd_q *wq, *wq1;
RB_FOREACH_SAFE(wc, wait_channels, &wait_channels, wc1) {
TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) {
TAILQ_REMOVE(&wc->waiters, wq, waitentry);
if (!cmdq_free(wq))
cmdq_continue(wq);
}
while ((wq = TAILQ_FIRST(&wc->lockers)) != NULL) {
TAILQ_REMOVE(&wc->lockers, wq, waitentry);
if (!cmdq_free(wq))
cmdq_continue(wq);
}
RB_REMOVE(wait_channels, &wait_channels, wc);
free((void *)wc->name);
free(wc);
}
}

452
cmd.c
View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -20,7 +20,6 @@
#include <sys/time.h> #include <sys/time.h>
#include <fnmatch.h> #include <fnmatch.h>
#include <pwd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@@ -35,7 +34,6 @@ const struct cmd_entry *cmd_table[] = {
&cmd_choose_buffer_entry, &cmd_choose_buffer_entry,
&cmd_choose_client_entry, &cmd_choose_client_entry,
&cmd_choose_session_entry, &cmd_choose_session_entry,
&cmd_choose_tree_entry,
&cmd_choose_window_entry, &cmd_choose_window_entry,
&cmd_clear_history_entry, &cmd_clear_history_entry,
&cmd_clock_mode_entry, &cmd_clock_mode_entry,
@@ -68,7 +66,6 @@ const struct cmd_entry *cmd_table[] = {
&cmd_lock_client_entry, &cmd_lock_client_entry,
&cmd_lock_server_entry, &cmd_lock_server_entry,
&cmd_lock_session_entry, &cmd_lock_session_entry,
&cmd_move_pane_entry,
&cmd_move_window_entry, &cmd_move_window_entry,
&cmd_new_session_entry, &cmd_new_session_entry,
&cmd_new_window_entry, &cmd_new_window_entry,
@@ -111,22 +108,19 @@ const struct cmd_entry *cmd_table[] = {
&cmd_switch_client_entry, &cmd_switch_client_entry,
&cmd_unbind_key_entry, &cmd_unbind_key_entry,
&cmd_unlink_window_entry, &cmd_unlink_window_entry,
&cmd_wait_for_entry,
NULL NULL
}; };
int cmd_session_better(struct session *, struct session *, int);
struct session *cmd_choose_session_list(struct sessionslist *); struct session *cmd_choose_session_list(struct sessionslist *);
struct session *cmd_choose_session(int); struct session *cmd_choose_session(int);
struct client *cmd_choose_client(struct clients *); struct client *cmd_choose_client(struct clients *);
struct client *cmd_lookup_client(const char *); struct client *cmd_lookup_client(const char *);
struct session *cmd_lookup_session(struct cmd_q *, const char *, int *); struct session *cmd_lookup_session(const char *, int *);
struct session *cmd_lookup_session_id(const char *);
struct winlink *cmd_lookup_window(struct session *, const char *, int *); struct winlink *cmd_lookup_window(struct session *, const char *, int *);
int cmd_lookup_index(struct session *, const char *, int *); int cmd_lookup_index(struct session *, const char *, int *);
struct winlink *cmd_lookup_winlink_windowid(struct session *, const char *); struct window_pane *cmd_lookup_paneid(const char *);
struct session *cmd_window_session(struct cmd_q *, struct window *, struct session *cmd_pane_session(struct cmd_ctx *,
struct winlink **); struct window_pane *, struct winlink **);
struct winlink *cmd_find_window_offset(const char *, struct session *, int *); struct winlink *cmd_find_window_offset(const char *, struct session *, int *);
int cmd_find_index_offset(const char *, struct session *, int *); int cmd_find_index_offset(const char *, struct session *, int *);
struct window_pane *cmd_find_pane_offset(const char *, struct winlink *); struct window_pane *cmd_find_pane_offset(const char *, struct winlink *);
@@ -137,9 +131,6 @@ cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
size_t arglen; size_t arglen;
int i; int i;
if (argc == 0)
return (0);
*buf = '\0'; *buf = '\0';
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
if (strlcpy(buf, argv[i], len) >= len) if (strlcpy(buf, argv[i], len) >= len)
@@ -179,14 +170,14 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
} }
char ** char **
cmd_copy_argv(int argc, char **argv) cmd_copy_argv(int argc, char *const *argv)
{ {
char **new_argv; char **new_argv;
int i; int i;
if (argc == 0) if (argc == 0)
return (NULL); return (NULL);
new_argv = xcalloc(argc + 1, sizeof *new_argv); new_argv = xcalloc(argc, sizeof *new_argv);
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
if (argv[i] != NULL) if (argv[i] != NULL)
new_argv[i] = xstrdup(argv[i]); new_argv[i] = xstrdup(argv[i]);
@@ -201,39 +192,15 @@ cmd_free_argv(int argc, char **argv)
if (argc == 0) if (argc == 0)
return; return;
for (i = 0; i < argc; i++)
free(argv[i]);
free(argv);
}
char *
cmd_stringify_argv(int argc, char **argv)
{
char *buf;
int i;
size_t len;
if (argc == 0)
return (xstrdup(""));
len = 0;
buf = NULL;
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
len += strlen(argv[i]) + 1; if (argv[i] != NULL)
buf = xrealloc(buf, len); xfree(argv[i]);
if (i == 0)
*buf = '\0';
else
strlcat(buf, " ", len);
strlcat(buf, argv[i], len);
} }
return (buf); xfree(argv);
} }
struct cmd * struct cmd *
cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause) cmd_parse(int argc, char **argv, char **cause)
{ {
const struct cmd_entry **entryp, *entry; const struct cmd_entry **entryp, *entry;
struct cmd *cmd; struct cmd *cmd;
@@ -280,15 +247,12 @@ cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause)
goto usage; goto usage;
if (entry->args_upper != -1 && args->argc > entry->args_upper) if (entry->args_upper != -1 && args->argc > entry->args_upper)
goto usage; goto usage;
if (entry->check != NULL && entry->check(args) != 0)
goto usage;
cmd = xcalloc(1, sizeof *cmd); cmd = xmalloc(sizeof *cmd);
cmd->entry = entry; cmd->entry = entry;
cmd->args = args; cmd->args = args;
if (file != NULL)
cmd->file = xstrdup(file);
cmd->line = line;
return (cmd); return (cmd);
ambiguous: ambiguous:
@@ -312,19 +276,34 @@ usage:
return (NULL); return (NULL);
} }
int
cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx)
{
return (cmd->entry->exec(cmd, ctx));
}
void
cmd_free(struct cmd *cmd)
{
if (cmd->args != NULL)
args_free(cmd->args);
xfree(cmd);
}
size_t size_t
cmd_print(struct cmd *cmd, char *buf, size_t len) cmd_print(struct cmd *cmd, char *buf, size_t len)
{ {
size_t off, used; size_t off, used;
off = xsnprintf(buf, len, "%s ", cmd->entry->name); off = xsnprintf(buf, len, "%s ", cmd->entry->name);
if (off + 1 < len) { if (off < len) {
used = args_print(cmd->args, buf + off, len - off - 1); used = args_print(cmd->args, buf + off, len - off);
if (used == 0) if (used == 0)
off--; buf[off - 1] = '\0';
else else {
off += used; off += used;
buf[off] = '\0'; buf[off] = '\0';
}
} }
return (off); return (off);
} }
@@ -337,32 +316,31 @@ cmd_print(struct cmd *cmd, char *buf, size_t len)
* session from all sessions. * session from all sessions.
*/ */
struct session * struct session *
cmd_current_session(struct cmd_q *cmdq, int prefer_unattached) cmd_current_session(struct cmd_ctx *ctx, int prefer_unattached)
{ {
struct client *c = cmdq->client; struct msg_command_data *data = ctx->msgdata;
struct client *c = ctx->cmdclient;
struct session *s; struct session *s;
struct sessionslist ss; struct sessionslist ss;
struct winlink *wl; struct winlink *wl;
struct window_pane *wp; struct window_pane *wp;
const char *path;
int found; int found;
if (c != NULL && c->session != NULL) if (ctx->curclient != NULL && ctx->curclient->session != NULL)
return (c->session); return (ctx->curclient->session);
/* /*
* If the name of the calling client's pty is known, build a list of * If the name of the calling client's pty is know, build a list of the
* the sessions that contain it and if any choose either the first or * sessions that contain it and if any choose either the first or the
* the newest. * newest.
*/ */
path = c == NULL ? NULL : c->tty.path; if (c != NULL && c->tty.path != NULL) {
if (path != NULL) {
ARRAY_INIT(&ss); ARRAY_INIT(&ss);
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
found = 0; found = 0;
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
TAILQ_FOREACH(wp, &wl->window->panes, entry) { TAILQ_FOREACH(wp, &wl->window->panes, entry) {
if (strcmp(wp->tty, path) == 0) { if (strcmp(wp->tty, c->tty.path) == 0) {
found = 1; found = 1;
break; break;
} }
@@ -380,25 +358,14 @@ cmd_current_session(struct cmd_q *cmdq, int prefer_unattached)
return (s); return (s);
} }
return (cmd_choose_session(prefer_unattached)); /* Use the session from the TMUX environment variable. */
} if (data != NULL && data->pid == getpid() && data->idx != -1) {
s = session_find_by_index(data->idx);
/* Is this session better? */ if (s != NULL)
int return (s);
cmd_session_better(struct session *s, struct session *best,
int prefer_unattached)
{
if (best == NULL)
return (1);
if (prefer_unattached) {
if (!(best->flags & SESSION_UNATTACHED) &&
(s->flags & SESSION_UNATTACHED))
return (1);
else if ((best->flags & SESSION_UNATTACHED) &&
!(s->flags & SESSION_UNATTACHED))
return (0);
} }
return (timercmp(&s->activity_time, &best->activity_time, >));
return (cmd_choose_session(prefer_unattached));
} }
/* /*
@@ -408,14 +375,21 @@ cmd_session_better(struct session *s, struct session *best,
struct session * struct session *
cmd_choose_session(int prefer_unattached) cmd_choose_session(int prefer_unattached)
{ {
struct session *s, *best; struct session *s, *sbest;
struct timeval *tv = NULL;
best = NULL; sbest = NULL;
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
if (cmd_session_better(s, best, prefer_unattached)) if (tv == NULL || timercmp(&s->activity_time, tv, >) ||
best = s; (prefer_unattached &&
!(sbest->flags & SESSION_UNATTACHED) &&
(s->flags & SESSION_UNATTACHED))) {
sbest = s;
tv = &s->activity_time;
}
} }
return (best);
return (sbest);
} }
/* Find the most recently used session from a list. */ /* Find the most recently used session from a list. */
@@ -446,21 +420,21 @@ cmd_choose_session_list(struct sessionslist *ss)
* then of all clients. * then of all clients.
*/ */
struct client * struct client *
cmd_current_client(struct cmd_q *cmdq) cmd_current_client(struct cmd_ctx *ctx)
{ {
struct session *s; struct session *s;
struct client *c; struct client *c;
struct clients cc; struct clients cc;
u_int i; u_int i;
if (cmdq->client != NULL && cmdq->client->session != NULL) if (ctx->curclient != NULL)
return (cmdq->client); return (ctx->curclient);
/* /*
* No current client set. Find the current session and return the * No current client set. Find the current session and return the
* newest of its clients. * newest of its clients.
*/ */
s = cmd_current_session(cmdq, 0); s = cmd_current_session(ctx, 0);
if (s != NULL && !(s->flags & SESSION_UNATTACHED)) { if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
ARRAY_INIT(&cc); ARRAY_INIT(&cc);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
@@ -505,19 +479,15 @@ cmd_choose_client(struct clients *cc)
/* Find the target client or report an error and return NULL. */ /* Find the target client or report an error and return NULL. */
struct client * struct client *
cmd_find_client(struct cmd_q *cmdq, const char *arg, int quiet) cmd_find_client(struct cmd_ctx *ctx, const char *arg)
{ {
struct client *c; struct client *c;
char *tmparg; char *tmparg;
size_t arglen; size_t arglen;
/* A NULL argument means the current client. */ /* A NULL argument means the current client. */
if (arg == NULL) { if (arg == NULL)
c = cmd_current_client(cmdq); return (cmd_current_client(ctx));
if (c == NULL && !quiet)
cmdq_error(cmdq, "no clients");
return (c);
}
tmparg = xstrdup(arg); tmparg = xstrdup(arg);
/* Trim a single trailing colon if any. */ /* Trim a single trailing colon if any. */
@@ -529,10 +499,10 @@ cmd_find_client(struct cmd_q *cmdq, const char *arg, int quiet)
c = cmd_lookup_client(tmparg); c = cmd_lookup_client(tmparg);
/* If no client found, report an error. */ /* If no client found, report an error. */
if (c == NULL && !quiet) if (c == NULL)
cmdq_error(cmdq, "client not found: %s", tmparg); ctx->error(ctx, "client not found: %s", tmparg);
free(tmparg); xfree(tmparg);
return (c); return (c);
} }
@@ -549,7 +519,7 @@ cmd_lookup_client(const char *name)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL || c->tty.path == NULL) if (c == NULL || c->session == NULL)
continue; continue;
path = c->tty.path; path = c->tty.path;
@@ -567,41 +537,14 @@ cmd_lookup_client(const char *name)
return (NULL); return (NULL);
} }
/* Find the target session or report an error and return NULL. */
struct session *
cmd_lookup_session_id(const char *arg)
{
char *endptr;
long id;
if (arg[0] != '$')
return (NULL);
id = strtol(arg + 1, &endptr, 10);
if (arg[1] != '\0' && *endptr == '\0')
return (session_find_by_id(id));
return (NULL);
}
/* Lookup a session by name. If no session is found, NULL is returned. */ /* Lookup a session by name. If no session is found, NULL is returned. */
struct session * struct session *
cmd_lookup_session(struct cmd_q *cmdq, const char *name, int *ambiguous) cmd_lookup_session(const char *name, int *ambiguous)
{ {
struct session *s, *sfound; struct session *s, *sfound;
struct window *w;
struct window_pane *wp;
*ambiguous = 0; *ambiguous = 0;
/* Look for $id first. */
if ((s = cmd_lookup_session_id(name)) != NULL)
return (s);
/* Try as pane or window id. */
if ((wp = cmd_lookup_paneid(name)) != NULL)
return (cmd_window_session(cmdq, wp->window, NULL));
if ((w = cmd_lookup_windowid(name)) != NULL)
return (cmd_window_session(cmdq, w, NULL));
/* /*
* Look for matches. First look for exact matches - session names must * Look for matches. First look for exact matches - session names must
* be unique so an exact match can't be ambigious and can just be * be unique so an exact match can't be ambigious and can just be
@@ -637,30 +580,12 @@ cmd_lookup_session(struct cmd_q *cmdq, const char *name, int *ambiguous)
struct winlink * struct winlink *
cmd_lookup_window(struct session *s, const char *name, int *ambiguous) cmd_lookup_window(struct session *s, const char *name, int *ambiguous)
{ {
struct winlink *wl, *wlfound; struct winlink *wl, *wlfound;
struct window *w; const char *errstr;
struct window_pane *wp; u_int idx;
const char *errstr;
u_int idx;
*ambiguous = 0; *ambiguous = 0;
/* Try as pane or window id. */
if ((wl = cmd_lookup_winlink_windowid(s, name)) != NULL)
return (wl);
/* Lookup as pane or window id. */
if ((wp = cmd_lookup_paneid(name)) != NULL) {
wl = winlink_find_by_window(&s->windows, wp->window);
if (wl != NULL)
return (wl);
}
if ((w = cmd_lookup_windowid(name)) != NULL) {
wl = winlink_find_by_window(&s->windows, w);
if (wl != NULL)
return (wl);
}
/* First see if this is a valid window index in this session. */ /* First see if this is a valid window index in this session. */
idx = strtonum(name, 0, INT_MAX, &errstr); idx = strtonum(name, 0, INT_MAX, &errstr);
if (errstr == NULL) { if (errstr == NULL) {
@@ -723,7 +648,10 @@ cmd_lookup_index(struct session *s, const char *name, int *ambiguous)
return (-1); return (-1);
} }
/* Lookup pane id. An initial % means a pane id. */ /*
* Lookup pane id. An initial % means a pane id. sp must already point to the
* current session.
*/
struct window_pane * struct window_pane *
cmd_lookup_paneid(const char *arg) cmd_lookup_paneid(const char *arg)
{ {
@@ -739,50 +667,19 @@ cmd_lookup_paneid(const char *arg)
return (window_pane_find_by_id(paneid)); return (window_pane_find_by_id(paneid));
} }
/* Lookup window id in a session. An initial @ means a window id. */ /* Find session and winlink for pane. */
struct winlink *
cmd_lookup_winlink_windowid(struct session *s, const char *arg)
{
const char *errstr;
u_int windowid;
if (*arg != '@')
return (NULL);
windowid = strtonum(arg + 1, 0, UINT_MAX, &errstr);
if (errstr != NULL)
return (NULL);
return (winlink_find_by_window_id(&s->windows, windowid));
}
/* Lookup window id. An initial @ means a window id. */
struct window *
cmd_lookup_windowid(const char *arg)
{
const char *errstr;
u_int windowid;
if (*arg != '@')
return (NULL);
windowid = strtonum(arg + 1, 0, UINT_MAX, &errstr);
if (errstr != NULL)
return (NULL);
return (window_find_by_id(windowid));
}
/* Find session and winlink for window. */
struct session * struct session *
cmd_window_session(struct cmd_q *cmdq, struct window *w, struct winlink **wlp) cmd_pane_session(struct cmd_ctx *ctx, struct window_pane *wp,
struct winlink **wlp)
{ {
struct session *s; struct session *s;
struct sessionslist ss; struct sessionslist ss;
struct winlink *wl; struct winlink *wl;
/* If this window is in the current session, return that winlink. */ /* If this pane is in the current session, return that winlink. */
s = cmd_current_session(cmdq, 0); s = cmd_current_session(ctx, 0);
if (s != NULL) { if (s != NULL) {
wl = winlink_find_by_window(&s->windows, w); wl = winlink_find_by_window(&s->windows, wp->window);
if (wl != NULL) { if (wl != NULL) {
if (wlp != NULL) if (wlp != NULL)
*wlp = wl; *wlp = wl;
@@ -790,35 +687,37 @@ cmd_window_session(struct cmd_q *cmdq, struct window *w, struct winlink **wlp)
} }
} }
/* Otherwise choose from all sessions with this window. */ /* Otherwise choose from all sessions with this pane. */
ARRAY_INIT(&ss); ARRAY_INIT(&ss);
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
if (winlink_find_by_window(&s->windows, w) != NULL) if (winlink_find_by_window(&s->windows, wp->window) != NULL)
ARRAY_ADD(&ss, s); ARRAY_ADD(&ss, s);
} }
s = cmd_choose_session_list(&ss); s = cmd_choose_session_list(&ss);
ARRAY_FREE(&ss); ARRAY_FREE(&ss);
if (wlp != NULL) if (wlp != NULL)
*wlp = winlink_find_by_window(&s->windows, w); *wlp = winlink_find_by_window(&s->windows, wp->window);
return (s); return (s);
} }
/* Find the target session or report an error and return NULL. */ /* Find the target session or report an error and return NULL. */
struct session * struct session *
cmd_find_session(struct cmd_q *cmdq, const char *arg, int prefer_unattached) cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached)
{ {
struct session *s; struct session *s;
struct client *c; struct window_pane *wp;
char *tmparg; struct client *c;
size_t arglen; char *tmparg;
int ambiguous; size_t arglen;
int ambiguous;
/* A NULL argument means the current session. */ /* A NULL argument means the current session. */
if (arg == NULL) { if (arg == NULL)
if ((s = cmd_current_session(cmdq, prefer_unattached)) == NULL) return (cmd_current_session(ctx, prefer_unattached));
cmdq_error(cmdq, "can't establish current session");
return (s); /* Lookup as pane id. */
} if ((wp = cmd_lookup_paneid(arg)) != NULL)
return (cmd_pane_session(ctx, wp, NULL));
/* Trim a single trailing colon if any. */ /* Trim a single trailing colon if any. */
tmparg = xstrdup(arg); tmparg = xstrdup(arg);
@@ -828,14 +727,12 @@ cmd_find_session(struct cmd_q *cmdq, const char *arg, int prefer_unattached)
/* An empty session name is the current session. */ /* An empty session name is the current session. */
if (*tmparg == '\0') { if (*tmparg == '\0') {
free(tmparg); xfree(tmparg);
if ((s = cmd_current_session(cmdq, prefer_unattached)) == NULL) return (cmd_current_session(ctx, prefer_unattached));
cmdq_error(cmdq, "can't establish current session");
return (s);
} }
/* Find the session, if any. */ /* Find the session, if any. */
s = cmd_lookup_session(cmdq, tmparg, &ambiguous); s = cmd_lookup_session(tmparg, &ambiguous);
/* If it doesn't, try to match it as a client. */ /* If it doesn't, try to match it as a client. */
if (s == NULL && (c = cmd_lookup_client(tmparg)) != NULL) if (s == NULL && (c = cmd_lookup_client(tmparg)) != NULL)
@@ -844,31 +741,32 @@ cmd_find_session(struct cmd_q *cmdq, const char *arg, int prefer_unattached)
/* If no session found, report an error. */ /* If no session found, report an error. */
if (s == NULL) { if (s == NULL) {
if (ambiguous) if (ambiguous)
cmdq_error(cmdq, "more than one session: %s", tmparg); ctx->error(ctx, "more than one session: %s", tmparg);
else else
cmdq_error(cmdq, "session not found: %s", tmparg); ctx->error(ctx, "session not found: %s", tmparg);
} }
free(tmparg); xfree(tmparg);
return (s); return (s);
} }
/* Find the target session and window or report an error and return NULL. */ /* Find the target session and window or report an error and return NULL. */
struct winlink * struct winlink *
cmd_find_window(struct cmd_q *cmdq, const char *arg, struct session **sp) cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp)
{ {
struct session *s; struct session *s;
struct winlink *wl; struct winlink *wl;
const char *winptr; struct window_pane *wp;
char *sessptr = NULL; const char *winptr;
int ambiguous = 0; char *sessptr = NULL;
int ambiguous = 0;
/* /*
* Find the current session. There must always be a current session, if * Find the current session. There must always be a current session, if
* it can't be found, report an error. * it can't be found, report an error.
*/ */
if ((s = cmd_current_session(cmdq, 0)) == NULL) { if ((s = cmd_current_session(ctx, 0)) == NULL) {
cmdq_error(cmdq, "can't establish current session"); ctx->error(ctx, "can't establish current session");
return (NULL); return (NULL);
} }
@@ -879,6 +777,14 @@ cmd_find_window(struct cmd_q *cmdq, const char *arg, struct session **sp)
return (s->curw); return (s->curw);
} }
/* Lookup as pane id. */
if ((wp = cmd_lookup_paneid(arg)) != NULL) {
s = cmd_pane_session(ctx, wp, &wl);
if (sp != NULL)
*sp = s;
return (wl);
}
/* Time to look at the argument. If it is empty, that is an error. */ /* Time to look at the argument. If it is empty, that is an error. */
if (*arg == '\0') if (*arg == '\0')
goto not_found; goto not_found;
@@ -893,7 +799,7 @@ cmd_find_window(struct cmd_q *cmdq, const char *arg, struct session **sp)
/* Try to lookup the session if present. */ /* Try to lookup the session if present. */
if (*sessptr != '\0') { if (*sessptr != '\0') {
if ((s = cmd_lookup_session(cmdq, sessptr, &ambiguous)) == NULL) if ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL)
goto no_session; goto no_session;
} }
if (sp != NULL) if (sp != NULL)
@@ -907,10 +813,6 @@ cmd_find_window(struct cmd_q *cmdq, const char *arg, struct session **sp)
wl = s->curw; wl = s->curw;
else if (winptr[0] == '!' && winptr[1] == '\0') else if (winptr[0] == '!' && winptr[1] == '\0')
wl = TAILQ_FIRST(&s->lastw); wl = TAILQ_FIRST(&s->lastw);
else if (winptr[0] == '^' && winptr[1] == '\0')
wl = RB_MIN(winlinks, &s->windows);
else if (winptr[0] == '$' && winptr[1] == '\0')
wl = RB_MAX(winlinks, &s->windows);
else if (winptr[0] == '+' || winptr[0] == '-') else if (winptr[0] == '+' || winptr[0] == '-')
wl = cmd_find_window_offset(winptr, s, &ambiguous); wl = cmd_find_window_offset(winptr, s, &ambiguous);
else else
@@ -919,7 +821,7 @@ cmd_find_window(struct cmd_q *cmdq, const char *arg, struct session **sp)
goto not_found; goto not_found;
if (sessptr != NULL) if (sessptr != NULL)
free(sessptr); xfree(sessptr);
return (wl); return (wl);
no_colon: no_colon:
@@ -944,8 +846,7 @@ no_colon:
lookup_session: lookup_session:
if (ambiguous) if (ambiguous)
goto not_found; goto not_found;
if (*arg != '\0' && if (*arg != '\0' && (s = cmd_lookup_session(arg, &ambiguous)) == NULL)
(s = cmd_lookup_session(cmdq, arg, &ambiguous)) == NULL)
goto no_session; goto no_session;
if (sp != NULL) if (sp != NULL)
@@ -955,18 +856,20 @@ lookup_session:
no_session: no_session:
if (ambiguous) if (ambiguous)
cmdq_error(cmdq, "multiple sessions: %s", arg); ctx->error(ctx, "multiple sessions: %s", arg);
else else
cmdq_error(cmdq, "session not found: %s", arg); ctx->error(ctx, "session not found: %s", arg);
free(sessptr); if (sessptr != NULL)
xfree(sessptr);
return (NULL); return (NULL);
not_found: not_found:
if (ambiguous) if (ambiguous)
cmdq_error(cmdq, "multiple windows: %s", arg); ctx->error(ctx, "multiple windows: %s", arg);
else else
cmdq_error(cmdq, "window not found: %s", arg); ctx->error(ctx, "window not found: %s", arg);
free(sessptr); if (sessptr != NULL)
xfree(sessptr);
return (NULL); return (NULL);
} }
@@ -997,7 +900,7 @@ cmd_find_window_offset(const char *winptr, struct session *s, int *ambiguous)
* example if it is going to be created). * example if it is going to be created).
*/ */
int int
cmd_find_index(struct cmd_q *cmdq, const char *arg, struct session **sp) cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp)
{ {
struct session *s; struct session *s;
struct winlink *wl; struct winlink *wl;
@@ -1009,8 +912,8 @@ cmd_find_index(struct cmd_q *cmdq, const char *arg, struct session **sp)
* Find the current session. There must always be a current session, if * Find the current session. There must always be a current session, if
* it can't be found, report an error. * it can't be found, report an error.
*/ */
if ((s = cmd_current_session(cmdq, 0)) == NULL) { if ((s = cmd_current_session(ctx, 0)) == NULL) {
cmdq_error(cmdq, "can't establish current session"); ctx->error(ctx, "can't establish current session");
return (-2); return (-2);
} }
@@ -1035,7 +938,7 @@ cmd_find_index(struct cmd_q *cmdq, const char *arg, struct session **sp)
/* Try to lookup the session if present. */ /* Try to lookup the session if present. */
if (sessptr != NULL && *sessptr != '\0') { if (sessptr != NULL && *sessptr != '\0') {
if ((s = cmd_lookup_session(cmdq, sessptr, &ambiguous)) == NULL) if ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL)
goto no_session; goto no_session;
} }
if (sp != NULL) if (sp != NULL)
@@ -1057,7 +960,8 @@ cmd_find_index(struct cmd_q *cmdq, const char *arg, struct session **sp)
} else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1) } else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1)
goto invalid_index; goto invalid_index;
free(sessptr); if (sessptr != NULL)
xfree(sessptr);
return (idx); return (idx);
no_colon: no_colon:
@@ -1083,8 +987,7 @@ no_colon:
lookup_session: lookup_session:
if (ambiguous) if (ambiguous)
goto not_found; goto not_found;
if (*arg != '\0' && if (*arg != '\0' && (s = cmd_lookup_session(arg, &ambiguous)) == NULL)
(s = cmd_lookup_session(cmdq, arg, &ambiguous)) == NULL)
goto no_session; goto no_session;
if (sp != NULL) if (sp != NULL)
@@ -1094,26 +997,29 @@ lookup_session:
no_session: no_session:
if (ambiguous) if (ambiguous)
cmdq_error(cmdq, "multiple sessions: %s", arg); ctx->error(ctx, "multiple sessions: %s", arg);
else else
cmdq_error(cmdq, "session not found: %s", arg); ctx->error(ctx, "session not found: %s", arg);
free(sessptr); if (sessptr != NULL)
xfree(sessptr);
return (-2); return (-2);
invalid_index: invalid_index:
if (ambiguous) if (ambiguous)
goto not_found; goto not_found;
cmdq_error(cmdq, "invalid index: %s", arg); ctx->error(ctx, "invalid index: %s", arg);
free(sessptr); if (sessptr != NULL)
xfree(sessptr);
return (-2); return (-2);
not_found: not_found:
if (ambiguous) if (ambiguous)
cmdq_error(cmdq, "multiple windows: %s", arg); ctx->error(ctx, "multiple windows: %s", arg);
else else
cmdq_error(cmdq, "window not found: %s", arg); ctx->error(ctx, "window not found: %s", arg);
free(sessptr); if (sessptr != NULL)
xfree(sessptr);
return (-2); return (-2);
} }
@@ -1149,7 +1055,7 @@ cmd_find_index_offset(const char *winptr, struct session *s, int *ambiguous)
* such as mysession:mywindow.0. * such as mysession:mywindow.0.
*/ */
struct winlink * struct winlink *
cmd_find_pane(struct cmd_q *cmdq, cmd_find_pane(struct cmd_ctx *ctx,
const char *arg, struct session **sp, struct window_pane **wpp) const char *arg, struct session **sp, struct window_pane **wpp)
{ {
struct session *s; struct session *s;
@@ -1159,8 +1065,8 @@ cmd_find_pane(struct cmd_q *cmdq,
u_int idx; u_int idx;
/* Get the current session. */ /* Get the current session. */
if ((s = cmd_current_session(cmdq, 0)) == NULL) { if ((s = cmd_current_session(ctx, 0)) == NULL) {
cmdq_error(cmdq, "can't establish current session"); ctx->error(ctx, "can't establish current session");
return (NULL); return (NULL);
} }
if (sp != NULL) if (sp != NULL)
@@ -1174,7 +1080,7 @@ cmd_find_pane(struct cmd_q *cmdq,
/* Lookup as pane id. */ /* Lookup as pane id. */
if ((*wpp = cmd_lookup_paneid(arg)) != NULL) { if ((*wpp = cmd_lookup_paneid(arg)) != NULL) {
s = cmd_window_session(cmdq, (*wpp)->window, &wl); s = cmd_pane_session(ctx, *wpp, &wl);
if (sp != NULL) if (sp != NULL)
*sp = s; *sp = s;
return (wl); return (wl);
@@ -1189,7 +1095,7 @@ cmd_find_pane(struct cmd_q *cmdq,
winptr[period - arg] = '\0'; winptr[period - arg] = '\0';
if (*winptr == '\0') if (*winptr == '\0')
wl = s->curw; wl = s->curw;
else if ((wl = cmd_find_window(cmdq, winptr, sp)) == NULL) else if ((wl = cmd_find_window(ctx, winptr, sp)) == NULL)
goto error; goto error;
/* Find the pane section and look it up. */ /* Find the pane section and look it up. */
@@ -1198,13 +1104,7 @@ cmd_find_pane(struct cmd_q *cmdq,
*wpp = wl->window->active; *wpp = wl->window->active;
else if (paneptr[0] == '+' || paneptr[0] == '-') else if (paneptr[0] == '+' || paneptr[0] == '-')
*wpp = cmd_find_pane_offset(paneptr, wl); *wpp = cmd_find_pane_offset(paneptr, wl);
else if (paneptr[0] == '!' && paneptr[1] == '\0') { else {
if (wl->window->last == NULL) {
cmdq_error(cmdq, "no last pane");
goto error;
}
*wpp = wl->window->last;
} else {
idx = strtonum(paneptr, 0, INT_MAX, &errstr); idx = strtonum(paneptr, 0, INT_MAX, &errstr);
if (errstr != NULL) if (errstr != NULL)
goto lookup_string; goto lookup_string;
@@ -1213,17 +1113,17 @@ cmd_find_pane(struct cmd_q *cmdq,
goto lookup_string; goto lookup_string;
} }
free(winptr); xfree(winptr);
return (wl); return (wl);
lookup_string: lookup_string:
/* Try pane string description. */ /* Try pane string description. */
if ((*wpp = window_find_string(wl->window, paneptr)) == NULL) { if ((*wpp = window_find_string(wl->window, paneptr)) == NULL) {
cmdq_error(cmdq, "can't find pane: %s", paneptr); ctx->error(ctx, "can't find pane: %s", paneptr);
goto error; goto error;
} }
free(winptr); xfree(winptr);
return (wl); return (wl);
no_period: no_period:
@@ -1244,12 +1144,12 @@ lookup_window:
return (s->curw); return (s->curw);
/* Try as a window and use the active pane. */ /* Try as a window and use the active pane. */
if ((wl = cmd_find_window(cmdq, arg, sp)) != NULL) if ((wl = cmd_find_window(ctx, arg, sp)) != NULL)
*wpp = wl->window->active; *wpp = wl->window->active;
return (wl); return (wl);
error: error:
free(winptr); xfree(winptr);
return (NULL); return (NULL);
} }
@@ -1274,14 +1174,14 @@ cmd_find_pane_offset(const char *paneptr, struct winlink *wl)
/* Replace the first %% or %idx in template by s. */ /* Replace the first %% or %idx in template by s. */
char * char *
cmd_template_replace(const char *template, const char *s, int idx) cmd_template_replace(char *template, const char *s, int idx)
{ {
char ch, *buf; char ch;
const char *ptr; char *buf, *ptr;
int replaced; int replaced;
size_t len; size_t len;
if (strchr(template, '%') == NULL) if (strstr(template, "%") == NULL)
return (xstrdup(template)); return (xstrdup(template));
buf = xmalloc(1); buf = xmalloc(1);
@@ -1301,11 +1201,11 @@ cmd_template_replace(const char *template, const char *s, int idx)
ptr++; ptr++;
len += strlen(s); len += strlen(s);
buf = xrealloc(buf, len + 1); buf = xrealloc(buf, 1, len + 1);
strlcat(buf, s, len + 1); strlcat(buf, s, len + 1);
continue; continue;
} }
buf = xrealloc(buf, len + 2); buf = xrealloc(buf, 1, len + 2);
buf[len++] = ch; buf[len++] = ch;
buf[len] = '\0'; buf[len] = '\0';
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -19,6 +19,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h> #include <ctype.h>
#include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -40,7 +41,7 @@ struct colour_rgb {
struct colour_rgb *colour_rgb_256; struct colour_rgb *colour_rgb_256;
void colour_rgb_generate256(void); void colour_rgb_generate256(void);
u_int colour_rgb_distance(struct colour_rgb *, struct colour_rgb *); double colour_rgb_distance(struct colour_rgb *, struct colour_rgb *);
int colour_rgb_find(struct colour_rgb *); int colour_rgb_find(struct colour_rgb *);
/* Generate 256 colour RGB table. */ /* Generate 256 colour RGB table. */
@@ -90,7 +91,7 @@ colour_rgb_generate256(void)
} }
/* Get colour RGB distance. */ /* Get colour RGB distance. */
u_int double
colour_rgb_distance(struct colour_rgb *rgb1, struct colour_rgb *rgb2) colour_rgb_distance(struct colour_rgb *rgb1, struct colour_rgb *rgb2)
{ {
int r, g, b; int r, g, b;
@@ -98,20 +99,21 @@ colour_rgb_distance(struct colour_rgb *rgb1, struct colour_rgb *rgb2)
r = rgb1->r - rgb2->r; r = rgb1->r - rgb2->r;
g = rgb1->g - rgb2->g; g = rgb1->g - rgb2->g;
b = rgb1->b - rgb2->b; b = rgb1->b - rgb2->b;
return (r * r + g * g + b * b); return (sqrt(r * r + g * g + b * b));
} }
/* Work out the nearest colour from the 256 colour set. */ /* Work out the nearest colour from the 256 colour set. */
int int
colour_rgb_find(struct colour_rgb *rgb) colour_rgb_find(struct colour_rgb *rgb)
{ {
u_int distance, lowest, colour, i; double distance, lowest;
u_int colour, i;
if (colour_rgb_256 == NULL) if (colour_rgb_256 == NULL)
colour_rgb_generate256(); colour_rgb_generate256();
colour = 16; colour = 16;
lowest = UINT_MAX; lowest = INFINITY;
for (i = 0; i < 240; i++) { for (i = 0; i < 240; i++) {
distance = colour_rgb_distance(&colour_rgb_256[i], rgb); distance = colour_rgb_distance(&colour_rgb_256[i], rgb);
if (distance < lowest) { if (distance < lowest) {
@@ -170,22 +172,6 @@ colour_tostring(int c)
return ("white"); return ("white");
case 8: case 8:
return ("default"); return ("default");
case 90:
return ("brightblack");
case 91:
return ("brightred");
case 92:
return ("brightgreen");
case 93:
return ("brightyellow");
case 94:
return ("brightblue");
case 95:
return ("brightmagenta");
case 96:
return ("brightcyan");
case 97:
return ("brightwhite");
} }
return (NULL); return (NULL);
} }
@@ -235,30 +221,6 @@ colour_fromstring(const char *s)
return (7); return (7);
if (strcasecmp(s, "default") == 0 || (s[0] == '8' && s[1] == '\0')) if (strcasecmp(s, "default") == 0 || (s[0] == '8' && s[1] == '\0'))
return (8); return (8);
if (strcasecmp(s, "brightblack") == 0 ||
(s[0] == '9' && s[1] == '0' && s[2] == '\0'))
return (90);
if (strcasecmp(s, "brightred") == 0 ||
(s[0] == '9' && s[1] == '1' && s[2] == '\0'))
return (91);
if (strcasecmp(s, "brightgreen") == 0 ||
(s[0] == '9' && s[1] == '2' && s[2] == '\0'))
return (92);
if (strcasecmp(s, "brightyellow") == 0 ||
(s[0] == '9' && s[1] == '3' && s[2] == '\0'))
return (93);
if (strcasecmp(s, "brightblue") == 0 ||
(s[0] == '9' && s[1] == '4' && s[2] == '\0'))
return (94);
if (strcasecmp(s, "brightmagenta") == 0 ||
(s[0] == '9' && s[1] == '5' && s[2] == '\0'))
return (95);
if (strcasecmp(s, "brightcyan") == 0 ||
(s[0] == '9' && s[1] == '6' && s[2] == '\0'))
return (96);
if (strcasecmp(s, "brightwhite") == 0 ||
(s[0] == '9' && s[1] == '7' && s[2] == '\0'))
return (97);
return (-1); return (-1);
} }
@@ -287,3 +249,29 @@ colour_256to16(u_char c)
return (table[c]); return (table[c]);
} }
/* Convert 256 colour palette to 88. */
u_char
colour_256to88(u_char c)
{
static const u_char table[256] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 17, 18, 18, 19, 20, 21, 21, 22, 22, 23, 20, 21, 21, 22,
22, 23, 24, 25, 25, 26, 26, 27, 24, 25, 25, 26, 26, 27, 28, 29,
29, 30, 30, 31, 32, 33, 33, 34, 34, 35, 36, 37, 37, 38, 38, 39,
36, 37, 37, 38, 38, 39, 40, 41, 41, 42, 42, 43, 40, 41, 41, 42,
42, 43, 44, 45, 45, 46, 46, 47, 32, 33, 33, 34, 34, 35, 36, 37,
37, 38, 38, 39, 36, 37, 37, 38, 38, 39, 40, 41, 41, 42, 42, 43,
40, 41, 41, 42, 42, 43, 44, 45, 45, 46, 46, 47, 48, 49, 49, 50,
50, 51, 52, 53, 53, 54, 54, 55, 52, 53, 53, 54, 54, 55, 56, 57,
57, 58, 58, 59, 56, 57, 57, 58, 58, 59, 60, 61, 61, 62, 62, 63,
48, 49, 49, 50, 50, 51, 52, 53, 53, 54, 54, 55, 52, 53, 53, 54,
54, 55, 56, 57, 57, 58, 58, 59, 56, 57, 57, 58, 58, 59, 60, 61,
61, 62, 62, 63, 64, 65, 65, 66, 66, 67, 68, 69, 69, 70, 70, 71,
68, 69, 69, 70, 70, 71, 72, 73, 73, 74, 74, 75, 72, 73, 73, 74,
74, 75, 76, 77, 77, 78, 78, 79, 0, 0, 80, 80, 80, 81, 81, 81,
82, 82, 82, 83, 83, 83, 84, 84, 84, 85, 85, 85, 86, 86, 86, 87
};
return (table[c]);
}

View File

@@ -30,10 +30,6 @@
#define __packed __attribute__ ((__packed__)) #define __packed __attribute__ ((__packed__))
#endif #endif
#ifndef ECHOPRT
#define ECHOPRT 0
#endif
#ifndef HAVE_BSD_TYPES #ifndef HAVE_BSD_TYPES
typedef uint8_t u_int8_t; typedef uint8_t u_int8_t;
typedef uint16_t u_int16_t; typedef uint16_t u_int16_t;
@@ -125,10 +121,6 @@ typedef uint64_t u_int64_t;
#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len)) #define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
#endif #endif
#ifndef O_DIRECTORY
#define O_DIRECTORY 0
#endif
#ifndef INFTIM #ifndef INFTIM
#define INFTIM -1 #define INFTIM -1
#endif #endif
@@ -160,33 +152,10 @@ typedef uint64_t u_int64_t;
} while (0) } while (0)
#endif #endif
#ifndef timersub
#define timersub(tvp, uvp, vvp) \
do { \
(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
if ((vvp)->tv_usec < 0) { \
(vvp)->tv_sec--; \
(vvp)->tv_usec += 1000000; \
} \
} while (0)
#endif
#ifndef TTY_NAME_MAX #ifndef TTY_NAME_MAX
#define TTY_NAME_MAX 32 #define TTY_NAME_MAX 32
#endif #endif
#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 255
#endif
#ifndef HAVE_FLOCK
#define LOCK_SH 0
#define LOCK_EX 0
#define LOCK_NB 0
#define flock(fd, op) (0)
#endif
#ifndef HAVE_BZERO #ifndef HAVE_BZERO
#undef bzero #undef bzero
#define bzero(buf, len) memset(buf, 0, len); #define bzero(buf, len) memset(buf, 0, len);
@@ -227,12 +196,6 @@ size_t strlcat(char *, const char *, size_t);
int daemon(int, int); int daemon(int, int);
#endif #endif
#ifndef HAVE_B64_NTOP
/* b64_ntop.c */
#undef b64_ntop /* for Cygwin */
int b64_ntop(const char *, size_t, char *, size_t);
#endif
#ifndef HAVE_FORKPTY #ifndef HAVE_FORKPTY
/* forkpty.c */ /* forkpty.c */
#include <sys/ioctl.h> #include <sys/ioctl.h>
@@ -250,27 +213,12 @@ int vasprintf(char **, const char *, va_list);
char *fgetln(FILE *, size_t *); char *fgetln(FILE *, size_t *);
#endif #endif
#ifndef HAVE_FPARSELN
char *fparseln(FILE *, size_t *, size_t *, const char *, int);
#endif
#ifndef HAVE_SETENV #ifndef HAVE_SETENV
/* setenv.c */ /* setenv.c */
int setenv(const char *, const char *, int); int setenv(const char *, const char *, int);
int unsetenv(const char *); int unsetenv(const char *);
#endif #endif
#ifndef HAVE_CFMAKERAW
/* cfmakeraw.c */
void cfmakeraw(struct termios *);
#endif
#ifndef HAVE_OPENAT
/* openat.c */
#define AT_FDCWD -100
int openat(int, const char *, int, ...);
#endif
#ifdef HAVE_GETOPT #ifdef HAVE_GETOPT
#include <getopt.h> #include <getopt.h>
#else #else

View File

@@ -1,3 +1,5 @@
/* $Id$ */
/* /*
* Copyright (c) 2006 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2006 Nicholas Marriott <nicm@users.sourceforge.net>
* *
@@ -42,24 +44,19 @@ int
vasprintf(char **ret, const char *fmt, va_list ap) vasprintf(char **ret, const char *fmt, va_list ap)
{ {
int n; int n;
va_list ap2;
va_copy(ap2, ap);
if ((n = vsnprintf(NULL, 0, fmt, ap)) < 0) if ((n = vsnprintf(NULL, 0, fmt, ap)) < 0)
goto error; goto error;
*ret = xmalloc(n + 1); *ret = xmalloc(n + 1);
if ((n = vsnprintf(*ret, n + 1, fmt, ap2)) < 0) { if ((n = vsnprintf(*ret, n + 1, fmt, ap)) < 0) {
free(*ret); xfree(*ret);
goto error; goto error;
} }
va_end(ap2);
return (n); return (n);
error: error:
va_end(ap2);
*ret = NULL; *ret = NULL;
return (-1); return (-1);
} }

View File

@@ -1,182 +0,0 @@
/*
* Copyright (c) 1996, 1998 by Internet Software Consortium.
*
* 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
/*
* Portions Copyright (c) 1995 by International Business Machines, Inc.
*
* International Business Machines, Inc. (hereinafter called IBM) grants
* permission under its copyrights to use, copy, modify, and distribute this
* Software with or without fee, provided that the above copyright notice and
* all paragraphs of this notice appear in all copies, and that the name of IBM
* not be used in connection with the marketing of any product incorporating
* the Software or modifications thereof, without specific, written prior
* permission.
*
* To the extent it has a right to do so, IBM grants an immunity from suit
* under its patents, if any, for the use, sale or manufacture of products to
* the extent that such products are used for performing Domain Name System
* dynamic updates in TCP/IP networks by means of the Software. No immunity is
* granted for any product per se or for any other function of any product.
*
* THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
* DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
* IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Assert(Cond) if (!(Cond)) abort()
static const char Base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char Pad64 = '=';
/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
The following encoding technique is taken from RFC 1521 by Borenstein
and Freed. It is reproduced here in a slightly edited form for
convenience.
A 65-character subset of US-ASCII is used, enabling 6 bits to be
represented per printable character. (The extra 65th character, "=",
is used to signify a special processing function.)
The encoding process represents 24-bit groups of input bits as output
strings of 4 encoded characters. Proceeding from left to right, a
24-bit input group is formed by concatenating 3 8-bit input groups.
These 24 bits are then treated as 4 concatenated 6-bit groups, each
of which is translated into a single digit in the base64 alphabet.
Each 6-bit group is used as an index into an array of 64 printable
characters. The character referenced by the index is placed in the
output string.
Table 1: The Base64 Alphabet
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w (pad) =
15 P 32 g 49 x
16 Q 33 h 50 y
Special processing is performed if fewer than 24 bits are available
at the end of the data being encoded. A full encoding quantum is
always completed at the end of a quantity. When fewer than 24 input
bits are available in an input group, zero bits are added (on the
right) to form an integral number of 6-bit groups. Padding at the
end of the data is performed using the '=' character.
Since all base64 input is an integral number of octets, only the
-------------------------------------------------
following cases can arise:
(1) the final quantum of encoding input is an integral
multiple of 24 bits; here, the final unit of encoded
output will be an integral multiple of 4 characters
with no "=" padding,
(2) the final quantum of encoding input is exactly 8 bits;
here, the final unit of encoded output will be two
characters followed by two "=" padding characters, or
(3) the final quantum of encoding input is exactly 16 bits;
here, the final unit of encoded output will be three
characters followed by one "=" padding character.
*/
int
b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) {
size_t datalength = 0;
uint8_t input[3];
uint8_t output[4];
size_t i;
while (2 < srclength) {
input[0] = *src++;
input[1] = *src++;
input[2] = *src++;
srclength -= 3;
output[0] = input[0] >> 2;
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
output[3] = input[2] & 0x3f;
Assert(output[0] < 64);
Assert(output[1] < 64);
Assert(output[2] < 64);
Assert(output[3] < 64);
if (datalength + 4 > targsize)
return (-1);
target[datalength++] = Base64[output[0]];
target[datalength++] = Base64[output[1]];
target[datalength++] = Base64[output[2]];
target[datalength++] = Base64[output[3]];
}
/* Now we worry about padding. */
if (0 != srclength) {
/* Get what's left. */
input[0] = input[1] = input[2] = '\0';
for (i = 0; i < srclength; i++)
input[i] = *src++;
output[0] = input[0] >> 2;
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
Assert(output[0] < 64);
Assert(output[1] < 64);
Assert(output[2] < 64);
if (datalength + 4 > targsize)
return (-1);
target[datalength++] = Base64[output[0]];
target[datalength++] = Base64[output[1]];
if (srclength == 1)
target[datalength++] = Pad64;
else
target[datalength++] = Base64[output[2]];
target[datalength++] = Pad64;
}
if (datalength >= targsize)
return (-1);
target[datalength] = '\0'; /* Returned value doesn't count \0. */
return (datalength);
}

View File

@@ -1,3 +1,4 @@
/* $Id$ */
/* $OpenBSD: bitstring.h,v 1.5 2003/06/02 19:34:12 millert Exp $ */ /* $OpenBSD: bitstring.h,v 1.5 2003/06/02 19:34:12 millert Exp $ */
/* $NetBSD: bitstring.h,v 1.5 1997/05/14 15:49:55 pk Exp $ */ /* $NetBSD: bitstring.h,v 1.5 1997/05/14 15:49:55 pk Exp $ */

View File

@@ -1,3 +1,5 @@
/* $Id$ */
/* /*
* Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
* *

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