1
0
mirror of https://github.com/tmate-io/tmate-ssh-server.git synced 2020-11-18 19:53:51 -08:00

merge latest tmux

This commit is contained in:
Nicolas Viennot 2015-12-28 01:11:10 -05:00
commit 8284dd910c
214 changed files with 21960 additions and 13094 deletions

3
.gitignore vendored
View File

@ -6,6 +6,7 @@
core core
tags tags
.deps/ .deps/
compat/.dirstamp
aclocal.m4 aclocal.m4
autom4te.cache/ autom4te.cache/
config.log config.log
@ -19,3 +20,5 @@ keys/
tmate-slave tmate-slave
cscope.* cscope.*
tags tags
tmux.1.*
tmate.1.*

View File

@ -1,24 +1,36 @@
Bob Beck <beck@openbsd.org> beck <beck> Bob Beck <beck@openbsd.org> beck <beck>
Claudio Jeker <claudio@openbsd.org> claudio <claudio>
Igor Sobrado <sobrado@openbsd.org> sobrado <sobrado> Igor Sobrado <sobrado@openbsd.org> sobrado <sobrado>
Ingo Schwarze <schwarze@openbsd.org> schwarze <schwarze>
Jacek Masiulaniec <jacekm@openbsd.org> jacekm <jacekm> Jacek Masiulaniec <jacekm@openbsd.org> jacekm <jacekm>
Jason McIntyre <jmc@openbsd.org> jcm <jcm> Jason McIntyre <jmc@openbsd.org> jmc <jmc>
Joel Sing <jsing@openbsd.org> jsing <jsing> Joel Sing <jsing@openbsd.org> jsing <jsing>
Jonathan Gray <jsg@openbsd.org> jsg <jsg>
Kenneth R Westerback <krw@openbsd.org> krw <krw>
Marc Espie <espie@openbsd.org> espie <espie> Marc Espie <espie@openbsd.org> espie <espie>
Matthew Dempsky <matthew@openbsd.org> matthew <matthew> Matthew Dempsky <matthew@openbsd.org> matthew <matthew>
Matthias Kilian <kili@openbsd.org> kili <kili> Matthias Kilian <kili@openbsd.org> kili <kili>
Matthieu Herrb <matthieu@openbsd.org> matthieu <matthieu> Matthieu Herrb <matthieu@openbsd.org> matthieu <matthieu>
Michael McConville <mmcc@openbsd.org> mmcc <mmcc>
Miod Vallat <miod@openbsd.org> miod <miod> Miod Vallat <miod@openbsd.org> miod <miod>
Nicholas Marriott <nicm@openbsd.org> nicm <nicm> Nicholas Marriott <nicholas.marriott@gmail.com> Nicholas Marriott <nicm@openbsd.org>
Nicholas Marriott <nicm@openbsd.org> no_author <no_author@example.org> Nicholas Marriott <nicholas.marriott@gmail.com> nicm <nicm>
<nicm@openbsd.org> <nicholas.marriott@gmail.com> Nicholas Marriott <nicholas.marriott@gmail.com> no_author <no_author@example.org>
Okan Demirmen <okan@openbsd.org> okan <okan> Okan Demirmen <okan@openbsd.org> okan <okan>
Philip Guenther <guenther@openbsd.org> guenther <guenther> Philip Guenther <guenther@openbsd.org> guenther <guenther>
Pierre-Yves Ritschard <pyr@openbsd.org> pyr <pyr> Pierre-Yves Ritschard <pyr@openbsd.org> pyr <pyr>
Ray Lai <ray@openbsd.org> ray <ray> Ray Lai <ray@openbsd.org> ray <ray>
Ryan McBride <mcbride@openbsd.org> mcbride <mcbride> Ryan McBride <mcbride@openbsd.org> mcbride <mcbride>
Sebastian Benoit <benno@openbsd.org> benno <benno>
Stefan Sperling <stsp@openbsd.org> stsp <stsp> Stefan Sperling <stsp@openbsd.org> stsp <stsp>
Stuart Henderson <sthen@openbsd.org> sthen <sthen> Stuart Henderson <sthen@openbsd.org> sthen <sthen>
Ted Unangst <tedu@openbsd.org> tedu <tedu> Ted Unangst <tedu@openbsd.org> tedu <tedu>
Theo Deraadt <deraadt@openbsd.org> deraadt <deraadt> Theo de Raadt <deraadt@openbsd.org> Theo Deraadt <deraadt@openbsd.org>
Theo de Raadt <deraadt@openbsd.org> deraadt <deraadt>
Thomas Adam <thomas@xteddy.org> Thomas <thomas@xteddy.org> Thomas Adam <thomas@xteddy.org> Thomas <thomas@xteddy.org>
Thomas Adam <thomas@xteddy.org> Thomas Adam <thomas.adam@smoothwall.net>
Thomas Adam <thomas@xteddy.org> n6tadam <n6tadam@xteddy.org>
Tim van der Molen <tim@openbsd.org> tim <tim>
Tobias Stoeckmann <tobias@openbsd.org> tobias <tobias>
Todd C Miller <millert@openbsd.org> millert <millert>
William Yodlowsky <william@openbsd.org> william <william> William Yodlowsky <william@openbsd.org> william <william>

10
.travis.yml Normal file
View File

@ -0,0 +1,10 @@
language: c
matrix:
include:
- compiler: gcc
- compiler: clang
env: CFLAGS="-g -O2"
before_install:
- sudo apt-get update -qq
- sudo apt-get -y install debhelper autotools-dev dh-autoreconf file libncurses5-dev libevent-dev pkg-config libutempter-dev build-essential
script: (CFLAGS= ./autogen.sh) && ./configure --enable-debug && make

189
CHANGES
View File

@ -1,3 +1,179 @@
CHANGES FROM 2.0 to 2.1 18 October 2015
Incompatible Changes
====================
* Mouse-mode has been rewritten. There's now no longer options for:
- mouse-resize-pane
- mouse-select-pane
- mouse-select-window
- mode-mouse
Instead there is just one option: 'mouse' which turns on mouse support
entirely.
* 'default-terminal' is now a session option. Furthermore, if this is set
to 'screen-*' then emulate what screen does. If italics are wanted, this
can be set to 'tmux' but this is still new and not necessarily supported
on all platforms with older ncurses installs.
* The c0-* options for rate-limiting have been removed. Instead, a backoff
approach is used.
Normal Changes
==============
* New formats:
- session_activity
- window_linked
- window_activity_format
- session_alerts
- session_last_attached
- client_pid
- pid
* 'copy-selection', 'append-selection', 'start-named-buffer' now understand
an '-x' flag to prevent it exiting copying mode.
* 'select-pane' now understands '-P' to set window/pane background colours.
* 'renumber-windows' now understands windows which are unlinked.
* 'bind' now understands multiple key tables. Allows for key-chaining.
* 'select-layout' understands '-o' to undo the last layout change.
* The environment is updated when switching sessions as well as attaching.
* 'select-pane' now understands '-M' for marking a pane. This marked pane
can then be used with commands which understand src-pane specifiers
automatically.
* If a session/window target is prefixed with '=' then only an exact match
is considered.
* 'move-window' understands '-a'.
* 'update-environment' understands '-E' when attach-session is used on an
already attached client.
* 'show-environment' understands '-s' to output Bourne-compatible commands.
* New option: 'history-file' to save/restore command prompt history.
* Copy mode is exited if the history is cleared whilst in copy-mode.
* 'copy-mode' learned '-e' to exit copy-mode when scrolling to end.
CHANGES FROM 1.9a to 2.0 6 March 2015
Incompatible Changes
====================
* The choose-list command has been removed.
* 'terminal-overrides' is now a server option, not a session option.
* 'message-limit' is now a server option, not a session option.
* 'monitor-content' option has been removed.
* 'pane_start_path' option has been removed.
* The "info" mechanism which used to (for some commands) provide feedback
has been removed, and like other commands, they now produce nothing on
success.
Normal Changes
==============
* tmux can now write an entry to utmp if the library 'utempter' is present
at compile time.
* set-buffer learned append mode (-a), and a corresponding
'append-selection' command has been added to copy-mode.
* choose-mode now has the following commands which can be bound:
- start-of-list
- end-of-list
- top-line
- bottom-line
* choose-buffer now understands UTF-8.
* Pane navigation has changed:
- The old way of always using the top or left if the choice is ambiguous.
- The new way of remembering the last used pane is annoying if the
layout is balanced and the leftmost is obvious to the user (because
clearly if we go right from the top-left in a tiled set of four we want
to end up in top-right, even if we were last using the bottom-right).
So instead, use a combination of both: if there is only one possible
pane alongside the current pane, move to it, otherwise choose the most
recently used of the choice.
* 'set-buffer' can now be told to give names to buffers.
* The 'new-session', 'new-window', 'split-window', and 'respawn-pane' commands
now understand multiple arguments and handle quoting problems correctly.
* 'capture-pane' understands '-S-' to mean the start of the pane, and '-E-' to
mean the end of the pane.
* Support for function keys beyond F12 has changed. The following explains:
- F13-F24 are S-F1 to S-F12
- F25-F36 are C-F1 to C-F12
- F37-F48 are C-S-F1 to C-S-F12
- F49-F60 are M-F1 to M-F12
- F61-F63 are M-S-F1 to M-S-F3
Therefore, F13 becomes a binding of S-F1, etc.
* Support using pane id as part of session or window specifier (so % means
session-of-%1 or window-of-%1) and window id as part of session
(so @1 means session-of-@1).
* 'copy-pipe' command now understands formats via -F
* 'if-shell' command now understands formats via -F
* 'split-window' and 'join-window' understand -b to create the pane to the left
or above the target pane.
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 CHANGES FROM 1.7 to 1.8, 26 March 2013
Incompatible Changes Incompatible Changes
@ -17,7 +193,7 @@ Normal Changes
* run-shell learnt '-t' to specify the pane to use when displaying output. * run-shell learnt '-t' to specify the pane to use when displaying output.
* Support for middle-click pasting. * Support for middle-click pasting.
* choose-tree learns '-u' to start uncollapsed. * choose-tree learns '-u' to start uncollapsed.
* select-window learnt '-T; to toggle to the last window if it's already * select-window learnt '-T' to toggle to the last window if it's already
current. current.
* New session option 'assume-paste-time' for pasting text versus key-binding * New session option 'assume-paste-time' for pasting text versus key-binding
actions. actions.
@ -37,9 +213,9 @@ Normal Changes
the 'source-file' command. the 'source-file' command.
* 'copy-pipe' mode command to copy selection and pipe the selection to a * 'copy-pipe' mode command to copy selection and pipe the selection to a
command. command.
* Changes panes can now emit focus notifications for certain applications * Panes can now emit focus notifications for certain applications
which use those. which use those.
* run-shell and if-shell now accept format placeholders. * run-shell and if-shell now accept formats.
* resize-pane learnt '-Z' for zooming a pane temporarily. * resize-pane learnt '-Z' for zooming a pane temporarily.
* new-session learnt '-A' to make it behave like attach-session. * new-session learnt '-A' to make it behave like attach-session.
* set-option learnt '-o' to prevent setting an option which is already set. * set-option learnt '-o' to prevent setting an option which is already set.
@ -1799,10 +1975,3 @@ The list of older changes is below.
emacs) that don't require scrolling regions (ESC[r) mostly work fine emacs) that don't require scrolling regions (ESC[r) mostly work fine
(including mutt, emacs). No status bar yet and no key remapping or other (including mutt, emacs). No status bar yet and no key remapping or other
customisation. customisation.
$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 Normal file
View File

@ -0,0 +1,21 @@
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.

130
FAQ
View File

@ -95,9 +95,6 @@ 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
@ -107,8 +104,12 @@ 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?
Please send bug reports by email to nicm@users.sourceforge.net or Check the latest version of tmux from Git to see if the problem is still
tmux-users@lists.sourceforge.net. Please include as much of the following 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 nicholas.marriott@gmail.com or
tmux-users@googlegroups.com. Please include as much of the following
information as possible: information as possible:
- the version of tmux you are running; - the version of tmux you are running;
@ -122,7 +123,7 @@ information as possible:
* Why doesn't tmux do $x? * Why doesn't tmux do $x?
Please send feature requests by email to nicm@users.sourceforge.net. Please send feature requests by email to tmux-users@googlegroups.com.
* Why do you use the screen terminal description inside tmux? It sucks. * Why do you use the screen terminal description inside tmux? It sucks.
@ -238,6 +239,31 @@ 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
@ -326,42 +352,33 @@ 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'
* vim displays reverse video instead of italics, while less displays italics * I don't see italics! Or less and vim show italics and reverse the wrong way round!
(or just regular text) instead of reverse. What's wrong?
Screen's terminfo description lacks italics mode and has standout mode in its GNU screen does not support italics and the "screen" terminfo description uses
place, but using the same escape sequence that urxvt uses for italics. This the italics escape sequence incorrectly.
means applications (like vim) looking for italics will not find it and might
turn to reverse in its place, while applications (like less) asking for
standout will end up with italics instead of reverse. To make applications
aware that tmux supports italics and to use a proper escape sequence for
standout, you'll need to create a new terminfo file with modified sgr, smso,
rmso, sitm and ritm entries:
$ mkdir $HOME/.terminfo/ As of tmux 2.1, if default-terminal is set to "screen" or matches "screen-*",
$ screen_terminfo="screen" tmux will behave like screen and italics will be disabled.
$ infocmp "$screen_terminfo" | sed \
-e 's/^screen[^|]*|[^,]*,/screen-it|screen with italics support,/' \ To enable italics, create a new terminfo entry called "tmux" (some platforms
-e 's/%?%p1%t;3%/%?%p1%t;7%/' \ may already have this, you can check with "infocmp tmux"):
-e 's/smso=[^,]*,/smso=\\E[7m,/' \
-e 's/rmso=[^,]*,/rmso=\\E[27m,/' \ $ cat <<EOF|tic -x -
-e '$s/$/ sitm=\\E[3m, ritm=\\E[23m,/' > /tmp/screen.terminfo tmux|tmux terminal multiplexer,
$ tic /tmp/screen.terminfo ritm=\E[23m, rmso=\E[27m, sitm=\E[3m, smso=\E[7m, Ms@,
use=xterm+tmux, use=screen,
tmux-256color|tmux with 256 colors,
use=xterm+256setaf, use=tmux,
EOF
$
And tell tmux to use it in ~/.tmux.conf: And tell tmux to use it in ~/.tmux.conf:
set -g default-terminal "screen-it" set -g default-terminal "tmux"
If your terminal supports 256 colors, use: If using urxvt, make sure you have an italics capable font enabled. for
example, add to ~/.Xdefaults:
$ screen_terminfo="screen-256color"
instead of "screen". See the FAQ entry about 256 colors support for more info.
Also note that tmux will still display reverse video on terminals that do not
support italics.
If your urxvt cannot display italics at all, make sure you have an italics
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
@ -377,7 +394,7 @@ always (or ever) be added to the scrollback.
You can make tmux use the normal screen by telling it that your terminal does 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: not have an alternate screen. Put the following in ~/.tmux.conf:
set -g terminal-overrides 'xterm*:smcup@:rmcup@' set -ga terminal-overrides ',xterm*:smcup@:rmcup@'
Adjust if your $TERM does not start with xterm. Adjust if your $TERM does not start with xterm.
@ -397,4 +414,41 @@ Or the default window options:
$ tmux -Lfoo -f/dev/null start\; show -gw $ tmux -Lfoo -f/dev/null start\; show -gw
$Id$ * 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

View File

@ -1,19 +1,19 @@
# $Id$ # Makefile.am
# Obvious program stuff. # Obvious program stuff.
bin_PROGRAMS = tmate-slave bin_PROGRAMS = tmate
dist_man1_MANS = tmate.1 CLEANFILES = tmate.1.mdoc tmate.1.man
# Distribution tarball options. # Distribution tarball options.
EXTRA_DIST = \ EXTRA_DIST = \
CHANGES FAQ README TODO examples compat \ CHANGES FAQ README TODO COPYING examples compat/*.[ch] \
array.h compat.h tmux.h osdep-*.c array.h compat.h tmux.h osdep-*.c mdoc2man.awk tmate.1
dist-hook: dist-hook:
make clean
grep "^#found_debug=" configure grep "^#found_debug=" configure
find $(distdir) -name .svn -type d|xargs rm -Rf
# Preprocessor flags. # Preprocessor flags.
CPPFLAGS += @XOPEN_DEFINES@ CPPFLAGS += @XOPEN_DEFINES@ -DTMUX_CONF="\"$(sysconfdir)/tmux.conf\""
# 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.
@ -21,85 +21,83 @@ if IS_GLIBC
CFLAGS += -D_GNU_SOURCE CFLAGS += -D_GNU_SOURCE
endif endif
CFLAGS += -Wno-unused-parameter -Wno-unused-variable
if IS_LINUX
CFLAGS += -rdynamic # for stack traces
endif
if IS_DEVENV if IS_DEVENV
CFLAGS += -DDEVENV CFLAGS += -DDEVENV
endif endif
# Set flags for gcc. gcc4 whines abouts silly stuff so it needs slightly if IS_LINUX
# different flags. CFLAGS += -rdynamic # for stack traces
endif
# Set flags for gcc.
if IS_GCC if IS_GCC
CFLAGS += -std=gnu99 CFLAGS += -std=gnu99 -O2
if IS_DEBUG if IS_DEBUG
CFLAGS += -O0 -g CFLAGS += -g
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 += -Wbad-function-cast -Winline -Wcast-align CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
CPPFLAGS += -DDEBUG CPPFLAGS += -DDEBUG
else
CFLAGS += -O2
endif endif
if IS_GCC4 if IS_COVERAGE
CPPFLAGS += -iquote. -I/usr/local/include CFLAGS += -g -O0 --coverage
if IS_DEBUG LDFLAGS += --coverage
CFLAGS += -Wno-pointer-sign
endif
else
CPPFLAGS += -I. -I- -I/usr/local/include
endif endif
CPPFLAGS += -iquote.
endif 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
CFLAGS += -erroff=E_EMPTY_DECLARATION CFLAGS += -erroff=E_EMPTY_DECLARATION
endif endif
# Set _LINUX_SOURCE_COMPAT for AIX for mallocing 0 bytes
if IS_AIX
DEFS += -D_LINUX_SOURCE_COMPAT=1
endif
# List of sources. # List of sources.
dist_tmate_slave_SOURCES = \ dist_tmate_slave_SOURCES = \
alerts.c \
arguments.c \ arguments.c \
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-list.c \
cmd-choose-tree.c \ cmd-choose-tree.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 \
cmd-delete-buffer.c \
cmd-detach-client.c \ cmd-detach-client.c \
cmd-display-message.c \ cmd-display-message.c \
cmd-display-panes.c \ cmd-display-panes.c \
cmd-find.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 \
@ -126,23 +124,20 @@ dist_tmate_slave_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-server-info.c \
cmd-set-buffer.c \ cmd-set-buffer.c \
cmd-set-environment.c \ cmd-set-environment.c \
cmd-set-hook.c \
cmd-set-option.c \ cmd-set-option.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-unlink-window.c \
cmd-wait-for.c \ cmd-wait-for.c \
cmd.c \ cmd.c \
colour.c \ colour.c \
@ -150,9 +145,9 @@ dist_tmate_slave_SOURCES = \
control-notify.c \ control-notify.c \
environ.c \ environ.c \
format.c \ format.c \
grid-cell.c \
grid-view.c \ grid-view.c \
grid.c \ grid.c \
hooks.c \
input-keys.c \ input-keys.c \
input.c \ input.c \
job.c \ job.c \
@ -168,17 +163,18 @@ dist_tmate_slave_SOURCES = \
options-table.c \ options-table.c \
options.c \ options.c \
paste.c \ paste.c \
proc.c \
resize.c \ resize.c \
screen-redraw.c \ screen-redraw.c \
screen-write.c \ screen-write.c \
screen.c \ screen.c \
server-client.c \ server-client.c \
server-fn.c \ server-fn.c \
server-window.c \
server.c \ server.c \
session.c \ session.c \
signal.c \ signal.c \
status.c \ status.c \
style.c \
tmate-debug.c \ tmate-debug.c \
tmate-daemon-decoder.c \ tmate-daemon-decoder.c \
tmate-daemon-encoder.c \ tmate-daemon-encoder.c \
@ -231,6 +227,9 @@ endif
if NO_FGETLN if NO_FGETLN
nodist_tmate_slave_SOURCES += compat/fgetln.c nodist_tmate_slave_SOURCES += compat/fgetln.c
endif endif
if NO_FPARSELN
nodist_tmux_SOURCES += compat/fparseln.c
endif
if NO_GETOPT if NO_GETOPT
nodist_tmate_slave_SOURCES += compat/getopt.c nodist_tmate_slave_SOURCES += compat/getopt.c
endif endif
@ -249,3 +248,12 @@ endif
if NO_B64_NTOP if NO_B64_NTOP
nodist_tmate_slave_SOURCES += compat/b64_ntop.c nodist_tmate_slave_SOURCES += compat/b64_ntop.c
endif endif
if NO_CFMAKERAW
nodist_tmate_SOURCES += compat/cfmakeraw.c
endif
if NO_OPENAT
nodist_tmate_SOURCES += compat/openat.c
endif
if NO_REALLOCARRAY
nodist_tmate_SOURCES += compat/reallocarray.c
endif

35
README
View File

@ -4,10 +4,9 @@ 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 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. 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 This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.
run on Solaris and AIX (although they haven't been tested in a while).
Since the 1.2 release tmux depends on libevent. Download it from: tmux depends on libevent 2.x. Download it from:
http://www.monkey.org/~provos/libevent/ http://www.monkey.org/~provos/libevent/
@ -18,14 +17,13 @@ To build tmux from a release tarball, do:
To get and build the latest from version control: To get and build the latest from version control:
$ git clone git://git.code.sf.net/p/tmux/tmux-code tmux $ git clone https://github.com/tmux/tmux.git
$ cd tmux $ cd tmux
$ sh autogen.sh $ sh autogen.sh
$ ./configure && make $ ./configure && make
For more information see https://sourceforge.net/scm/?type=git&group_id=200378 For more information see http://git-scm.com. Patches should be sent by email to
and http://git-scm.com. Patches should be sent by email to the mailing list at the mailing list at tmux-users@googlegroups.com.
tmux-users@lists.sourceforge.net.
For documentation on using tmux, see the tmux.1 manpage. It can be viewed from For documentation on using tmux, see the tmux.1 manpage. It can be viewed from
the source tree with: the source tree with:
@ -41,20 +39,23 @@ directory.
For debugging, running tmux with -v or -vv will generate server and client log For debugging, running tmux with -v or -vv will generate server and client log
files in the current directory. files in the current directory.
tmux mailing lists are available. Visit: tmux mailing lists are available. For general discussion and bug reports:
https://sourceforge.net/mail/?group_id=200378 https://groups.google.com/forum/#!forum/tmux-users
And for Git commit emails:
https://groups.google.com/forum/#!forum/tmux-git
Bug reports, feature suggestions and especially code contributions are most Bug reports, feature suggestions and especially code contributions are most
welcome. Please send by email to: welcome. Please send by email to:
tmux-users@lists.sourceforge.net tmux-users@googlegroups.com
This file and the CHANGES, FAQ and TODO files are licensed under the ISC This file and the CHANGES, FAQ, SYNCING and TODO files are licensed under
license. Files under examples/ remain copyright their authors unless otherwise the ISC license. Files under examples/ remain copyright their authors unless
stated in the file but permission has been received to distribute them with otherwise stated in the file but permission has been received to distribute
tmux. All other files have a license and copyright notice at their start. them with tmux. All other files have a license and copyright notice at their
start.
-- Nicholas Marriott <nicm@users.sf.net> -- Nicholas Marriott <nicholas.marriott@gmail.com>
$Id$

82
SYNCING
View File

@ -1,10 +1,10 @@
Preamble Preamble
======== ========
Tmux on SourceForge has two git repositories [1] "tmux-code" and "tmux-openbsd". Tmux portable relies on repositories "tmux" and "tmux-openbsd".
Here's a description of them: Here's a description of them:
* "tmux-code" is the portable version, the one which contains code for other * "tmux" is the portable version, the one which contains code for other
operating systems, and autotools, etc., which isn't found or needed in the operating systems, and autotools, etc., which isn't found or needed in the
OpenBSD base system. OpenBSD base system.
@ -17,9 +17,6 @@ repository will take at least that long to appear in this git repository.
(It might take longer, depending on the CVS mirror used to import the (It might take longer, depending on the CVS mirror used to import the
OpenBSD code). 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 If you've never used git before, git tracks meta-data about the committer
and the author, as part of a commit, hence: and the author, as part of a commit, hence:
@ -37,11 +34,11 @@ this information has ever been set before.
Cloning repositories Cloning repositories
==================== ====================
This involves having both tmux-code and tmux-openbsd cloned, as in: This involves having both tmux and tmux-openbsd cloned, as in:
% cd /some/where/useful % cd /some/where/useful
% git clone ssh://${USER}@git.code.sf.net/p/tmux/tmux % git clone https://github.com/tmux/tmux.git
% git clone ssh://${USER}@git.code.sf.net/p/tmux/tmux-openbsd % git clone https://github.com/ThomasAdam/tmux-openbsd.git
Note that you do not need additional checkouts to manage the sync -- an Note that you do not need additional checkouts to manage the sync -- an
existing clone of either repositories will suffice. So if you already have existing clone of either repositories will suffice. So if you already have
@ -50,56 +47,56 @@ these checkouts existing, skip that.
Adding in git-remotes Adding in git-remotes
===================== =====================
Because the portable "tmux-code" git repository and the "tmux-openbsd" Because the portable "tmux" git repository and the "tmux-openbsd"
repository do not inherently share any history between each other, the repository do not inherently share any history between each other, the
history has been faked between them. This "faking of history" is something history has been faked between them. This "faking of history" is something
which has to be told to git for the purposes of comparing the "tmux" and which has to be told to git for the purposes of comparing the "tmux" and
"tmux-openbsd" repositories for syncing. To do this, we must reference the "tmux-openbsd" repositories for syncing. To do this, we must reference the
clone of the "tmux-openbsd" repository from the "tmux-code" repository, as clone of the "tmux-openbsd" repository from the "tmux" repository, as
shown by the following command: shown by the following command:
% cd /path/to/tmux-code % cd /path/to/tmux
% git remote add obsd-tmux file:///path/to/tmux-openbsd % git remote add obsd-tmux file:///path/to/tmux-openbsd
So that now, the remote "obsd-tmux" can be used to reference branches and So that now, the remote "obsd-tmux" can be used to reference branches and
commits from the "tmux-openbsd" repository, but from the context of the commits from the "tmux-openbsd" repository, but from the context of the
portable "tmux-code" repository, which makes sense because it's the "tmux" portable "tmux" repository, which makes sense because it's the "tmux"
repository which will have the updates applied to them. repository which will have the updates applied to them.
Fetching updates Fetching updates
================ ================
To ensure the latest commits from "tmux-openbsd" can be found from within To ensure the latest commits from "tmux-openbsd" can be found from within
"tmux-code", we have to ensure the "master" branch from "tmux-openbsd" is "tmux", 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: up-to-date first, and then reference that update in "tmux", as in:
% cd /path/to/tmux-openbsd % cd /path/to/tmux-openbsd
% git checkout master % git checkout master
% git pull % git pull
Then back in "tmux-code": Then back in "tmux":
% cd /path/to/tmux-code % cd /path/to/tmux
% git fetch obsd-tmux-code % git fetch obsd-tmux
Creating the necessary branches Creating the necessary branches
=============================== ===============================
Now that "tmux-code" can see commits and branches from "tmux-openbsd" by way Now that "tmux" can see commits and branches from "tmux-openbsd" by way
of the remote name "obsd-tmux", we can now create the master branch from of the remote name "obsd-tmux", we can now create the master branch from
"tmux-openbsd" in the "tmux-code" repository: "tmux-openbsd" in the "tmux" repository:
% git checkout -b obsd-master obsd-tmux/master % git checkout -b obsd-master obsd-tmux/master
Adding in the fake history points Adding in the fake history points
================================= =================================
To tie both the "master" branch from "tmux-code" and the "obsd-master" To tie both the "master" branch from "tmux" and the "obsd-master"
branch from "tmux-openbsd" together, the fake history points added to the branch from "tmux-openbsd" together, the fake history points added to the
"tmux-code" repository need to be added. To do this, we must add an "tmux" repository need to be added. To do this, we must add an
additional refspec line, as in: additional refspec line, as in:
% cd /path/to/tmux-code % cd /path/to/tmux
% git config --add remote.origin.fetch '+refs/replace/*:refs/replace/*' % git config --add remote.origin.fetch '+refs/replace/*:refs/replace/*'
% git fetch origin % git fetch origin
@ -110,7 +107,7 @@ Make sure the "master" branch is checked out:
% git checkout master % git checkout master
The following will show commits on OpenBSD not yet synched with "tmux-code": The following will show commits on OpenBSD not yet synched with "tmux":
% git log master..obsd-master % git log master..obsd-master
@ -131,6 +128,15 @@ And if happy:
% git push origin master % 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 Release tmux for next version
============================= =============================
@ -145,30 +151,26 @@ Release tmux for next version
3. Tag with: 3. Tag with:
% git tag -a 1.X % git tag -a 2.X
Where "1.X" is the next version. Where "2.X" is the next version.
Push the tag out with: Push the tag out with:
% git push 1.X % git push 2.X
4. Build the tarball with make dist. Now that it's using autoconf there 4. Build the tarball with 'make dist'.
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 5. Check the tarball. If it's good, go here to select the tag just pushed:
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 https://github.com/tmux/tmux/tags
download by selecting all operating systems under the file details.
7. Run make update-index.html upload-index.html to replace %%VERSION%%. Click the "Add release notes", upload the tarball and add a link in the
description field to the CHANGES file.
8. Bump version in configure.ac and uncomment "found_debug=yes" to create 7. Clone the tmux.github.io repository, and change the RELEASE version in
a debug build by default. the Makefile. Commit it, and run 'make' to replace %%VERSION%%. Push
the result out.
9. Update freshmeat. 8. Bump version in tmu/tmux.git configure.ac and uncomment "found_debug=yes" to
create a debug build by default.
[1] https://sourceforge.net/p/tmux/_list/git

274
TODO
View File

@ -1,155 +1,135 @@
NOTES - command bits and pieces:
===== * allow multiple targets: fnmatch for -t/-c, for example detach all
clients with -t*
* add -c for new-session like new-window
* ' and " should be parsed the same (eg "\e" vs '\e') in config
and command prompt
* last-pane across sessions
* list-keys should quote output so that bindings can just be used in
config file as-is
This file describes rough notes regarding ideas for potential future tmux - make command sequences more usable
development. It's not necessarily guaranteed that items in this TODO file * don't require space after ;
will ever get implemented. * options for error handling: && and ||?
It is asked therefore, that anyone thinking of undertaking a task in this - options bits and pieces:
TODO file, email tmux-users@lists.sf.net to discuss the feature. * set-remain-on-exit is a complete hack
* way to set socket path from config file
Thie file is split up between tmux user interface (UI) issues, and terminal - format improvements:
compatibility issues. * option to quote format (#{q:session_name})
* formats need conditions for >0 (for #P)
* some way to pad # stuff with spaces
* formats to show if a window is linked into multiple sessions, into
multiple attached sessions, and is the active window in multiple
attached sessions?
TMUX UI ISSUES - 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)
* choose modes should ditch the key bindings and just have fixed keys, and
be more customized to their purpose (d to delete a buffer for choose-buffer,
a preview of buffer contents, etc)
- improve monitor-*:
* straighten out rules for multiple clients
* think about what happens across sessions
* monitor changes within a region
* perhaps monitor /all/ panes in the window not just one
- improve mouse support:
* bind commands to mouse in different areas?
* commands executed when clicking on a pattern (URL)
- hooks!
- implicitly add exec to the commands for new windows (switch to disable it)?
- bring back detach-session to detach all clients on a session?
- allow fnmatch for -c, so that you can, eg, detach all clients
- garbage collect window history (100 lines at a time?) if it hasn't been used
in $x time
- flags to centre screen in window
- activity/bell should be per-window not per-link? what if it is cur win in
session not being watched?
- should be able to move to a hidden pane and it would be moved into view. pane
number in status line/top-right would be cool for this
- support other mouse modes (highlight etc) and use it in copy mode
- set-remain-on-exit is a bit of a hack, some way to do it generically?
- would be nice to be able to use "--" to mark start of command w/ neww etc
to avoid quoting
- make command sequences more usable: don't require space after ;, handle
errors better
- choice and more mode would be better per client than per window?
- hooks to which commands may be attached, for example: tmux add-hook
"new-session" if-shell "[ -e $HOME/.tmux-session.conf ]" source-file
$HOME/.tmux-session.conf
- way to set socket path from config file
- 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-*
- server-info * split-window -> split-pane?
- up-pane/down-pane/swap-pane -U/swap-pane -D vs next-*/previous-*
- split-window -> split-pane??
- some way to force a screen to use the entire terminal even if it is forced
to be smaller by other clients. pan smaller terminal? (like screen F)
-- idea of a "view" onto a window, need base x/y offsets for redraw
- commands should be able to succeed or fail and have || or && for command
lists
- some way to keep a command running continually and just use its last line of
output
- UTF-8 to a non-UTF-8 terminal should not be able to balls up
the terminal - www/ruby-addressable; make regress
- support esc-esc to quit in modes
- fix ctrl+F1-F4 output. to what?
- better utf8 support: window names, prompt input, message display
- option to move copy mode indicator into status line
- selection behaviour closer to vi in vi mode
- live update: server started with -U connects to server, requests sessions and
windows, receives fds
- sort out inheriting config from shell on new sessions/windows:
should pick up default-path/termios/etc from client if possible,
else leave empty/default
- link panes into multiple windows
- bells should be passed between sessions with visual-bell etc
sequence until its shell exits, to allow them to be used from the config file
- better session sharing: create-socket command to create socket somewhere (-r
flag for readonly)
- multiline status line (no?)
- support title stack, both internally and externally
http://docs.freebsd.org/cgi/getmsg.cgi?fetch=1149299+0+archive/2010/freebsd-questions/20100207.freebsd-questions
- some way to pad # stuff with spaces, #!2T maybe
- a binding to "scroll down and exit at bottom" copy mode
- some way to pass keystrokes in copy mode through to underlying window. why?
- last window update time and # replacement for it for display-message
- find-window across sessions - other ways to make session handling easier?
- ' and " should be parsed the same (eg "\e" vs '\e') in config and command
prompt?
- command to toggle selection not to move it in copy-mode
- audit of escape sequence support vs xterm
- support binding keys to mouse (mouse-select-pane -> mouse-keys or something,
mouse click == select-pane -t %%, mouse scroll up == copy-mode)
- 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
command that says "next key from $othertable" and so on. means -n can
go away as well
- monitor, bell etc should monitor /all/ panes in the window not just one
- a history of commands that can be reversed (reverse member of each command,
and a buffer)
- info() when changing to same window
- way to add dest for break-pane; maybe some easier way to unbreak-pane
- case insensitive searching
- incremental searching in copy mode.
- configurable borders and empty space filler for when panes < window?
- 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)
- pass shell commands as argv rather than strings, allow them to be specified
in commands without quotes
- named buffers and allow gaps in the stack
- 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
- wait-for command 20130222153957.GY6782@yelena.nicm.ath.cx
- last-pane across sessions
- panes should have names like windows
- command-prompt doesn't work if made read-only. why?
- option to quote format eg #{session_name:quoted}
- formats need conditions for >0 (for #P)
- fetch full command line on !Linux, and add option to strip prefixes
such as "sh " "/bin/sh " etc etc
- synchronize-windows option
- append to buffer in copy mode
- way to paste w/o trailing whitespace
- flag to switch-client to switch all clients
- history of layouts and undo/redo flags to selectl
- way to tag a layout as a number/name
- optimize pane redraws, 20120318184853.GK10965@yelena.nicm.ath.cx
- support multibyte key strings
- allow commands to be executed when certain patterns in a screen
are clicked on with the mouse
- flag to make next/previous commands skip a window
- way to do tmux command/run-shell from mode keys
- send command to all windows
- choose-pane command (augment choose-tree to do this?)
- choose-mode and copy-mode are very similar. Perhaps make choose-mode a subset
of copy-mode in that it inherits key-bindings and other traits but not all
- add -c for new-session like new-window
- flag to choose-* for sort order (eg sort windows/sessions/clients by last
used time) - perhaps using formats (but what about numeric sort)?
- instead of separate window and session options, just one master options list
with each option having a type (window or session), then options on window,
on session, and global. for window options we look window->session->global,
and for session we look session->global
- maybe keep last layout + size around and if size reverts just put it back
- way to set hints/limits about pane size for resizing
- revamp layouts: they are too complicated, should be more closely integrated,
should support hints, layout sets should just be a special case of custom
layouts, and we should support panes that are not attached to a cell at
all. this could be the time to introduce panelink to replace layout_cell
- run-shell/if-shell should support formats
- attach should take a pane and select it as well as attaching
- attach should have a flag to create session if it doesn't exist. or better
new a flag to attach it
TERMINAL ISSUES - better UTF-8 support:
================ * message display
* prompt input
* searching in copy mode
- use a better termcap internally instead of screen, perhaps xterm - copy/paste improvements:
- clear window title on exit (see using xterm title stack) * incremental searching
- get it passing all the vttest tests that don't require resizing the terminal * paste w/o trailing whitespace
- support for bce * command to toggle selection not to move it in copy-mode
- use screen-256color when started on 256 colour terminal? * regex searching
* We need a tmux terminfo entry to document the extensions we are using in * copy-pipe should have -x as well
upstream terminfo. Must NOT change (only add or remove) anything from
TERM=screen so we can fallback! - layout stuff
* way to tag a layout as a number/name
* maybe keep last layout + size around and if size reverts just put it
back
* revamp layouts: they are too complicated, should be more closely
integrated, should support hints, layout sets should just be a
special case of custom layouts, and we should support panes that are
not attached to a cell at all. this could be the time to introduce
panelink to replace layout_cell
* way to set hints/limits about pane size for resizing
* panning over window (window larger than visible)
* a mode where one application can cross two panes (ie x|y, width =
COLUMNS/2 but height = ROWS * 2)
* general key to space cells out evenly (horiz or vert) within their
parent cell (could replace even-vert/even-horiz layouts)
* separate active panes for different clients
- terminfo bits
* use a better termcap internally instead of screen, perhaps xterm
* use screen-256color when started on 256 colour terminal?
- code cleanup
* instead of separate window and session options, just one master
options list with each option having a type (window or session), then
options on window, on session, and global. for window options we look
window->session->global, and for session we look session->global
* the way pane, window, session destroy is handled is too complicated
and the distinction between session.c, window.c and server-fn.c
functions is not clear. could we just have kill_pane(),
kill_window(), unlink_window(), kill_session() that fix up all data
structures (flagging sessions as dead) and return a value to say
whether clients need to be checked for dead sessions? sort of like
session_detach now but more so. or some other scheme to make it
simpler and clearer? also would be nice to remove/rename server-fn.c
* more readable way to work out the various things commands need to
know about the client, notably:
- is this the config file? (cmdq->c == NULL)
- is this a command client? (cmdq->c != NULL &&
cmdq->c->session == NULL)
- is this a control client?
- can i do stdin or stdout to this client?
or even guarantee that cmdq->c != NULL and provide a better way to
tell when in the config file - then we use cmdq->c if we need a
client w/o a session else cmd_current_client
* optimize pane redraws, 20120318184853.GK10965@yelena.nicm.ath.cx
- miscellaneous
* way to keep a job running just read its last line of output for #()
* link panes into multiple windows
* live update: server started with -U connects to server, requests
sessions and windows, receives file descriptors
* there are inconsistencies in what we get from old shell and what
comes from config for new sessions and windows. likewise, panes and
jobs and run-shell and lock command all start with slightly different
environments
* multiline status line?
* customizable command aliases
* automatic pane logging
* BCE? We are halfway there (output side is done for pane backgrounds),
just need to change how screen/grid handles erase
* copy mode key bindings should just be a standard key table, using
something like "copy-mode start-selection"; it could use
command-prompt for search, goto, etc:
bind -Temacs command-prompt -p'Search Up: ' 'copy-mode search-up %%'
it'd need a separate lookup, because modes are per-pane, perhaps a
table() cb to give the table name ("vi" or "emacs"). anything in the
table fires the command, anything not in the table is injected as a
key

277
alerts.c Normal file
View File

@ -0,0 +1,277 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2015 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 <event.h>
#include "tmux.h"
int alerts_fired;
void alerts_timer(int, short, void *);
int alerts_enabled(struct window *, int);
void alerts_callback(int, short, void *);
void alerts_reset(struct window *);
int alerts_check_all(struct session *, struct winlink *);
int alerts_check_bell(struct session *, struct winlink *);
int alerts_check_activity(struct session *, struct winlink *);
int alerts_check_silence(struct session *, struct winlink *);
void alerts_ring_bell(struct session *);
void
alerts_timer(__unused int fd, __unused short events, void *arg)
{
struct window *w = arg;
log_debug("@%u alerts timer expired", w->id);
alerts_reset(w);
alerts_queue(w, WINDOW_SILENCE);
}
void
alerts_callback(__unused int fd, __unused short events, __unused void *arg)
{
struct window *w;
struct session *s;
struct winlink *wl;
int flags, alerts;
RB_FOREACH(w, windows, &windows) {
RB_FOREACH(s, sessions, &sessions) {
if (s->flags & SESSION_UNATTACHED)
continue;
RB_FOREACH(wl, winlinks, &s->windows) {
if (wl->window != w)
continue;
flags = w->flags;
alerts = alerts_check_all(s, wl);
log_debug("%s:%d @%u alerts check, alerts %#x, "
"flags %#x", s->name, wl->idx, w->id,
alerts, flags);
}
}
}
alerts_fired = 0;
}
int
alerts_check_all(struct session *s, struct winlink *wl)
{
int alerts;
alerts = alerts_check_bell(s, wl);
alerts |= alerts_check_activity(s, wl);
alerts |= alerts_check_silence(s, wl);
if (alerts != 0)
server_status_session(s);
return (alerts);
}
void
alerts_check_session(struct session *s)
{
struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows)
alerts_check_all(s, wl);
}
int
alerts_enabled(struct window *w, int flags)
{
if (flags & WINDOW_BELL)
return (1);
if (flags & WINDOW_ACTIVITY) {
if (options_get_number(w->options, "monitor-activity"))
return (1);
}
if (flags & WINDOW_SILENCE) {
if (options_get_number(w->options, "monitor-silence") != 0)
return (1);
}
return (0);
}
void
alerts_reset_all(void)
{
struct window *w;
RB_FOREACH(w, windows, &windows)
alerts_reset(w);
}
void
alerts_reset(struct window *w)
{
struct timeval tv;
w->flags &= ~WINDOW_SILENCE;
event_del(&w->alerts_timer);
timerclear(&tv);
tv.tv_sec = options_get_number(w->options, "monitor-silence");
log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec);
if (tv.tv_sec != 0)
event_add(&w->alerts_timer, &tv);
}
void
alerts_queue(struct window *w, int flags)
{
if (w->flags & WINDOW_ACTIVITY)
alerts_reset(w);
if (!event_initialized(&w->alerts_timer))
evtimer_set(&w->alerts_timer, alerts_timer, w);
if (!alerts_fired) {
w->flags |= flags;
log_debug("@%u alerts flags added %#x", w->id, flags);
if (alerts_enabled(w, flags)) {
log_debug("alerts check queued (by @%u)", w->id);
event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
alerts_fired = 1;
}
}
}
int
alerts_check_bell(struct session *s, struct winlink *wl)
{
struct client *c;
struct window *w = wl->window;
int action, visual;
if (!(w->flags & WINDOW_BELL))
return (0);
if (s->curw != wl) {
wl->flags |= WINLINK_BELL;
w->flags &= ~WINDOW_BELL;
}
if (s->curw->window == w)
w->flags &= ~WINDOW_BELL;
action = options_get_number(s->options, "bell-action");
if (action == BELL_NONE)
return (0);
visual = options_get_number(s->options, "visual-bell");
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != s || c->flags & CLIENT_CONTROL)
continue;
if (!visual) {
if ((action == BELL_CURRENT &&
c->session->curw->window == w) ||
(action == BELL_OTHER &&
c->session->curw->window != w) ||
action == BELL_ANY)
tty_putcode(&c->tty, TTYC_BEL);
continue;
}
if (action == BELL_CURRENT && c->session->curw->window == w)
status_message_set(c, "Bell in current window");
else if (action == BELL_ANY || (action == BELL_OTHER &&
c->session->curw->window != w))
status_message_set(c, "Bell in window %d", wl->idx);
}
return (WINDOW_BELL);
}
int
alerts_check_activity(struct session *s, struct winlink *wl)
{
struct client *c;
struct window *w = wl->window;
if (s->curw->window == w)
w->flags &= ~WINDOW_ACTIVITY;
if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY)
return (0);
if (s->curw == wl)
return (0);
if (!options_get_number(w->options, "monitor-activity"))
return (0);
if (options_get_number(s->options, "bell-on-alert"))
alerts_ring_bell(s);
wl->flags |= WINLINK_ACTIVITY;
if (options_get_number(s->options, "visual-activity")) {
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != s)
continue;
status_message_set(c, "Activity in window %d", wl->idx);
}
}
return (WINDOW_ACTIVITY);
}
int
alerts_check_silence(struct session *s, struct winlink *wl)
{
struct client *c;
struct window *w = wl->window;
if (s->curw->window == w)
w->flags &= ~WINDOW_SILENCE;
if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE)
return (0);
if (s->curw == wl)
return (0);
if (options_get_number(w->options, "monitor-silence") == 0)
return (0);
if (options_get_number(s->options, "bell-on-alert"))
alerts_ring_bell(s);
wl->flags |= WINLINK_SILENCE;
if (options_get_number(s->options, "visual-silence")) {
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != s)
continue;
status_message_set(c, "Silence in window %d", wl->idx);
}
}
return (WINDOW_SILENCE);
}
void
alerts_ring_bell(struct session *s)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == s && !(c->flags & CLIENT_CONTROL))
tty_putcode(&c->tty, TTYC_BEL);
}
}

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
@ -20,9 +20,31 @@
#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 {
u_char flag;
char *value;
RB_ENTRY(args_entry) entry;
};
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, ...)
@ -32,8 +54,6 @@ 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)
@ -49,35 +69,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 || opt >= SCHAR_MAX) if (opt < 0)
continue; continue;
if (opt == '?' || (ptr = strchr(template, opt)) == NULL) { if (opt == '?' || strchr(template, opt) == NULL) {
free(args->flags); args_free(args);
free(args);
return (NULL); return (NULL);
} }
args_set(args, opt, optarg);
bit_set(args->flags, opt);
if (ptr[1] == ':') {
free(args->values[opt]);
args->values[opt] = xstrdup(optarg);
}
} }
argc -= optind; argc -= optind;
argv += optind; argv += optind;
@ -92,122 +113,142 @@ args_parse(const char *template, int argc, char **argv)
void void
args_free(struct args *args) args_free(struct args *args)
{ {
u_int i; struct args_entry *entry;
struct args_entry *entry1;
cmd_free_argv(args->argc, args->argv); cmd_free_argv(args->argc, args->argv);
for (i = 0; i < SCHAR_MAX; i++) RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
free(args->values[i]); RB_REMOVE(args_tree, &args->tree, entry);
free(entry->value);
free(entry);
}
free(args->flags);
free(args); free(args);
} }
/* Print a set of arguments. */ /* Add to string. */
size_t static void printflike(3, 4)
args_print(struct args *args, char *buf, size_t len) args_print_add(char **buf, size_t *len, const char *fmt, ...)
{ {
size_t off; va_list ap;
int i; char *s;
const char *quotes; size_t slen;
/* There must be at least one byte at the start. */ va_start(ap, fmt);
if (len == 0) slen = xvasprintf(&s, fmt, ap);
return (0); va_end(ap);
off = 0;
*len += slen;
*buf = xrealloc(*buf, *len);
strlcat(*buf, s, *len);
free(s);
}
/* Print a set of arguments. */
char *
args_print(struct args *args)
{
size_t len;
char *buf;
int i;
struct args_entry *entry;
len = 1;
buf = xcalloc(1, len);
/* Process the flags first. */ /* Process the flags first. */
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 (*buf == '\0')
buf[off] = '\0'; args_print_add(&buf, &len, "-");
return (len); args_print_add(&buf, &len, "%c", entry->flag);
} }
buf[off++] = i;
buf[off] = '\0';
}
if (off == 1)
buf[--off] = '\0';
/* Then the flags with arguments. */ /* Then the flags with arguments. */
for (i = 0; i < SCHAR_MAX; i++) { RB_FOREACH(entry, args_tree, &args->tree) {
if (!bit_test(args->flags, i) || args->values[i] == NULL) if (entry->value == NULL)
continue; continue;
if (off >= len) { if (*buf != '\0')
/* snprintf will have zero terminated. */ args_print_add(&buf, &len, " -%c ", entry->flag);
return (len);
}
if (strchr(args->values[i], ' ') != NULL)
quotes = "\"";
else else
quotes = ""; args_print_add(&buf, &len, "-%c ", entry->flag);
off += xsnprintf(buf + off, len - off, "%s-%c %s%s%s", if (strchr(entry->value, ' ') != NULL)
off != 0 ? " " : "", i, quotes, args->values[i], quotes); args_print_add(&buf, &len, "\"%s\"", entry->value);
else
args_print_add(&buf, &len, "%s", entry->value);
} }
/* And finally the argument vector. */ /* And finally the argument vector. */
for (i = 0; i < args->argc; i++) { for (i = 0; i < args->argc; i++) {
if (off >= len) { if (*buf != '\0')
/* snprintf will have zero terminated. */ args_print_add(&buf, &len, " ");
return (len);
}
if (strchr(args->argv[i], ' ') != NULL) if (strchr(args->argv[i], ' ') != NULL)
quotes = "\""; args_print_add(&buf, &len, "\"%s\"", args->argv[i]);
else else
quotes = ""; args_print_add(&buf, &len, "%s", args->argv[i]);
off += xsnprintf(buf + off, len - off, "%s%s%s%s",
off != 0 ? " " : "", quotes, args->argv[i], quotes);
} }
return (off); return (buf);
} }
/* Return if an argument is present. */ /* Return if an argument is present. */
int int
args_has(struct args *args, u_char ch) args_has(struct args *args, u_char ch)
{ {
return (bit_test(args->flags, ch)); return (args_find(args, ch) == NULL ? 0 : 1);
} }
/* Set argument value. */ /* Set argument value in the arguments tree. */
void void
args_set(struct args *args, u_char ch, const char *value) args_set(struct args *args, u_char ch, const char *value)
{ {
free(args->values[ch]); struct args_entry *entry;
/* 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)
args->values[ch] = xstrdup(value); entry->value = 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)
{ {
return (args->values[ch]); struct args_entry *entry;
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, args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
u_char ch, long long minval, long long maxval, char **cause) char **cause)
{ {
const char *errstr; const char *errstr;
long long ll; long long ll;
struct args_entry *entry;
if (!args_has(args, ch)) { if ((entry = args_find(args, ch)) == NULL) {
*cause = xstrdup("missing"); *cause = xstrdup("missing");
return (0); return (0);
} }
ll = strtonum(args->values[ch], minval, maxval, &errstr); ll = strtonum(entry->value, minval, maxval, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
*cause = xstrdup(errstr); *cause = xstrdup(errstr);
return (0); return (0);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2006 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2006 Nicholas Marriott <nicm@users.sourceforge.net>
@ -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, 1, (a)->space); \ (a)->list = xrealloc((a)->list, (a)->space); \
} \ } \
while ((a)->space <= ((a)->num + (n)) * ARRAY_ITEMSIZE(a)) { \ while ((a)->space <= ((a)->num + (n)) * ARRAY_ITEMSIZE(a)) { \
(a)->list = xrealloc((a)->list, 2, (a)->space); \ (a)->list = xreallocarray((a)->list, 2, (a)->space); \
(a)->space *= 2; \ (a)->space *= 2; \
} \ } \
} while (0) } while (0)

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org> * Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org>

View File

@ -1,5 +1,4 @@
#!/bin/sh #!/bin/sh
# $Id$
if [ "x$(uname)" = "xOpenBSD" ]; then if [ "x$(uname)" = "xOpenBSD" ]; then
[ -z "$AUTOMAKE_VERSION" ] && export AUTOMAKE_VERSION=1.10 [ -z "$AUTOMAKE_VERSION" ] && export AUTOMAKE_VERSION=1.10

181
cfg.c
View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -17,28 +17,77 @@
*/ */
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
char *cfg_file;
struct cmd_q *cfg_cmd_q; struct cmd_q *cfg_cmd_q;
int cfg_finished; int cfg_finished;
int cfg_references; int cfg_references;
struct causelist cfg_causes; char **cfg_causes;
u_int cfg_ncauses;
struct client *cfg_client;
void cfg_default_done(struct cmd_q *);
void
set_cfg_file(const char *path)
{
free(cfg_file);
cfg_file = xstrdup(path);
}
void
start_cfg(void)
{
char *cause = NULL;
const char *home;
cfg_cmd_q = cmdq_new(NULL);
cfg_cmd_q->emptyfn = cfg_default_done;
cfg_finished = 0;
cfg_references = 1;
cfg_client = TAILQ_FIRST(&clients);
if (cfg_client != NULL)
cfg_client->references++;
if (access(TMUX_CONF, R_OK) == 0) {
if (load_cfg(TMUX_CONF, cfg_cmd_q, &cause) == -1)
cfg_add_cause("%s: %s", TMUX_CONF, cause);
} else if (errno != ENOENT)
cfg_add_cause("%s: %s", TMUX_CONF, strerror(errno));
if (cfg_file == NULL && (home = find_home()) != NULL) {
xasprintf(&cfg_file, "%s/.tmux.conf", home);
if (access(cfg_file, R_OK) != 0 && errno == ENOENT) {
free(cfg_file);
cfg_file = NULL;
}
}
if (cfg_file != NULL && load_cfg(cfg_file, cfg_cmd_q, &cause) == -1)
cfg_add_cause("%s: %s", cfg_file, cause);
free(cause);
cmdq_continue(cfg_cmd_q);
}
int int
load_cfg(const char *path, struct cmd_q *cmdq, char **cause) load_cfg(const char *path, struct cmd_q *cmdq, char **cause)
{ {
FILE *f; FILE *f;
u_int n, found; char delim[3] = { '\\', '\\', '\0' };
char *buf, *copy, *line, *cause1, *msg; u_int found;
size_t len, oldlen; size_t line = 0;
char *buf, *cause1, *p;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
log_debug("loading %s", path); log_debug("loading %s", path);
@ -47,76 +96,43 @@ load_cfg(const char *path, struct cmd_q *cmdq, char **cause)
return (-1); return (-1);
} }
n = found = 0; found = 0;
line = NULL; while ((buf = fparseln(f, NULL, &line, delim, 0)) != NULL) {
while ((buf = fgetln(f, &len))) { log_debug("%s: %s", path, buf);
/* Trim \n. */
if (buf[len - 1] == '\n')
len--;
log_debug("%s: %.*s", path, (int)len, buf);
/* Current line is the continuation of the previous one. */
if (line != NULL) {
oldlen = strlen(line);
line = xrealloc(line, 1, oldlen + len + 1);
} else {
oldlen = 0;
line = xmalloc(len + 1);
}
/* Append current line to the previous. */
memcpy(line + oldlen, buf, len);
line[oldlen + len] = '\0';
n++;
/* Continuation: get next line? */
len = strlen(line);
if (len > 0 && line[len - 1] == '\\') {
line[len - 1] = '\0';
/* Ignore escaped backslash at EOL. */
if (len > 1 && line[len - 2] != '\\')
continue;
}
copy = line;
line = NULL;
/* Skip empty lines. */ /* Skip empty lines. */
buf = copy; p = buf;
while (isspace((u_char)*buf)) while (isspace((u_char) *p))
buf++; p++;
if (*buf == '\0') { if (*p == '\0') {
free(copy); free(buf);
continue; continue;
} }
/* Parse and run the command. */ /* Parse and run the command. */
if (cmd_string_parse(buf, &cmdlist, path, n, &cause1) != 0) { if (cmd_string_parse(p, &cmdlist, path, line, &cause1) != 0) {
free(copy); free(buf);
if (cause1 == NULL) if (cause1 == NULL)
continue; continue;
xasprintf(&msg, "%s:%u: %s", path, n, cause1); cfg_add_cause("%s:%zu: %s", path, line, cause1);
ARRAY_ADD(&cfg_causes, msg);
free(cause1); free(cause1);
continue; continue;
} }
free(copy); free(buf);
if (cmdlist == NULL) if (cmdlist == NULL)
continue; continue;
cmdq_append(cmdq, cmdlist); cmdq_append(cmdq, cmdlist, NULL);
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
found++; found++;
} }
if (line != NULL)
free(line);
fclose(f); fclose(f);
return (found); return (found);
} }
void void
cfg_default_done(unused struct cmd_q *cmdq) cfg_default_done(__unused struct cmd_q *cmdq)
{ {
if (--cfg_references != 0) if (--cfg_references != 0)
return; return;
@ -127,25 +143,70 @@ cfg_default_done(unused struct cmd_q *cmdq)
cmdq_free(cfg_cmd_q); cmdq_free(cfg_cmd_q);
cfg_cmd_q = NULL; 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);
server_client_unref(cfg_client);
cfg_client = NULL;
}
}
void
cfg_add_cause(const char *fmt, ...)
{
va_list ap;
char *msg;
va_start(ap, fmt);
xvasprintf(&msg, fmt, ap);
va_end(ap);
cfg_ncauses++;
cfg_causes = xreallocarray(cfg_causes, cfg_ncauses, sizeof *cfg_causes);
cfg_causes[cfg_ncauses - 1] = msg;
}
void
cfg_print_causes(struct cmd_q *cmdq)
{
u_int i;
for (i = 0; i < cfg_ncauses; i++) {
cmdq_print(cmdq, "%s", cfg_causes[i]);
free(cfg_causes[i]);
}
free(cfg_causes);
cfg_causes = NULL;
cfg_ncauses = 0;
} }
void void
cfg_show_causes(struct session *s) cfg_show_causes(struct session *s)
{ {
struct window_pane *wp; struct window_pane *wp;
char *cause;
u_int i; u_int i;
if (s == NULL || ARRAY_EMPTY(&cfg_causes)) if (s == NULL || cfg_ncauses == 0)
return; return;
wp = s->curw->window->active; wp = s->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode); window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp); window_copy_init_for_output(wp);
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) { for (i = 0; i < cfg_ncauses; i++) {
cause = ARRAY_ITEM(&cfg_causes, i); window_copy_add(wp, "%s", cfg_causes[i]);
window_copy_add(wp, "%s", cause); free(cfg_causes[i]);
free(cause);
} }
ARRAY_FREE(&cfg_causes);
free(cfg_causes);
cfg_causes = NULL;
cfg_ncauses = 0;
} }

673
client.c
View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -26,7 +26,7 @@
#include <errno.h> #include <errno.h>
#include <event.h> #include <event.h>
#include <fcntl.h> #include <fcntl.h>
#include <pwd.h> #include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@ -34,8 +34,9 @@
#include "tmux.h" #include "tmux.h"
#include "tmate.h" #include "tmate.h"
struct imsgbuf client_ibuf; struct tmuxproc *client_proc;
struct event client_event; struct tmuxpeer *client_peer;
int client_flags;
struct event client_stdin; struct event client_stdin;
enum { enum {
CLIENT_EXIT_NONE, CLIENT_EXIT_NONE,
@ -49,54 +50,60 @@ enum {
} client_exitreason = CLIENT_EXIT_NONE; } 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;
__dead void client_exec(const char *,const char *);
int client_get_lock(char *); int client_get_lock(char *);
int client_connect(char *, int); int client_connect(struct event_base *, const char *, int);
void client_send_identify(int); void client_send_identify(const char *, const char *);
void client_send_environ(void);
void client_write_server(enum msgtype, void *, size_t);
void client_update_event(void);
void client_signal(int, short, void *);
void client_stdin_callback(int, short, void *); void client_stdin_callback(int, short, void *);
void client_write(int, const char *, size_t); void client_write(int, const char *, size_t);
void client_callback(int, short, void *); void client_signal(int);
int client_dispatch_attached(void); void client_dispatch(struct imsg *, void *);
int client_dispatch_wait(void *); void client_dispatch_attached(struct imsg *);
void client_dispatch_wait(struct imsg *, const char *);
const char *client_exit_message(void); const char *client_exit_message(void);
/* /*
* Get server create lock. If already held then server start is happening in * 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 * another client, so block until the lock is released and return -2 to
* retry. Ignore other errors - just continue and start the server without the * retry. Return -1 on failure to continue and start the server anyway.
* lock.
*/ */
int int
client_get_lock(char *lockfile) client_get_lock(char *lockfile)
{ {
int lockfd; int lockfd;
if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) log_debug("lock file is %s", lockfile);
fatal("open failed");
if (flock(lockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) { if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) {
log_debug("open failed: %s", strerror(errno));
return (-1);
}
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) while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
/* nothing */; /* nothing */;
close(lockfd); close(lockfd);
return (-1); return (-2);
} }
log_debug("flock succeeded");
return (lockfd); return (lockfd);
} }
/* Connect client to server. */ /* Connect client to server. */
int int
client_connect(char *path, int start_server) client_connect(struct event_base *base, const char *path, int start_server)
{ {
struct sockaddr_un sa; struct sockaddr_un sa;
size_t size; size_t size;
int fd, lockfd; int fd, lockfd = -1, locked = 0;
char *lockfile; char *lockfile = NULL;
memset(&sa, 0, sizeof sa); memset(&sa, 0, sizeof sa);
sa.sun_family = AF_UNIX; sa.sun_family = AF_UNIX;
@ -105,32 +112,64 @@ client_connect(char *path, int start_server)
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
return (-1); return (-1);
} }
log_debug("socket is %s", path);
retry: retry:
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
fatal("socket failed"); return (-1);
if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { log_debug("trying connect");
if (connect(fd, (struct sockaddr *)&sa, sizeof sa) == -1) {
log_debug("connect failed: %s", strerror(errno));
if (errno != ECONNREFUSED && errno != ENOENT) if (errno != ECONNREFUSED && errno != ENOENT)
goto failed; goto failed;
if (!start_server) if (!start_server)
goto failed; goto failed;
close(fd); close(fd);
if (!locked) {
xasprintf(&lockfile, "%s.lock", path); xasprintf(&lockfile, "%s.lock", path);
if ((lockfd = client_get_lock(lockfile)) == -1) if ((lockfd = client_get_lock(lockfile)) < 0) {
log_debug("didn't get lock (%d)", lockfd);
free(lockfile);
lockfile = NULL;
if (lockfd == -2)
goto retry; goto retry;
if (unlink(path) != 0 && errno != ENOENT) }
log_debug("got lock (%d)", lockfd);
/*
* 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 (lockfd >= 0 && unlink(path) != 0 && errno != ENOENT) {
free(lockfile);
close(lockfd);
return (-1); return (-1);
fd = server_start(lockfd, lockfile); }
fd = server_start(base, lockfd, lockfile);
}
if (locked && lockfd >= 0) {
free(lockfile); free(lockfile);
close(lockfd); close(lockfd);
} }
setblocking(fd, 0); setblocking(fd, 0);
return (fd); return (fd);
failed: failed:
if (locked) {
free(lockfile);
close(lockfd);
}
close(fd); close(fd);
return (-1); return (-1);
} }
@ -139,12 +178,24 @@ failed:
const char * const char *
client_exit_message(void) client_exit_message(void)
{ {
static char msg[256];
switch (client_exitreason) { switch (client_exitreason) {
case CLIENT_EXIT_NONE: case CLIENT_EXIT_NONE:
break; break;
case CLIENT_EXIT_DETACHED: case CLIENT_EXIT_DETACHED:
if (client_exitsession != NULL) {
xsnprintf(msg, sizeof msg, "detached "
"(from session %s)", client_exitsession);
return (msg);
}
return ("detached"); return ("detached");
case CLIENT_EXIT_DETACHED_HUP: 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"); return ("detached and SIGHUP");
case CLIENT_EXIT_LOST_TTY: case CLIENT_EXIT_LOST_TTY:
return ("lost tty"); return ("lost tty");
@ -162,25 +213,34 @@ client_exit_message(void)
/* Client main loop. */ /* Client main loop. */
int int
client_main(int argc, char **argv, int flags) client_main(struct event_base *base, int argc, char **argv, int flags,
const char *shellcmd)
{ {
struct cmd *cmd; struct cmd *cmd;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct msg_command_data cmddata; struct msg_command_data *data;
int cmdflags, fd; int cmdflags, fd, i;
const char *ttynam, *cwd;
pid_t ppid; pid_t ppid;
enum msgtype msg; enum msgtype msg;
char *cause; char *cause, path[PATH_MAX];
struct termios tio, saved_tio; struct termios tio, saved_tio;
size_t size;
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
signal(SIGCHLD, SIG_IGN);
/* Save the flags. */
client_flags = flags;
/* Set up the initial command. */ /* Set up the initial command. */
cmdflags = 0; cmdflags = 0;
if (shell_cmd != NULL) { if (shellcmd != NULL) {
msg = MSG_SHELL; msg = MSG_SHELL;
cmdflags = CMD_STARTSERVER; cmdflags = CMD_STARTSERVER;
} else if (argc == 0) { } else if (argc == 0) {
msg = MSG_COMMAND; msg = MSG_COMMAND;
cmdflags = CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST; cmdflags = CMD_STARTSERVER;
} else { } else {
msg = MSG_COMMAND; msg = MSG_COMMAND;
@ -198,10 +258,6 @@ client_main(int argc, char **argv, int flags)
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)
cmdflags |= CMD_CANTNEST;
} }
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
} }
@ -209,46 +265,60 @@ client_main(int argc, char **argv, int flags)
#ifdef TMATE_SLAVE #ifdef TMATE_SLAVE
fd = tmate_session->tmux_socket_fd; fd = tmate_session->tmux_socket_fd;
#else #else
/* Create client process structure (starts logging). */
client_proc = proc_start("client", base, 0, client_signal);
/* /* Initialize the client socket and start the server. */
* Check if this could be a nested session, if the command can't nest: fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
* if the socket path matches $TMUX, this is probably the same server.
*/
if (shell_cmd == NULL && environ_path != NULL &&
(cmdflags & CMD_CANTNEST) &&
strcmp(socket_path, environ_path) == 0) {
fprintf(stderr, "sessions should be nested with care, "
"unset $TMUX to force\n");
return (1);
}
/* Initialise the client socket and start the server. */
fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER);
if (fd == -1) { if (fd == -1) {
fprintf(stderr, "failed to connect to server\n"); if (errno == ECONNREFUSED) {
fprintf(stderr, "no server running on %s\n",
socket_path);
} else {
fprintf(stderr, "error connecting to %s (%s)\n",
socket_path, strerror(errno));
}
return (1); return (1);
} }
#endif #endif
client_peer = proc_add_peer(client_proc, fd, client_dispatch,
(void *)shellcmd);
/* Set process title, log and signals now this is the client. */ /* Save these before pledge(). */
#ifdef HAVE_SETPROCTITLE if ((cwd = getcwd(path, sizeof path)) == NULL) {
setproctitle("client (%s)", socket_path); if ((cwd = find_home()) == NULL)
cwd = "/";
}
if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
ttynam = "";
#ifdef __OpenBSD__
/*
* Drop privileges for client. "proc exec" is needed for -c and for
* locking (which uses system(3)).
*
* "tty" is needed to restore termios(4) and also for some reason -CC
* does not work properly without it (input is not recognised).
*
* "sendfd" is dropped later in client_dispatch_wait().
*/
if (pledge("stdio unix sendfd proc exec tty", NULL) != 0)
fatal("pledge failed");
#endif #endif
/* Create imsg. */ /* Free stuff that is not used in the client. */
imsg_init(&client_ibuf, fd); options_free(global_options);
event_set(&client_event, fd, EV_READ, client_callback, shell_cmd); options_free(global_s_options);
options_free(global_w_options);
environ_free(global_environ);
/* Create stdin handler. */ /* Create stdin handler. */
setblocking(STDIN_FILENO, 0); setblocking(STDIN_FILENO, 0);
event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST, event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
client_stdin_callback, NULL); client_stdin_callback, NULL);
if (flags & IDENTIFY_TERMIOS) { if (client_flags & CLIENT_CONTROLCONTROL) {
if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) { if (tcgetattr(STDIN_FILENO, &saved_tio) != 0)
fprintf(stderr, "tcgetattr failed: %s\n", fatal("tcgetattr failed");
strerror(errno));
return (1);
}
cfmakeraw(&tio); cfmakeraw(&tio);
tio.c_iflag = ICRNL|IXANY; tio.c_iflag = ICRNL|IXANY;
tio.c_oflag = OPOST|ONLCR; tio.c_oflag = OPOST|ONLCR;
@ -263,214 +333,114 @@ client_main(int argc, char **argv, int flags)
tcsetattr(STDIN_FILENO, TCSANOW, &tio); tcsetattr(STDIN_FILENO, TCSANOW, &tio);
} }
/* Establish signal handlers. */ /* Send identify messages. */
set_signals(client_signal); client_send_identify(ttynam, cwd);
/* Send initial environment. */
if (cmdflags & CMD_SENDENVIRON)
client_send_environ();
client_send_identify(flags);
/* Send first command. */ /* Send first command. */
if (msg == MSG_COMMAND) { if (msg == MSG_COMMAND) {
/* Fill in command line arguments. */ /* How big is the command? */
cmddata.pid = environ_pid; size = 0;
cmddata.session_id = environ_session_id; for (i = 0; i < argc; i++)
size += strlen(argv[i]) + 1;
data = xmalloc((sizeof *data) + size);
/* Prepare command for server. */ /* Prepare command for server. */
cmddata.argc = argc; data->argc = argc;
if (cmd_pack_argv( if (cmd_pack_argv(argc, argv, (char *)(data + 1), size) != 0) {
argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) {
fprintf(stderr, "command too long\n"); fprintf(stderr, "command too long\n");
free(data);
return (1); return (1);
} }
size += sizeof *data;
client_write_server(msg, &cmddata, sizeof cmddata); /* Send the command. */
if (proc_send(client_peer, msg, -1, 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); proc_send(client_peer, msg, -1, NULL, 0);
/* Set the event and dispatch. */ /* Start main loop. */
client_update_event(); proc_loop(client_proc, NULL);
event_dispatch();
/* 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_exitreason != CLIENT_EXIT_NONE)
printf("[%s]\r\n", client_exit_message()); printf("[%s]\r\n", client_exit_message());
}
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 & IDENTIFY_TERMIOS) { } else if (client_flags & CLIENT_CONTROLCONTROL) {
if (flags & IDENTIFY_CONTROL) {
if (client_exitreason != CLIENT_EXIT_NONE) if (client_exitreason != CLIENT_EXIT_NONE)
printf("%%exit %s\n", client_exit_message()); printf("%%exit %s\n", client_exit_message());
else else
printf("%%exit\n"); printf("%%exit\n");
printf("\033\\"); printf("\033\\");
}
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio); tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
} } else if (client_exitreason != CLIENT_EXIT_NONE)
fprintf(stderr, "%s\n", client_exit_message());
setblocking(STDIN_FILENO, 1); setblocking(STDIN_FILENO, 1);
return (client_exitval); return (client_exitval);
} }
/* Send identify message to server with the file descriptors. */ /* Send identify messages to server. */
void void
client_send_identify(int flags) client_send_identify(const char *ttynam, const char *cwd)
{ {
struct msg_identify_data data; const char *s;
char *term; char **ss;
int fd; size_t sslen;
int fd, flags = client_flags;
pid_t pid;
proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
#ifdef TMATE_SLAVE #ifdef TMATE_SLAVE
strncpy(data.ip_address, tmate_session->ssh_client.ip_address, proc_send(client_peer, MSG_IDENTIFY_TMATE_IP_ADDRESS, -1,
sizeof(data.ip_address)); tmate_session->ssh_client.ip_address,
strncpy(data.pubkey, tmate_session->ssh_client.pubkey, strlen(tmate_session->ssh_client.ip_address) + 1);
sizeof(data.pubkey));
data.readonly = tmate_session->readonly; proc_send(client_peer, MSG_IDENTIFY_TMATE_PUBKEY, -1,
tmate_session->ssh_client.pubkey,
strlen(tmate_session->ssh_client.pubkey) + 1);
proc_send(client_peer, MSG_IDENTIFY_TMATE_READONLY,
-1, &tmate_session->readonly, 1);
#endif #endif
data.flags = flags; if ((s = getenv("TERM")) == NULL)
s = "";
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
if (getcwd(data.cwd, sizeof data.cwd) == NULL) proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
*data.cwd = '\0'; strlen(ttynam) + 1);
proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
term = getenv("TERM");
if (term == NULL ||
strlcpy(data.term, term, sizeof data.term) >= sizeof data.term)
*data.term = '\0';
if ((fd = dup(STDIN_FILENO)) == -1) if ((fd = dup(STDIN_FILENO)) == -1)
fatal("dup failed"); fatal("dup failed");
imsg_compose(&client_ibuf, proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
client_update_event();
}
/* Forward entire environment to server. */ pid = getpid();
void proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
client_send_environ(void)
{
struct msg_environ_data data;
char **var;
for (var = environ; *var != NULL; var++) { for (ss = environ; *ss != NULL; ss++) {
if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var) sslen = strlen(*ss) + 1;
if (sslen > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
continue; continue;
client_write_server(MSG_ENVIRON, &data, sizeof data); proc_send(client_peer, MSG_IDENTIFY_ENVIRON, -1, *ss, sslen);
}
} }
/* Write a message to the server without a file descriptor. */ proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0);
void
client_write_server(enum msgtype type, void *buf, size_t len)
{
imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
client_update_event();
}
/* Update client event based on whether it needs to read or read and write. */
void
client_update_event(void)
{
short events;
event_del(&client_event);
events = EV_READ;
if (client_ibuf.w.queued > 0)
events |= EV_WRITE;
event_set(
&client_event, client_ibuf.fd, events, client_callback, shell_cmd);
event_add(&client_event, NULL);
}
/* Callback to handle signals in the client. */
void
client_signal(int sig, unused short events, unused void *data)
{
struct sigaction sigact;
int status;
if (!client_attached) {
switch (sig) {
case SIGCHLD:
waitpid(WAIT_ANY, &status, WNOHANG);
break;
case SIGTERM:
event_loopexit(NULL);
break;
}
} else {
switch (sig) {
case SIGHUP:
client_exitreason = CLIENT_EXIT_LOST_TTY;
client_exitval = 1;
client_write_server(MSG_EXITING, NULL, 0);
break;
case SIGTERM:
client_exitreason = CLIENT_EXIT_TERMINATED;
client_exitval = 1;
client_write_server(MSG_EXITING, NULL, 0);
break;
#ifndef TMATE_SLAVE
case SIGWINCH:
client_write_server(MSG_RESIZE, NULL, 0);
break;
#endif
case SIGCONT:
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
client_write_server(MSG_WAKEUP, NULL, 0);
break;
}
}
client_update_event();
}
/* Callback for client imsg read events. */
void
client_callback(unused int fd, short events, void *data)
{
ssize_t n;
int retval;
if (events & EV_READ) {
if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
goto lost_server;
if (client_attached)
retval = client_dispatch_attached();
else
retval = client_dispatch_wait(data);
if (retval != 0) {
event_loopexit(NULL);
return;
}
}
if (events & EV_WRITE) {
if (msgbuf_write(&client_ibuf.w) < 0)
goto lost_server;
}
client_update_event();
return;
lost_server:
client_exitreason = CLIENT_EXIT_LOST_SERVER;
client_exitval = 1;
event_loopexit(NULL);
} }
/* Callback for client stdin read events. */ /* Callback for client stdin read events. */
void void
client_stdin_callback(unused int fd, unused short events, unused void *data1) client_stdin_callback(__unused int fd, __unused short events,
__unused void *arg)
{ {
struct msg_stdin_data data; struct msg_stdin_data data;
@ -478,10 +448,9 @@ client_stdin_callback(unused int fd, unused short events, unused void *data1)
if (data.size < 0 && (errno == EINTR || errno == EAGAIN)) if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
return; return;
client_write_server(MSG_STDIN, &data, sizeof data); proc_send(client_peer, MSG_STDIN, -1, &data, sizeof data);
if (data.size <= 0) if (data.size <= 0)
event_del(&client_stdin); event_del(&client_stdin);
client_update_event();
} }
/* Force write to file descriptor. */ /* Force write to file descriptor. */
@ -502,45 +471,140 @@ client_write(int fd, const char *data, size_t size)
} }
} }
/* Dispatch imsgs when in wait state (before MSG_READY). */ /* Run command in shell; used for -c. */
int __dead void
client_dispatch_wait(void *data) client_exec(const char *shell, const char *shellcmd)
{ {
struct imsg imsg; const char *name, *ptr;
ssize_t n, datalen; char *argv0;
struct msg_shell_data shelldata;
struct msg_exit_data exitdata; log_debug("shell %s, command %s", shell, shellcmd);
ptr = strrchr(shell, '/');
if (ptr != NULL && *(ptr + 1) != '\0')
name = ptr + 1;
else
name = shell;
if (client_flags & CLIENT_LOGIN)
xasprintf(&argv0, "-%s", name);
else
xasprintf(&argv0, "%s", name);
setenv("SHELL", shell, 1);
setblocking(STDIN_FILENO, 1);
setblocking(STDOUT_FILENO, 1);
setblocking(STDERR_FILENO, 1);
closefrom(STDERR_FILENO + 1);
execl(shell, argv0, "-c", shellcmd, (char *) NULL);
fatal("execl failed");
}
/* Callback to handle signals in the client. */
void
client_signal(int sig)
{
struct sigaction sigact;
int status;
if (sig == SIGCHLD)
waitpid(WAIT_ANY, &status, WNOHANG);
else if (!client_attached) {
if (sig == SIGTERM)
proc_exit(client_proc);
} else {
switch (sig) {
case SIGHUP:
client_exitreason = CLIENT_EXIT_LOST_TTY;
client_exitval = 1;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
case SIGTERM:
client_exitreason = CLIENT_EXIT_TERMINATED;
client_exitval = 1;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
#ifndef TMATE_SLAVE
case SIGWINCH:
proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
break;
#endif
case SIGCONT:
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0);
break;
}
}
}
/* Callback for client read events. */
void
client_dispatch(struct imsg *imsg, void *arg)
{
if (imsg == NULL) {
client_exitreason = CLIENT_EXIT_LOST_SERVER;
client_exitval = 1;
proc_exit(client_proc);
return;
}
if (client_attached)
client_dispatch_attached(imsg);
else
client_dispatch_wait(imsg, arg);
}
/* Dispatch imsgs when in wait state (before MSG_READY). */
void
client_dispatch_wait(struct imsg *imsg, const char *shellcmd)
{
char *data;
ssize_t datalen;
struct msg_stdout_data stdoutdata; struct msg_stdout_data stdoutdata;
struct msg_stderr_data stderrdata; struct msg_stderr_data stderrdata;
const char *shellcmd = data; int retval;
#ifdef __OpenBSD__
static int pledge_applied;
for (;;) { /*
if ((n = imsg_get(&client_ibuf, &imsg)) == -1) * "sendfd" is no longer required once all of the identify messages
fatalx("imsg_get failed"); * have been sent. We know the server won't send us anything until that
if (n == 0) * point (because we don't ask it to), so we can drop "sendfd" once we
return (0); * get the first message from the server.
datalen = imsg.hdr.len - IMSG_HEADER_SIZE; */
if (!pledge_applied) {
if (pledge("stdio unix proc exec tty", NULL) != 0)
fatal("pledge failed");
pledge_applied = 1;
};
#endif
log_debug2("got %d from server", imsg.hdr.type); data = imsg->data;
switch (imsg.hdr.type) { datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
switch (imsg->hdr.type) {
case MSG_EXIT: case MSG_EXIT:
case MSG_SHUTDOWN: case MSG_SHUTDOWN:
if (datalen != sizeof exitdata) { if (datalen != sizeof retval && datalen != 0)
if (datalen != 0)
fatalx("bad MSG_EXIT size"); fatalx("bad MSG_EXIT size");
} else { if (datalen == sizeof retval) {
memcpy(&exitdata, imsg.data, sizeof exitdata); memcpy(&retval, data, sizeof retval);
client_exitval = exitdata.retcode; client_exitval = retval;
} }
imsg_free(&imsg); proc_exit(client_proc);
return (-1); break;
case MSG_READY: case MSG_READY:
if (datalen != 0) if (datalen != 0)
fatalx("bad MSG_READY size"); fatalx("bad MSG_READY size");
event_del(&client_stdin); event_del(&client_stdin);
client_attached = 1; client_attached = 1;
client_write_server(MSG_RESIZE, NULL, 0); proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
break; break;
case MSG_STDIN: case MSG_STDIN:
if (datalen != 0) if (datalen != 0)
@ -550,102 +614,94 @@ client_dispatch_wait(void *data)
break; break;
case MSG_STDOUT: case MSG_STDOUT:
if (datalen != sizeof stdoutdata) if (datalen != sizeof stdoutdata)
fatalx("bad MSG_STDOUT"); fatalx("bad MSG_STDOUT size");
memcpy(&stdoutdata, imsg.data, sizeof stdoutdata); memcpy(&stdoutdata, data, sizeof stdoutdata);
client_write(STDOUT_FILENO, stdoutdata.data, stdoutdata.size); client_write(STDOUT_FILENO, stdoutdata.data,
stdoutdata.size);
break; break;
case MSG_STDERR: case MSG_STDERR:
if (datalen != sizeof stderrdata) if (datalen != sizeof stderrdata)
fatalx("bad MSG_STDERR"); fatalx("bad MSG_STDERR size");
memcpy(&stderrdata, imsg.data, sizeof stderrdata); memcpy(&stderrdata, data, sizeof stderrdata);
client_write(fileno(stderr), stderrdata.data, stderrdata.size); client_write(fileno(stderr), 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 " fprintf(stderr, "protocol version mismatch "
"(client %u, server %u)\n", PROTOCOL_VERSION, "(client %d, server %u)\n", PROTOCOL_VERSION,
imsg.hdr.peerid); imsg->hdr.peerid & 0xff);
client_exitval = 1; client_exitval = 1;
proc_exit(client_proc);
imsg_free(&imsg); break;
return (-1);
case MSG_SHELL: case MSG_SHELL:
if (datalen != sizeof shelldata) if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_SHELL size"); fatalx("bad MSG_SHELL string");
memcpy(&shelldata, imsg.data, sizeof shelldata);
shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
clear_signals(0); clear_signals(0);
#ifdef TMATE_SLAVE
exit(1); exit(1);
#else
client_exec(data, shellcmd);
#endif
/* NOTREACHED */ /* NOTREACHED */
case MSG_DETACH: case MSG_DETACH:
client_write_server(MSG_EXITING, NULL, 0); case MSG_DETACHKILL:
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break; break;
case MSG_EXITED: case MSG_EXITED:
imsg_free(&imsg); proc_exit(client_proc);
return (-1); break;
default:
fatalx("unexpected message");
}
imsg_free(&imsg);
} }
} }
/* Dispatch imsgs in attached state (after MSG_READY). */ /* Dispatch imsgs in attached state (after MSG_READY). */
int void
client_dispatch_attached(void) client_dispatch_attached(struct imsg *imsg)
{ {
struct imsg imsg;
struct msg_lock_data lockdata;
struct sigaction sigact; struct sigaction sigact;
ssize_t n, datalen; char *data;
ssize_t datalen;
for (;;) { data = imsg->data;
if ((n = imsg_get(&client_ibuf, &imsg)) == -1) datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
fatalx("imsg_get failed");
if (n == 0)
return (0);
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
log_debug2("got %d from server", imsg.hdr.type); switch (imsg->hdr.type) {
switch (imsg.hdr.type) {
case MSG_DETACHKILL:
case MSG_DETACH: case MSG_DETACH:
if (datalen != 0) case MSG_DETACHKILL:
fatalx("bad MSG_DETACH size"); if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_DETACH string");
client_exittype = imsg.hdr.type; client_exitsession = xstrdup(data);
if (imsg.hdr.type == MSG_DETACHKILL) client_exittype = imsg->hdr.type;
if (imsg->hdr.type == MSG_DETACHKILL)
client_exitreason = CLIENT_EXIT_DETACHED_HUP; client_exitreason = CLIENT_EXIT_DETACHED_HUP;
else else
client_exitreason = CLIENT_EXIT_DETACHED; client_exitreason = CLIENT_EXIT_DETACHED;
client_write_server(MSG_EXITING, NULL, 0); proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break; break;
case MSG_EXIT: case MSG_EXIT:
if (datalen != 0 && if (datalen != 0 && datalen != sizeof (int))
datalen != sizeof (struct msg_exit_data))
fatalx("bad MSG_EXIT size"); fatalx("bad MSG_EXIT size");
client_write_server(MSG_EXITING, NULL, 0); proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
client_exitreason = CLIENT_EXIT_EXITED; client_exitreason = CLIENT_EXIT_EXITED;
break; break;
case MSG_EXITED: case MSG_EXITED:
if (datalen != 0) if (datalen != 0)
fatalx("bad MSG_EXITED size"); fatalx("bad MSG_EXITED size");
imsg_free(&imsg); proc_exit(client_proc);
return (-1); break;
case MSG_SHUTDOWN: case MSG_SHUTDOWN:
if (datalen != 0) if (datalen != 0)
fatalx("bad MSG_SHUTDOWN size"); fatalx("bad MSG_SHUTDOWN size");
client_write_server(MSG_EXITING, NULL, 0); proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
client_exitreason = CLIENT_EXIT_SERVER_EXITED; client_exitreason = CLIENT_EXIT_SERVER_EXITED;
client_exitval = 1; client_exitval = 1;
break; break;
@ -662,18 +718,11 @@ client_dispatch_attached(void)
kill(getpid(), SIGTSTP); kill(getpid(), SIGTSTP);
break; break;
case MSG_LOCK: case MSG_LOCK:
if (datalen != sizeof lockdata) if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_LOCK size"); fatalx("bad MSG_LOCK string");
memcpy(&lockdata, imsg.data, sizeof lockdata);
lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0'; system(data);
system(lockdata.cmd); proc_send(client_peer, MSG_UNLOCK, -1, NULL, 0);
client_write_server(MSG_UNLOCK, NULL, 0);
break; break;
default:
fatalx("unexpected message");
}
imsg_free(&imsg);
} }
} }

159
clock.c
View File

@ -1,159 +0,0 @@
/* $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 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -18,7 +18,11 @@
#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"
#include "tmate.h" #include "tmate.h"
@ -30,82 +34,122 @@
enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_attach_session_entry = { const struct cmd_entry cmd_attach_session_entry = {
"attach-session", "attach", .name = "attach-session",
"drt:", 0, 0, .alias = "attach",
"[-dr] " CMD_TARGET_SESSION_USAGE,
CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, .args = { "c:dErt:", 0, 0 },
NULL, .usage = "[-dEr] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
NULL,
cmd_attach_session_exec .tflag = CMD_SESSION_WITHPANE,
.flags = CMD_STARTSERVER,
.exec = cmd_attach_session_exec
}; };
enum cmd_retval enum cmd_retval
cmd_attach_session(struct cmd_q *cmdq, const char* tflag, int dflag, int rflag) cmd_attach_session(struct cmd_q *cmdq, int dflag, int rflag, const char *cflag,
int Eflag)
{ {
struct session *s; struct session *s = cmdq->state.tflag.s;
struct client *c; struct client *c = cmdq->client, *c_loop;
struct winlink *wl = cmdq->state.tflag.wl;
struct window_pane *wp = cmdq->state.tflag.wp;
const char *update; const char *update;
char *cause; char *cause, *cwd;
u_int i; struct format_tree *ft;
if (RB_EMPTY(&sessions)) { if (RB_EMPTY(&sessions)) {
cmdq_error(cmdq, "no sessions"); cmdq_error(cmdq, "no sessions");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) if (c == NULL)
return (CMD_RETURN_ERROR);
if (cmdq->client == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (server_client_check_nested(c)) {
cmdq_error(cmdq, "sessions should be nested with care, "
"unset $TMUX to force");
return (CMD_RETURN_ERROR);
}
if (cmdq->client->session != NULL) { if (wl != NULL) {
if (wp != NULL)
window_set_active_pane(wp->window, wp);
session_set_current(s, wl);
}
if (cflag != NULL) {
ft = format_create(cmdq, 0);
format_defaults(ft, c, s, wl, wp);
cwd = format_expand(ft, cflag);
format_free(ft);
free((void *)s->cwd);
s->cwd = cwd;
}
if (c->session != NULL) {
if (dflag) { if (dflag) {
/* TAILQ_FOREACH(c_loop, &clients, entry) {
* Can't use server_write_session in case attaching to if (c_loop->session != s || c == c_loop)
* the same session as currently attached to.
*/
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != s)
continue; continue;
if (c == cmdq->client) server_client_detach(c_loop, MSG_DETACH);
continue;
server_write_client(c, MSG_DETACH, NULL, 0);
} }
} }
cmdq->client->session = s; if (!Eflag) {
notify_attached_session_changed(cmdq->client); update = options_get_string(s->options,
session_update_activity(s); "update-environment");
server_redraw_client(cmdq->client); environ_update(update, c->environ, s->environ);
}
c->session = s;
server_client_set_key_table(c, NULL);
status_timer_start(c);
notify_attached_session_changed(c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS; s->curw->flags &= ~WINLINK_ALERTFLAGS;
} else { } else {
if (server_client_open(cmdq->client, s, &cause) != 0) { if (server_client_open(c, &cause) != 0) {
cmdq_error(cmdq, "open terminal failed: %s", cause); cmdq_error(cmdq, "open terminal failed: %s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (rflag) if (rflag)
cmdq->client->flags |= CLIENT_READONLY; c->flags |= CLIENT_READONLY;
if (dflag) if (dflag) {
server_write_session(s, MSG_DETACH, NULL, 0); TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session != s || c == c_loop)
continue;
server_client_detach(c_loop, MSG_DETACH);
}
}
update = options_get_string(&s->options, "update-environment"); if (!Eflag) {
environ_update(update, &cmdq->client->environ, &s->environ); update = options_get_string(s->options,
"update-environment");
environ_update(update, c->environ, s->environ);
}
cmdq->client->session = s; c->session = s;
notify_attached_session_changed(cmdq->client); server_client_set_key_table(c, NULL);
session_update_activity(s); status_timer_start(c);
server_redraw_client(cmdq->client); notify_attached_session_changed(c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS; s->curw->flags &= ~WINLINK_ALERTFLAGS;
server_write_ready(cmdq->client); if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0);
hooks_run(c->session->hooks, c, NULL, "client-attached");
cmdq->client_exit = 0; cmdq->client_exit = 0;
} }
recalculate_sizes(); recalculate_sizes();
alerts_check_session(s);
server_update_socket(); server_update_socket();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@ -116,6 +160,6 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
return (cmd_attach_session(cmdq, args_get(args, 't'), return (cmd_attach_session(cmdq, args_has(args, 'd'),
args_has(args, 'd'), args_has(args, 'r'))); args_has(args, 'r'), args_get(args, 'c'), args_has(args, 'E')));
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -27,33 +27,22 @@
* 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_check(struct args *);
enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmd_q *);
enum cmd_retval cmd_bind_key_table(struct cmd *, struct cmd_q *, int); enum cmd_retval cmd_bind_key_mode_table(struct cmd *, struct cmd_q *,
key_code);
const struct cmd_entry cmd_bind_key_entry = { const struct cmd_entry cmd_bind_key_entry = {
"bind-key", "bind", .name = "bind-key",
"cnrt:", 1, -1, .alias = "bind",
"[-cnr] [-t key-table] key command [arguments]",
0,
NULL,
cmd_bind_key_check,
cmd_bind_key_exec
};
enum cmd_retval .args = { "cnrt:T:", 1, -1 },
cmd_bind_key_check(struct args *args) .usage = "[-cnr] [-t mode-table] [-T key-table] key command "
{ "[arguments]",
if (args_has(args, 't')) {
if (args->argc != 2 && args->argc != 3) .flags = 0,
return (CMD_RETURN_ERROR); .exec = cmd_bind_key_exec
} else { };
if (args->argc < 2)
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
enum cmd_retval enum cmd_retval
cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq) cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
@ -61,16 +50,36 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
struct args *args = self->args; struct args *args = self->args;
char *cause; char *cause;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
int key; key_code key;
const char *tablename;
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 || key == KEYC_UNKNOWN) {
cmdq_error(cmdq, "unknown key: %s", args->argv[0]); cmdq_error(cmdq, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(args, 't')) if (args_has(args, 't'))
return (cmd_bind_key_table(self, cmdq, key)); return (cmd_bind_key_mode_table(self, cmdq, key));
if (args_has(args, 'T'))
tablename = args_get(args, 'T');
else if (args_has(args, 'n'))
tablename = "root";
else
tablename = "prefix";
cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0, cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0,
&cause); &cause);
@ -80,14 +89,12 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (!args_has(args, 'n')) key_bindings_add(tablename, key, args_has(args, 'r'), cmdlist);
key |= KEYC_PREFIX;
key_bindings_add(key, args_has(args, 'r'), cmdlist);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
enum cmd_retval enum cmd_retval
cmd_bind_key_table(struct cmd *self, struct cmd_q *cmdq, int key) cmd_bind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, key_code key)
{ {
struct args *args = self->args; struct args *args = self->args;
const char *tablename; const char *tablename;
@ -108,18 +115,34 @@ cmd_bind_key_table(struct cmd *self, struct cmd_q *cmdq, int key)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (cmd != MODEKEYCOPY_COPYPIPE) { switch (cmd) {
if (args->argc != 2) { case MODEKEYCOPY_APPENDSELECTION:
cmdq_error(cmdq, "no argument allowed"); case MODEKEYCOPY_COPYSELECTION:
case MODEKEYCOPY_STARTNAMEDBUFFER:
if (args->argc == 2)
arg = NULL;
else {
arg = args->argv[2];
if (strcmp(arg, "-x") != 0) {
cmdq_error(cmdq, "unknown argument");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
arg = NULL; }
} else { break;
case MODEKEYCOPY_COPYPIPE:
if (args->argc != 3) { if (args->argc != 3) {
cmdq_error(cmdq, "no argument given"); cmdq_error(cmdq, "no argument given");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
arg = args->argv[2]; arg = args->argv[2];
break;
default:
if (args->argc != 2) {
cmdq_error(cmdq, "no argument allowed");
return (CMD_RETURN_ERROR);
}
arg = NULL;
break;
} }
mtmp.key = key; mtmp.key = key;

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -26,16 +26,22 @@
* Break pane off into a window. * Break pane off into a window.
*/ */
#define BREAK_PANE_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
enum cmd_retval cmd_break_pane_exec(struct cmd *, struct cmd_q *); 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", .name = "break-pane",
"dPF:t:", 0, 0, .alias = "breakp",
"[-dP] [-F format] " CMD_TARGET_PANE_USAGE,
0, .args = { "dPF:s:t:", 0, 0 },
NULL, .usage = "[-dP] [-F format] " CMD_SRCDST_PANE_USAGE,
NULL,
cmd_break_pane_exec .sflag = CMD_PANE,
.tflag = CMD_WINDOW_INDEX,
.flags = 0,
.exec = cmd_break_pane_exec
}; };
enum cmd_retval enum cmd_retval
@ -45,68 +51,61 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
#else #else
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl = cmdq->state.sflag.wl;
struct session *s; struct session *src_s = cmdq->state.sflag.s;
struct window_pane *wp; struct session *dst_s = cmdq->state.tflag.s;
struct window *w; struct window_pane *wp = cmdq->state.sflag.wp;
struct window *w = wl->window;
char *name; char *name;
char *cause; char *cause;
int base_idx; int idx = cmdq->state.tflag.idx;
struct client *c;
struct format_tree *ft; struct format_tree *ft;
const char *template; const char *template;
char *cp; char *cp;
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL) if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) {
cmdq_error(cmdq, "index %d already in use", idx);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
}
if (window_count_panes(wl->window) == 1) { if (window_count_panes(w) == 1) {
cmdq_error(cmdq, "can't break with only one pane"); cmdq_error(cmdq, "can't break with only one pane");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
w = wl->window;
server_unzoom_window(w); server_unzoom_window(w);
TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_REMOVE(&w->panes, wp, entry);
if (wp == w->active) { window_lost_pane(w, wp);
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(dst_s->sx, dst_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); name = default_window_name(w);
window_set_name(w, name); window_set_name(w, name);
free(name); free(name);
layout_init(w, wp); layout_init(w, wp);
wp->flags |= PANE_CHANGED;
base_idx = options_get_number(&s->options, "base-index"); if (idx == -1)
wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */ idx = -1 - options_get_number(dst_s->options, "base-index");
wl = session_attach(dst_s, w, idx, &cause); /* can't fail */
if (!args_has(self->args, 'd')) if (!args_has(self->args, 'd'))
session_select(s, wl->idx); session_select(dst_s, wl->idx);
server_redraw_session(s); server_redraw_session(src_s);
server_status_session_group(s); if (src_s != dst_s)
server_redraw_session(dst_s);
server_status_session_group(src_s);
if (src_s != dst_s)
server_status_session_group(dst_s);
if (args_has(args, 'P')) { if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = BREAK_PANE_TEMPLATE; template = BREAK_PANE_TEMPLATE;
ft = format_create(); ft = format_create(cmdq, 0);
if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) format_defaults(ft, cmdq->state.c, dst_s, wl, wp);
format_client(ft, c);
format_session(ft, s);
format_winlink(ft, s, wl);
format_window_pane(ft, wp);
cp = format_expand(ft, template); cp = format_expand(ft, template);
cmdq_print(cmdq, "%s", cp); cmdq_print(cmdq, "%s", cp);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Jonathan Alvarado <radobobo@users.sourceforge.net> * Copyright (c) 2009 Jonathan Alvarado <radobobo@users.sourceforge.net>
@ -36,20 +36,23 @@ char *cmd_capture_pane_history(struct args *, struct cmd_q *,
struct window_pane *, size_t *); struct window_pane *, size_t *);
const struct cmd_entry cmd_capture_pane_entry = { const struct cmd_entry cmd_capture_pane_entry = {
"capture-pane", "capturep", .name = "capture-pane",
"ab:CeE:JpPqS:t:", 0, 0, .alias = "capturep",
"[-aCeJpPq] [-b buffer-index] [-E end-line] [-S start-line]"
CMD_TARGET_PANE_USAGE, .args = { "ab:CeE:JpPqS:t:", 0, 0 },
0, .usage = "[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] "
NULL, "[-S start-line]" CMD_TARGET_PANE_USAGE,
NULL,
cmd_capture_pane_exec .tflag = CMD_PANE,
.flags = 0,
.exec = cmd_capture_pane_exec
}; };
char * char *
cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen) cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen)
{ {
buf = xrealloc(buf, 1, *len + linelen + 1); buf = xrealloc(buf, *len + linelen + 1);
memcpy(buf + *len, line, linelen); memcpy(buf + *len, line, linelen);
*len += linelen; *len += linelen;
return (buf); return (buf);
@ -59,15 +62,17 @@ char *
cmd_capture_pane_pending(struct args *args, struct window_pane *wp, cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
size_t *len) size_t *len)
{ {
struct evbuffer *pending;
char *buf, *line, tmp[5]; char *buf, *line, tmp[5];
size_t linelen; size_t linelen;
u_int i; u_int i;
if (wp->ictx.since_ground == NULL) pending = input_pending(wp);
if (pending == NULL)
return (xstrdup("")); return (xstrdup(""));
line = EVBUFFER_DATA(wp->ictx.since_ground); line = EVBUFFER_DATA(pending);
linelen = EVBUFFER_LENGTH(wp->ictx.since_ground); linelen = EVBUFFER_LENGTH(pending);
buf = xstrdup(""); buf = xstrdup("");
if (args_has(args, 'C')) { if (args_has(args, 'C')) {
@ -76,7 +81,7 @@ cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
tmp[0] = line[i]; tmp[0] = line[i];
tmp[1] = '\0'; tmp[1] = '\0';
} else } else
xsnprintf(tmp, sizeof tmp, "\\%03o", line[i]); xsnprintf(tmp, sizeof tmp, "\\%03hho", line[i]);
buf = cmd_capture_pane_append(buf, len, tmp, buf = cmd_capture_pane_append(buf, len, tmp,
strlen(tmp)); strlen(tmp));
} }
@ -95,6 +100,7 @@ cmd_capture_pane_history(struct args *args, struct cmd_q *cmdq,
int n, with_codes, escape_c0, join_lines; int n, with_codes, escape_c0, join_lines;
u_int i, sx, top, bottom, tmp; u_int i, sx, top, bottom, tmp;
char *cause, *buf, *line; char *cause, *buf, *line;
const char *Sflag, *Eflag;
size_t linelen; size_t linelen;
sx = screen_size_x(&wp->base); sx = screen_size_x(&wp->base);
@ -110,6 +116,10 @@ cmd_capture_pane_history(struct args *args, struct cmd_q *cmdq,
} else } else
gd = wp->base.grid; gd = wp->base.grid;
Sflag = args_get(args, 'S');
if (Sflag != NULL && strcmp(Sflag, "-") == 0)
top = 0;
else {
n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause); n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause);
if (cause != NULL) { if (cause != NULL) {
top = gd->hsize; top = gd->hsize;
@ -120,7 +130,12 @@ cmd_capture_pane_history(struct args *args, struct cmd_q *cmdq,
top = gd->hsize + n; top = gd->hsize + n;
if (top > gd->hsize + gd->sy - 1) if (top > gd->hsize + gd->sy - 1)
top = gd->hsize + gd->sy - 1; top = gd->hsize + gd->sy - 1;
}
Eflag = args_get(args, 'E');
if (Eflag != NULL && strcmp(Eflag, "-") == 0)
bottom = gd->hsize + gd->sy - 1;
else {
n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause); n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause);
if (cause != NULL) { if (cause != NULL) {
bottom = gd->hsize + gd->sy - 1; bottom = gd->hsize + gd->sy - 1;
@ -131,6 +146,7 @@ cmd_capture_pane_history(struct args *args, struct cmd_q *cmdq,
bottom = gd->hsize + n; bottom = gd->hsize + n;
if (bottom > gd->hsize + gd->sy - 1) if (bottom > gd->hsize + gd->sy - 1)
bottom = gd->hsize + gd->sy - 1; bottom = gd->hsize + gd->sy - 1;
}
if (bottom < top) { if (bottom < top) {
tmp = bottom; tmp = bottom;
@ -164,15 +180,11 @@ cmd_capture_pane_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 window_pane *wp; struct window_pane *wp = cmdq->state.tflag.wp;
char *buf, *cause; char *buf, *cause;
int buffer; const char *bufname;
u_int limit;
size_t len; size_t len;
if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
return (CMD_RETURN_ERROR);
len = 0; len = 0;
if (args_has(args, 'P')) if (args_has(args, 'P'))
buf = cmd_capture_pane_pending(args, wp, &len); buf = cmd_capture_pane_pending(args, wp, &len);
@ -186,29 +198,22 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq)
if (c == NULL || if (c == NULL ||
(c->session != NULL && !(c->flags & CLIENT_CONTROL))) { (c->session != NULL && !(c->flags & CLIENT_CONTROL))) {
cmdq_error(cmdq, "can't write to stdout"); cmdq_error(cmdq, "can't write to stdout");
free(buf);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
evbuffer_add(c->stdout_data, buf, len); evbuffer_add(c->stdout_data, buf, len);
free(buf);
if (args_has(args, 'P') && len > 0) if (args_has(args, 'P') && len > 0)
evbuffer_add(c->stdout_data, "\n", 1); evbuffer_add(c->stdout_data, "\n", 1);
server_push_stdout(c); server_client_push_stdout(c);
} else { } else {
limit = options_get_number(&global_options, "buffer-limit"); bufname = NULL;
if (!args_has(args, 'b')) { if (args_has(args, 'b'))
paste_add(&global_buffers, buf, len, limit); bufname = args_get(args, 'b');
return (CMD_RETURN_NORMAL);
}
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (paste_set(buf, len, bufname, &cause) != 0) {
if (cause != NULL) { cmdq_error(cmdq, "%s", cause);
cmdq_error(cmdq, "buffer %s", cause);
free(buf);
free(cause); free(cause);
return (CMD_RETURN_ERROR);
}
if (paste_replace(&global_buffers, buffer, buf, len) != 0) {
cmdq_error(cmdq, "no buffer %d", buffer);
free(buf); free(buf);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
@ -27,31 +27,37 @@
* Enter choice mode to choose a buffer. * Enter choice mode to choose a buffer.
*/ */
#define CHOOSE_BUFFER_TEMPLATE \
"#{buffer_name}: #{buffer_size} bytes: #{buffer_sample}"
enum cmd_retval cmd_choose_buffer_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_choose_buffer_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_choose_buffer_entry = { const struct cmd_entry cmd_choose_buffer_entry = {
"choose-buffer", NULL, .name = "choose-buffer",
"F:t:", 0, 1, .alias = NULL,
CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
0, .args = { "F:t:", 0, 1 },
NULL, .usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
NULL,
cmd_choose_buffer_exec .tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_choose_buffer_exec
}; };
enum cmd_retval enum cmd_retval
cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq) cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c = cmdq->state.c;
struct winlink *wl = cmdq->state.tflag.wl;
struct window_choose_data *cdata; struct window_choose_data *cdata;
struct winlink *wl;
struct paste_buffer *pb; struct paste_buffer *pb;
char *action, *action_data; char *action, *action_data;
const char *template; const char *template;
u_int idx; u_int idx;
if ((c = cmd_current_client(cmdq)) == NULL) { if (c == NULL) {
cmdq_error(cmdq, "no client available"); cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@ -59,10 +65,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = CHOOSE_BUFFER_TEMPLATE; template = CHOOSE_BUFFER_TEMPLATE;
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) if (paste_get_top(NULL) == NULL)
return (CMD_RETURN_ERROR);
if (paste_get_top(&global_buffers) == NULL)
return (CMD_RETURN_NORMAL); 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)
@ -74,19 +77,20 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
action = xstrdup("paste-buffer -b '%%'"); action = xstrdup("paste-buffer -b '%%'");
idx = 0; idx = 0;
while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) { pb = NULL;
while ((pb = paste_walk(pb)) != NULL) {
cdata = window_choose_data_create(TREE_OTHER, c, c->session); cdata = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = idx - 1; cdata->idx = idx;
cdata->ft_template = xstrdup(template); cdata->ft_template = xstrdup(template);
format_add(cdata->ft, "line", "%u", idx - 1); format_defaults_paste_buffer(cdata->ft, pb);
format_paste_buffer(cdata->ft, pb);
xasprintf(&action_data, "%u", idx - 1); xasprintf(&action_data, "%s", paste_buffer_name(pb));
cdata->command = cmd_template_replace(action, action_data, 1); cdata->command = cmd_template_replace(action, action_data, 1);
free(action_data); free(action_data);
window_choose_add(wl->window->active, cdata); window_choose_add(wl->window->active, cdata);
idx++;
} }
free(action); free(action);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -27,18 +27,27 @@
* Enter choice mode to choose a client. * Enter choice mode to choose a client.
*/ */
#define CHOOSE_CLIENT_TEMPLATE \
"#{client_tty}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}]" \
"#{?client_utf8, (utf8),}#{?client_readonly, (ro),} " \
"(last used #{t:client_activity})"
enum cmd_retval cmd_choose_client_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_choose_client_exec(struct cmd *, struct cmd_q *);
void cmd_choose_client_callback(struct window_choose_data *); 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, .name = "choose-client",
"F:t:", 0, 1, .alias = NULL,
CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
0, .args = { "F:t:", 0, 1 },
NULL, .usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
NULL,
cmd_choose_client_exec .tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_choose_client_exec
}; };
struct cmd_choose_client_data { struct cmd_choose_client_data {
@ -49,22 +58,19 @@ enum cmd_retval
cmd_choose_client_exec(struct cmd *self, struct cmd_q *cmdq) cmd_choose_client_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c = cmdq->state.c;
struct client *c1; struct client *c1;
struct window_choose_data *cdata; struct window_choose_data *cdata;
struct winlink *wl; struct winlink *wl = cmdq->state.tflag.wl;
const char *template; const char *template;
char *action; char *action;
u_int i, idx, cur; u_int idx, cur;
if ((c = cmd_current_client(cmdq)) == NULL) { if (c == NULL) {
cmdq_error(cmdq, "no client available"); cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR);
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 (CMD_RETURN_NORMAL);
@ -77,25 +83,24 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_q *cmdq)
action = xstrdup("detach-client -t '%%'"); action = xstrdup("detach-client -t '%%'");
cur = idx = 0; cur = idx = 0;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { TAILQ_FOREACH(c1, &clients, entry) {
c1 = ARRAY_ITEM(&clients, i); if (c1->session == NULL || c1->tty.path == NULL)
if (c1 == NULL || c1->session == NULL || c1->tty.path == NULL)
continue; continue;
if (c1 == cmdq->client) if (c1 == cmdq->client)
cur = idx; cur = idx;
idx++;
cdata = window_choose_data_create(TREE_OTHER, c, c->session); cdata = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = i; cdata->idx = idx;
cdata->ft_template = xstrdup(template); cdata->ft_template = xstrdup(template);
format_add(cdata->ft, "line", "%u", i); format_add(cdata->ft, "line", "%u", idx);
format_session(cdata->ft, c1->session); format_defaults(cdata->ft, c1, NULL, NULL, NULL);
format_client(cdata->ft, c1);
cdata->command = cmd_template_replace(action, c1->tty.path, 1); cdata->command = cmd_template_replace(action, c1->tty.path, 1);
window_choose_add(wl->window->active, cdata); window_choose_add(wl->window->active, cdata);
idx++;
} }
free(action); free(action);
@ -109,15 +114,19 @@ void
cmd_choose_client_callback(struct window_choose_data *cdata) cmd_choose_client_callback(struct window_choose_data *cdata)
{ {
struct client *c; struct client *c;
u_int idx;
if (cdata == NULL) if (cdata == NULL)
return; return;
if (cdata->start_client->flags & CLIENT_DEAD) if (cdata->start_client->flags & CLIENT_DEAD)
return; return;
if (cdata->idx > ARRAY_LENGTH(&clients) - 1) idx = 0;
return; TAILQ_FOREACH(c, &clients, entry) {
c = ARRAY_ITEM(&clients, cdata->idx); if (idx == cdata->idx)
break;
idx++;
}
if (c == NULL || c->session == NULL) if (c == NULL || c->session == NULL)
return; return;

View File

@ -1,98 +0,0 @@
/* $Id$ */
/*
* 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_LIST_DEFAULT_TEMPLATE "run-shell '%%'"
/*
* Enter choose mode to choose a custom list.
*/
enum cmd_retval cmd_choose_list_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_choose_list_entry = {
"choose-list", NULL,
"l:t:", 0, 1,
"[-l items] " CMD_TARGET_WINDOW_USAGE "[template]",
0,
NULL,
NULL,
cmd_choose_list_exec
};
enum cmd_retval
cmd_choose_list_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c;
struct winlink *wl;
const char *list1;
char *template, *item, *copy, *list;
u_int idx;
if ((c = cmd_current_client(cmdq)) == NULL) {
cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}
if ((list1 = args_get(args, 'l')) == NULL)
return (CMD_RETURN_ERROR);
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (CMD_RETURN_NORMAL);
if (args->argc != 0)
template = xstrdup(args->argv[0]);
else
template = xstrdup(CMD_CHOOSE_LIST_DEFAULT_TEMPLATE);
copy = list = xstrdup(list1);
idx = 0;
while ((item = strsep(&list, ",")) != NULL)
{
if (*item == '\0') /* no empty entries */
continue;
window_choose_add_item(wl->window->active, c, wl, item,
template, idx);
idx++;
}
free(copy);
if (idx == 0) {
free(template);
window_pane_reset_mode(wl->window->active);
return (CMD_RETURN_ERROR);
}
window_choose_ready(wl->window->active, 0, NULL);
free(template);
return (CMD_RETURN_NORMAL);
}

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2012 Thomas Adam <thomas@xteddy.org> * Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
@ -32,46 +32,64 @@
* Enter choice mode to choose a session and/or window. * 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 *); enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_choose_tree_entry = { const struct cmd_entry cmd_choose_tree_entry = {
"choose-tree", NULL, .name = "choose-tree",
"S:W:swub:c:t:", 0, 1, .alias = NULL,
"[-suw] [-b session-template] [-c window template] [-S format] " \
"[-W format] " CMD_TARGET_WINDOW_USAGE, .args = { "S:W:swub:c:t:", 0, 1 },
0, .usage = "[-suw] [-b session-template] [-c window template] "
NULL, "[-S format] [-W format] " CMD_TARGET_WINDOW_USAGE,
NULL,
cmd_choose_tree_exec .tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_choose_tree_exec
}; };
const struct cmd_entry cmd_choose_session_entry = { const struct cmd_entry cmd_choose_session_entry = {
"choose-session", NULL, .name = "choose-session",
"F:t:", 0, 1, .alias = NULL,
CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
0, .args = { "F:t:", 0, 1 },
NULL, .usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
NULL,
cmd_choose_tree_exec .tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_choose_tree_exec
}; };
const struct cmd_entry cmd_choose_window_entry = { const struct cmd_entry cmd_choose_window_entry = {
"choose-window", NULL, .name = "choose-window",
"F:t:", 0, 1, .alias = NULL,
CMD_TARGET_WINDOW_USAGE "[-F format] [template]",
0, .args = { "F:t:", 0, 1 },
NULL, .usage = CMD_TARGET_WINDOW_USAGE "[-F format] [template]",
NULL,
cmd_choose_tree_exec .tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_choose_tree_exec
}; };
enum cmd_retval enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmd_q *cmdq) cmd_choose_tree_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl, *wm; struct client *c = cmdq->state.c;
struct session *s, *s2; struct winlink *wl = cmdq->state.tflag.wl, *wm;
struct client *c; struct session *s = cmdq->state.tflag.s, *s2;
struct window_choose_data *wcd = NULL; struct window_choose_data *wcd = NULL;
const char *ses_template, *win_template; const char *ses_template, *win_template;
char *final_win_action, *cur_win_template; char *final_win_action, *cur_win_template;
@ -84,17 +102,11 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_q *cmdq)
ses_template = win_template = NULL; ses_template = win_template = NULL;
ses_action = win_action = NULL; ses_action = win_action = NULL;
if ((c = cmd_current_client(cmdq)) == NULL) { if (c == NULL) {
cmdq_error(cmdq, "no client available"); cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if ((s = c->session) == NULL)
return (CMD_RETURN_ERROR);
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR);
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 (CMD_RETURN_NORMAL);
@ -232,8 +244,10 @@ windows_only:
window_choose_ready(wl->window->active, cur_win, NULL); window_choose_ready(wl->window->active, cur_win, NULL);
if (args_has(args, 'u')) if (args_has(args, 'u')) {
window_choose_expand_all(wl->window->active); window_choose_expand_all(wl->window->active);
window_choose_set_current(wl->window->active, cur_win);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -27,28 +27,29 @@
enum cmd_retval cmd_clear_history_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_clear_history_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_clear_history_entry = { const struct cmd_entry cmd_clear_history_entry = {
"clear-history", "clearhist", .name = "clear-history",
"t:", 0, 0, .alias = "clearhist",
CMD_TARGET_PANE_USAGE,
0, .args = { "t:", 0, 0 },
NULL, .usage = CMD_TARGET_PANE_USAGE,
NULL,
cmd_clear_history_exec .tflag = CMD_PANE,
.flags = 0,
.exec = cmd_clear_history_exec
}; };
enum cmd_retval enum cmd_retval
cmd_clear_history_exec(struct cmd *self, struct cmd_q *cmdq) cmd_clear_history_exec(__unused struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct window_pane *wp = cmdq->state.tflag.wp;
struct window_pane *wp;
struct grid *gd; struct grid *gd;
if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL) gd = cmdq->state.tflag.wp->base.grid;
return (CMD_RETURN_ERROR);
gd = wp->base.grid;
grid_move_lines(gd, 0, gd->hsize, gd->sy); if (wp->mode == &window_copy_mode)
gd->hsize = 0; window_pane_reset_mode(wp);
grid_clear_history(gd);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -1,51 +0,0 @@
/* $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 "tmux.h"
/*
* Enter clock mode.
*/
enum cmd_retval cmd_clock_mode_exec(struct cmd *, struct cmd_q *);
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
};
enum cmd_retval
cmd_clock_mode_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct window_pane *wp;
if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
return (CMD_RETURN_ERROR);
window_pane_set_mode(wp, &window_clock_mode);
return (CMD_RETURN_NORMAL);
}

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -29,21 +29,23 @@
* Prompt for command in client. * Prompt for command in client.
*/ */
void cmd_command_prompt_key_binding(struct cmd *, int);
int cmd_command_prompt_check(struct args *);
enum cmd_retval cmd_command_prompt_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_command_prompt_exec(struct cmd *, struct cmd_q *);
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 *);
const struct cmd_entry cmd_command_prompt_entry = { const struct cmd_entry cmd_command_prompt_entry = {
"command-prompt", NULL, .name = "command-prompt",
"I:p:t:", 0, 1, .alias = NULL,
"[-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " [template]",
0, .args = { "I:p:t:", 0, 1 },
cmd_command_prompt_key_binding, .usage = "[-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
NULL, "[template]",
cmd_command_prompt_exec
.tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_command_prompt_exec
}; };
struct cmd_command_prompt_cdata { struct cmd_command_prompt_cdata {
@ -56,47 +58,16 @@ struct cmd_command_prompt_cdata {
int idx; int idx;
}; };
void
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;
}
}
enum cmd_retval enum cmd_retval
cmd_command_prompt_exec(struct cmd *self, struct cmd_q *cmdq) cmd_command_prompt_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
const char *inputs, *prompts; const char *inputs, *prompts;
struct cmd_command_prompt_cdata *cdata; struct cmd_command_prompt_cdata *cdata;
struct client *c; struct client *c = cmdq->state.c;
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)
return (CMD_RETURN_ERROR);
if (c->prompt_string != NULL) if (c->prompt_string != NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@ -183,7 +154,7 @@ cmd_command_prompt_callback(void *data, const char *s)
return (0); return (0);
} }
cmdq_run(c->cmdq, cmdlist); cmdq_run(c->cmdq, cmdlist, NULL);
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)

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@ -16,6 +16,8 @@
* 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 <stdlib.h>
#include <string.h> #include <string.h>
@ -26,20 +28,22 @@
* Asks for confirmation before executing a command. * Asks for confirmation before executing a command.
*/ */
void cmd_confirm_before_key_binding(struct cmd *, int);
enum cmd_retval cmd_confirm_before_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_confirm_before_exec(struct cmd *, struct cmd_q *);
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", .name = "confirm-before",
"p:t:", 1, 1, .alias = "confirm",
"[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
0, .args = { "p:t:", 1, 1 },
cmd_confirm_before_key_binding, .usage = "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
NULL,
cmd_confirm_before_exec .tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_confirm_before_exec
}; };
struct cmd_confirm_before_data { struct cmd_confirm_before_data {
@ -47,36 +51,15 @@ struct cmd_confirm_before_data {
struct client *client; struct client *client;
}; };
void
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;
}
}
enum cmd_retval enum cmd_retval
cmd_confirm_before_exec(struct cmd *self, struct cmd_q *cmdq) cmd_confirm_before_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_confirm_before_data *cdata; struct cmd_confirm_before_data *cdata;
struct client *c; struct client *c = cmdq->state.c;
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)
return (CMD_RETURN_ERROR);
if ((prompt = args_get(args, 'p')) != NULL) if ((prompt = args_get(args, 'p')) != NULL)
xasprintf(&new_prompt, "%s ", prompt); xasprintf(&new_prompt, "%s ", prompt);
else { else {
@ -124,7 +107,7 @@ cmd_confirm_before_callback(void *data, const char *s)
return (0); return (0);
} }
cmdq_run(c->cmdq, cmdlist); cmdq_run(c->cmdq, cmdlist, NULL);
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
return (0); return (0);
@ -136,7 +119,7 @@ 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; struct client *c = cdata->client;
c->references--; server_client_unref(c);
free(cdata->cmd); free(cdata->cmd);
free(cdata); free(cdata);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -21,42 +21,65 @@
#include "tmux.h" #include "tmux.h"
/* /*
* Enter copy mode. * Enter copy or clock mode.
*/ */
void cmd_copy_mode_key_binding(struct cmd *, int);
enum cmd_retval cmd_copy_mode_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_copy_mode_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_copy_mode_entry = { const struct cmd_entry cmd_copy_mode_entry = {
"copy-mode", NULL, .name = "copy-mode",
"t:u", 0, 0, .alias = NULL,
"[-u] " CMD_TARGET_PANE_USAGE,
0, .args = { "Met:u", 0, 0 },
cmd_copy_mode_key_binding, .usage = "[-Mu] " CMD_TARGET_PANE_USAGE,
NULL,
cmd_copy_mode_exec .tflag = CMD_PANE,
.flags = 0,
.exec = cmd_copy_mode_exec
}; };
void const struct cmd_entry cmd_clock_mode_entry = {
cmd_copy_mode_key_binding(struct cmd *self, int key) .name = "clock-mode",
{ .alias = NULL,
self->args = args_create(0);
if (key == KEYC_PPAGE) .args = { "t:", 0, 0 },
args_set(self->args, 'u', NULL); .usage = CMD_TARGET_PANE_USAGE,
}
.flags = 0,
.exec = cmd_copy_mode_exec
};
enum cmd_retval enum cmd_retval
cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq) cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp; struct client *c = cmdq->client;
struct session *s;
struct window_pane *wp = cmdq->state.tflag.wp;
if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL) if (args_has(args, 'M')) {
return (CMD_RETURN_ERROR); if ((wp = cmd_mouse_pane(&cmdq->item->mouse, &s, NULL)) == NULL)
return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
}
if (self->entry == &cmd_clock_mode_entry) {
window_pane_set_mode(wp, &window_clock_mode);
return (CMD_RETURN_NORMAL);
}
if (wp->mode != &window_copy_mode) {
if (window_pane_set_mode(wp, &window_copy_mode) != 0) if (window_pane_set_mode(wp, &window_copy_mode) != 0)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
window_copy_init_from_pane(wp); window_copy_init_from_pane(wp, args_has(self->args, 'e'));
}
if (args_has(args, 'M')) {
if (wp->mode != NULL && wp->mode != &window_copy_mode)
return (CMD_RETURN_NORMAL);
window_copy_start_drag(c, &cmdq->item->mouse);
}
if (wp->mode == &window_copy_mode && args_has(self->args, 'u')) if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
window_copy_pageup(wp); window_copy_pageup(wp);

View File

@ -1,66 +0,0 @@
/* $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"
/*
* Delete a paste buffer.
*/
enum cmd_retval cmd_delete_buffer_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_delete_buffer_entry = {
"delete-buffer", "deleteb",
"b:", 0, 0,
CMD_BUFFER_USAGE,
0,
NULL,
NULL,
cmd_delete_buffer_exec
};
enum cmd_retval
cmd_delete_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
char *cause;
int buffer;
if (!args_has(args, 'b')) {
paste_free_top(&global_buffers);
return (CMD_RETURN_NORMAL);
}
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(cmdq, "buffer %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (paste_free_index(&global_buffers, buffer) != 0) {
cmdq_error(cmdq, "no buffer %d", buffer);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -18,6 +18,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <string.h>
#include "tmux.h" #include "tmux.h"
/* /*
@ -27,23 +29,46 @@
enum cmd_retval cmd_detach_client_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_detach_client_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_detach_client_entry = { const struct cmd_entry cmd_detach_client_entry = {
"detach-client", "detach", .name = "detach-client",
"as:t:P", 0, 0, .alias = "detach",
"[-P] [-a] [-s target-session] " CMD_TARGET_CLIENT_USAGE,
CMD_READONLY, .args = { "as:t:P", 0, 0 },
NULL, .usage = "[-P] [-a] [-s target-session] " CMD_TARGET_CLIENT_USAGE,
NULL,
cmd_detach_client_exec .sflag = CMD_SESSION,
.tflag = CMD_CLIENT,
.flags = CMD_READONLY,
.exec = cmd_detach_client_exec
};
const struct cmd_entry cmd_suspend_client_entry = {
.name = "suspend-client",
.alias = "suspendc",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_detach_client_exec
}; };
enum cmd_retval enum cmd_retval
cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq) cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c, *c2; struct client *c = cmdq->state.c, *cloop;
struct session *s; struct session *s;
enum msgtype msgtype; enum msgtype msgtype;
u_int i;
if (self->entry == &cmd_suspend_client_entry) {
tty_stop_tty(&c->tty);
c->flags |= CLIENT_SUSPENDED;
proc_send(c->peer, MSG_SUSPEND, -1, NULL, 0);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'P')) if (args_has(args, 'P'))
msgtype = MSG_DETACHKILL; msgtype = MSG_DETACHKILL;
@ -51,30 +76,22 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq)
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 = cmdq->state.sflag.s;
if (s == NULL) TAILQ_FOREACH(cloop, &clients, entry) {
return (CMD_RETURN_ERROR); if (cloop->session == s)
server_client_detach(cloop, msgtype);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c != NULL && c->session == s)
server_write_client(c, msgtype, NULL, 0);
} }
} else { return (CMD_RETURN_STOP);
c = cmd_find_client(cmdq, args_get(args, 't'), 0); }
if (c == NULL)
return (CMD_RETURN_ERROR); if (args_has(args, 'a')) {
TAILQ_FOREACH(cloop, &clients, entry) {
if (args_has(args, 'a')) { if (cloop->session != NULL && cloop != c)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { server_client_detach(cloop, msgtype);
c2 = ARRAY_ITEM(&clients, i); }
if (c2 == NULL || c == c2) return (CMD_RETURN_NORMAL);
continue; }
server_write_client(c2, msgtype, NULL, 0);
} server_client_detach(c, msgtype);
} else
server_write_client(c, msgtype, NULL, 0);
}
return (CMD_RETURN_STOP); return (CMD_RETURN_STOP);
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@ -27,79 +27,55 @@
* Displays a message in the status line. * Displays a message in the status line.
*/ */
#define DISPLAY_MESSAGE_TEMPLATE \
"[#{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 *); 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", .name = "display-message",
"c:pt:F:", 0, 1, .alias = "display",
"[-p] [-c target-client] [-F format] " CMD_TARGET_PANE_USAGE
" [message]", .args = { "c:pt:F:", 0, 1 },
0, .usage = "[-p] [-c target-client] [-F format] "
NULL, CMD_TARGET_PANE_USAGE " [message]",
NULL,
cmd_display_message_exec .cflag = CMD_CLIENT_CANFAIL,
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_display_message_exec
}; };
enum cmd_retval enum cmd_retval
cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq) cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c = cmdq->state.c;
struct session *s; struct session *s = cmdq->state.tflag.s;
struct winlink *wl; struct winlink *wl = cmdq->state.tflag.wl;
struct window_pane *wp; struct window_pane *wp = cmdq->state.tflag.wp;
const char *template; const char *template;
char *msg; char *msg;
struct format_tree *ft; struct format_tree *ft;
char out[BUFSIZ];
time_t t;
size_t len;
if (args_has(args, 't')) {
wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
if (wl == NULL)
return (CMD_RETURN_ERROR);
} else {
wl = cmd_find_pane(cmdq, NULL, &s, &wp);
if (wl == NULL)
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'F') && args->argc != 0) { if (args_has(args, 'F') && args->argc != 0) {
cmdq_error(cmdq, "only one of -F or argument must be given"); cmdq_error(cmdq, "only one of -F or argument must be given");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
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'); template = args_get(args, 'F');
if (args->argc != 0) if (args->argc != 0)
template = args->argv[0]; template = args->argv[0];
if (template == NULL) if (template == NULL)
template = DISPLAY_MESSAGE_TEMPLATE; template = DISPLAY_MESSAGE_TEMPLATE;
ft = format_create(); ft = format_create(cmdq, 0);
if (c != NULL) format_defaults(ft, c, s, wl, wp);
format_client(ft, c);
format_session(ft, s);
format_winlink(ft, s, wl);
format_window_pane(ft, wp);
t = time(NULL); msg = format_expand_time(ft, template, 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); cmdq_print(cmdq, "%s", msg);
else else

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -27,25 +27,22 @@
enum cmd_retval cmd_display_panes_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_display_panes_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_display_panes_entry = { const struct cmd_entry cmd_display_panes_entry = {
"display-panes", "displayp", .name = "display-panes",
"t:", 0, 0, .alias = "displayp",
CMD_TARGET_CLIENT_USAGE,
0, .args = { "t:", 0, 0 },
NULL, .usage = CMD_TARGET_CLIENT_USAGE,
NULL,
cmd_display_panes_exec .tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_display_panes_exec
}; };
enum cmd_retval enum cmd_retval
cmd_display_panes_exec(struct cmd *self, struct cmd_q *cmdq) cmd_display_panes_exec(__unused struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; server_set_identify(cmdq->state.c);
struct client *c;
if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
server_set_identify(c);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -28,6 +28,11 @@
* Find window containing text. * Find window containing text.
*/ */
#define FIND_WINDOW_TEMPLATE \
"#{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 *); enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmd_q *);
void cmd_find_window_callback(struct window_choose_data *); void cmd_find_window_callback(struct window_choose_data *);
@ -43,24 +48,28 @@ void cmd_find_window_callback(struct window_choose_data *);
CMD_FIND_WINDOW_BY_NAME) CMD_FIND_WINDOW_BY_NAME)
const struct cmd_entry cmd_find_window_entry = { const struct cmd_entry cmd_find_window_entry = {
"find-window", "findw", .name = "find-window",
"F:CNt:T", 1, 4, .alias = "findw",
"[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string",
0, .args = { "F:CNt:T", 1, 4 },
NULL, .usage = "[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string",
NULL,
cmd_find_window_exec .tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_find_window_exec
}; };
struct cmd_find_window_data { struct cmd_find_window_data {
struct winlink *wl; struct winlink *wl;
char *list_ctx; char *list_ctx;
u_int pane_id; u_int pane_id;
TAILQ_ENTRY(cmd_find_window_data) entry;
}; };
ARRAY_DECL(cmd_find_window_data_list, struct cmd_find_window_data); TAILQ_HEAD(cmd_find_window_list, cmd_find_window_data);
u_int cmd_find_window_match_flags(struct args *); u_int cmd_find_window_match_flags(struct args *);
void cmd_find_window_match(struct cmd_find_window_data_list *, int, void cmd_find_window_match(struct cmd_find_window_list *, int,
struct winlink *, const char *, const char *); struct winlink *, const char *, const char *);
u_int u_int
@ -84,15 +93,16 @@ cmd_find_window_match_flags(struct args *args)
} }
void void
cmd_find_window_match(struct cmd_find_window_data_list *find_list, cmd_find_window_match(struct cmd_find_window_list *find_list,
int match_flags, struct winlink *wl, const char *str, const char *searchstr) int match_flags, struct winlink *wl, const char *str,
const char *searchstr)
{ {
struct cmd_find_window_data find_data; struct cmd_find_window_data *find_data;
struct window_pane *wp; struct window_pane *wp;
u_int i, line; u_int i, line;
char *sres; char *sres;
memset(&find_data, 0, sizeof find_data); find_data = xcalloc(1, sizeof *find_data);
i = 0; i = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) { TAILQ_FOREACH(wp, &wl->window->panes, entry) {
@ -100,53 +110,53 @@ cmd_find_window_match(struct cmd_find_window_data_list *find_list,
if ((match_flags & CMD_FIND_WINDOW_BY_NAME) && if ((match_flags & CMD_FIND_WINDOW_BY_NAME) &&
fnmatch(searchstr, wl->window->name, 0) == 0) { fnmatch(searchstr, wl->window->name, 0) == 0) {
find_data.list_ctx = xstrdup(""); find_data->list_ctx = xstrdup("");
break; break;
} }
if ((match_flags & CMD_FIND_WINDOW_BY_TITLE) && if ((match_flags & CMD_FIND_WINDOW_BY_TITLE) &&
fnmatch(searchstr, wp->base.title, 0) == 0) { fnmatch(searchstr, wp->base.title, 0) == 0) {
xasprintf(&find_data.list_ctx, xasprintf(&find_data->list_ctx,
"pane %u title: \"%s\"", i - 1, wp->base.title); "pane %u title: \"%s\"", i - 1, wp->base.title);
break; break;
} }
if (match_flags & CMD_FIND_WINDOW_BY_CONTENT && if (match_flags & CMD_FIND_WINDOW_BY_CONTENT &&
(sres = window_pane_search(wp, str, &line)) != NULL) { (sres = window_pane_search(wp, str, &line)) != NULL) {
xasprintf(&find_data.list_ctx, xasprintf(&find_data->list_ctx,
"pane %u line %u: \"%s\"", i - 1, line + 1, sres); "pane %u line %u: \"%s\"", i - 1, line + 1, sres);
free(sres); free(sres);
break; break;
} }
} }
if (find_data.list_ctx != NULL) {
find_data.wl = wl; if (find_data->list_ctx != NULL) {
find_data.pane_id = i - 1; find_data->wl = wl;
ARRAY_ADD(find_list, find_data); find_data->pane_id = i - 1;
} TAILQ_INSERT_TAIL(find_list, find_data, entry);
} else
free(find_data);
} }
enum cmd_retval enum cmd_retval
cmd_find_window_exec(struct cmd *self, struct cmd_q *cmdq) 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 client *c = cmdq->state.c;
struct window_choose_data *cdata; struct window_choose_data *cdata;
struct session *s; struct session *s = cmdq->state.tflag.s;
struct winlink *wl, *wm; struct winlink *wl = cmdq->state.tflag.wl, *wm;
struct cmd_find_window_data_list find_list; struct cmd_find_window_list find_list;
struct cmd_find_window_data *find_data;
struct cmd_find_window_data *find_data1;
char *str, *searchstr; char *str, *searchstr;
const char *template; const char *template;
u_int i, match_flags; u_int i, match_flags;
if ((c = cmd_current_client(cmdq)) == NULL) { if (c == NULL) {
cmdq_error(cmdq, "no client available"); cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
s = c->session;
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR);
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = FIND_WINDOW_TEMPLATE; template = FIND_WINDOW_TEMPLATE;
@ -154,21 +164,20 @@ cmd_find_window_exec(struct cmd *self, struct cmd_q *cmdq)
match_flags = cmd_find_window_match_flags(args); match_flags = cmd_find_window_match_flags(args);
str = args->argv[0]; str = args->argv[0];
ARRAY_INIT(&find_list); TAILQ_INIT(&find_list);
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); cmd_find_window_match(&find_list, match_flags, wm, str, searchstr);
free(searchstr); free(searchstr);
if (ARRAY_LENGTH(&find_list) == 0) { if (TAILQ_EMPTY(&find_list)) {
cmdq_error(cmdq, "no windows matching: %s", str); cmdq_error(cmdq, "no windows matching: %s", str);
ARRAY_FREE(&find_list);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (ARRAY_LENGTH(&find_list) == 1) { if (TAILQ_NEXT(TAILQ_FIRST(&find_list), entry) == NULL) {
if (session_select(s, ARRAY_FIRST(&find_list).wl->idx) == 0) if (session_select(s, TAILQ_FIRST(&find_list)->wl->idx) == 0)
server_redraw_session(s); server_redraw_session(s);
recalculate_sizes(); recalculate_sizes();
goto out; goto out;
@ -177,30 +186,33 @@ 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++) { i = 0;
wm = ARRAY_ITEM(&find_list, i).wl; TAILQ_FOREACH(find_data, &find_list, entry) {
cdata = window_choose_data_create(TREE_OTHER, c, c->session); cdata = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = wm->idx; cdata->idx = find_data->wl->idx;
cdata->wl = wm; cdata->wl = find_data->wl;
cdata->ft_template = xstrdup(template); cdata->ft_template = xstrdup(template);
cdata->pane_id = ARRAY_ITEM(&find_list, i).pane_id; cdata->pane_id = find_data->pane_id;
format_add(cdata->ft, "line", "%u", i); format_add(cdata->ft, "line", "%u", i);
format_add(cdata->ft, "window_find_matches", "%s", format_add(cdata->ft, "window_find_matches", "%s",
ARRAY_ITEM(&find_list, i).list_ctx); find_data->list_ctx);
format_session(cdata->ft, s); format_defaults(cdata->ft, NULL, s, find_data->wl, NULL);
format_winlink(cdata->ft, s, wm);
format_window_pane(cdata->ft, wm->window->active);
window_choose_add(wl->window->active, cdata); window_choose_add(wl->window->active, cdata);
i++;
} }
window_choose_ready(wl->window->active, 0, cmd_find_window_callback); window_choose_ready(wl->window->active, 0, cmd_find_window_callback);
out: out:
ARRAY_FREE(&find_list); TAILQ_FOREACH_SAFE(find_data, &find_list, entry, find_data1) {
free(find_data->list_ctx);
TAILQ_REMOVE(&find_list, find_data, entry);
free(find_data);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

1228
cmd-find.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,48 +0,0 @@
/* $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.
*/
enum cmd_retval cmd_has_session_exec(struct cmd *, struct cmd_q *);
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
};
enum cmd_retval
cmd_has_session_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
if (cmd_find_session(cmdq, args_get(args, 't'), 0) == NULL)
return (CMD_RETURN_ERROR);
return (CMD_RETURN_NORMAL);
}

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@ -36,21 +36,28 @@ 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", .name = "if-shell",
"bt:", 2, 3, .alias = "if",
"[-b] " CMD_TARGET_PANE_USAGE " shell-command command [command]",
0, .args = { "bFt:", 2, 3 },
NULL, .usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command "
NULL, "[command]",
cmd_if_shell_exec
.tflag = CMD_PANE_CANFAIL,
.flags = 0,
.exec = cmd_if_shell_exec
}; };
struct cmd_if_shell_data { struct cmd_if_shell_data {
char *cmd_if; char *cmd_if;
char *cmd_else; char *cmd_else;
struct cmd_q *cmdq; struct cmd_q *cmdq;
struct mouse_event mouse;
int bflag; int bflag;
int started; int references;
}; };
enum cmd_retval enum cmd_retval
@ -58,47 +65,65 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_if_shell_data *cdata; struct cmd_if_shell_data *cdata;
char *shellcmd; char *shellcmd, *cmd, *cause;
struct client *c; struct cmd_list *cmdlist;
struct session *s = NULL; struct session *s = cmdq->state.tflag.s;
struct winlink *wl = NULL; struct winlink *wl = cmdq->state.tflag.wl;
struct window_pane *wp = NULL; struct window_pane *wp = cmdq->state.tflag.wp;
struct format_tree *ft; struct format_tree *ft;
const char *cwd;
if (args_has(args, 't')) cwd = wp->cwd;
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(); if (cmdq->client != NULL && cmdq->client->session == NULL)
if (s != NULL) cwd = cmdq->client->cwd;
format_session(ft, s); else if (s != NULL)
if (s != NULL && wl != NULL) cwd = s->cwd;
format_winlink(ft, s, wl); else
if (wp != NULL) cwd = NULL;
format_window_pane(ft, wp); ft = format_create(cmdq, 0);
format_defaults(ft, NULL, s, wl, wp);
shellcmd = format_expand(ft, args->argv[0]); shellcmd = format_expand(ft, args->argv[0]);
format_free(ft); 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];
free(shellcmd);
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, &cmdq->item->mouse);
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_if = xstrdup(args->argv[1]);
if (args->argc == 3) if (args->argc == 3)
cdata->cmd_else = xstrdup(args->argv[2]); cdata->cmd_else = xstrdup(args->argv[2]);
else else
cdata->cmd_else = NULL; cdata->cmd_else = NULL;
cdata->bflag = args_has(args, 'b'); cdata->bflag = args_has(args, 'b');
cdata->started = 0;
cdata->cmdq = cmdq; cdata->cmdq = cmdq;
memcpy(&cdata->mouse, &cmdq->item->mouse, sizeof cdata->mouse);
cmdq->references++; cmdq->references++;
job_run(shellcmd, s, cmd_if_shell_callback, cmd_if_shell_free, cdata); cdata->references = 1;
job_run(shellcmd, s, cwd, cmd_if_shell_callback, cmd_if_shell_free,
cdata);
free(shellcmd); free(shellcmd);
if (cdata->bflag) if (cdata->bflag)
@ -114,7 +139,7 @@ cmd_if_shell_callback(struct job *job)
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
char *cause, *cmd; char *cause, *cmd;
if (cmdq->dead) if (cmdq->flags & CMD_Q_DEAD)
return; return;
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
@ -132,13 +157,12 @@ cmd_if_shell_callback(struct job *job)
return; return;
} }
cdata->started = 1;
cmdq1 = cmdq_new(cmdq->client); cmdq1 = cmdq_new(cmdq->client);
cmdq1->emptyfn = cmd_if_shell_done; cmdq1->emptyfn = cmd_if_shell_done;
cmdq1->data = cdata; cmdq1->data = cdata;
cmdq_run(cmdq1, cmdlist); cdata->references++;
cmdq_run(cmdq1, cmdlist, &cdata->mouse);
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
} }
@ -148,11 +172,16 @@ cmd_if_shell_done(struct cmd_q *cmdq1)
struct cmd_if_shell_data *cdata = cmdq1->data; struct cmd_if_shell_data *cdata = cmdq1->data;
struct cmd_q *cmdq = cdata->cmdq; struct cmd_q *cmdq = cdata->cmdq;
if (cmdq1->client_exit >= 0)
cmdq->client_exit = cmdq1->client_exit;
cmdq_free(cmdq1);
if (--cdata->references != 0)
return;
if (!cmdq_free(cmdq) && !cdata->bflag) if (!cmdq_free(cmdq) && !cdata->bflag)
cmdq_continue(cmdq); cmdq_continue(cmdq);
cmdq_free(cmdq1);
free(cdata->cmd_else); free(cdata->cmd_else);
free(cdata->cmd_if); free(cdata->cmd_if);
free(cdata); free(cdata);
@ -164,7 +193,7 @@ 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_q *cmdq = cdata->cmdq;
if (cdata->started) if (--cdata->references != 0)
return; return;
if (!cmdq_free(cmdq) && !cdata->bflag) if (!cmdq_free(cmdq) && !cdata->bflag)

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2011 George Nachman <tmux@georgester.com> * Copyright (c) 2011 George Nachman <tmux@georgester.com>
@ -28,44 +28,37 @@
* Join or move a pane into another (like split/swap/kill). * Join or move a pane into another (like split/swap/kill).
*/ */
void cmd_join_pane_key_binding(struct cmd *, int);
enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmd_q *);
enum cmd_retval join_pane(struct cmd *, struct cmd_q *, int); 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", .name = "join-pane",
"bdhvp:l:s:t:", 0, 0, .alias = "joinp",
"[-bdhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]",
0, .args = { "bdhvp:l:s:t:", 0, 0 },
cmd_join_pane_key_binding, .usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
NULL,
cmd_join_pane_exec .sflag = CMD_PANE_MARKED,
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_join_pane_exec
}; };
const struct cmd_entry cmd_move_pane_entry = { const struct cmd_entry cmd_move_pane_entry = {
"move-pane", "movep", .name = "move-pane",
"bdhvp:l:s:t:", 0, 0, .alias = "movep",
"[-bdhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]",
0,
NULL,
NULL,
cmd_join_pane_exec
};
void .args = { "bdhvp:l:s:t:", 0, 0 },
cmd_join_pane_key_binding(struct cmd *self, int key) .usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
{
switch (key) { .sflag = CMD_PANE,
case '%': .tflag = CMD_PANE,
self->args = args_create(0);
args_set(self->args, 'h', NULL); .flags = 0,
break; .exec = cmd_join_pane_exec
default: };
self->args = args_create(0);
break;
}
}
enum cmd_retval enum cmd_retval
cmd_join_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_join_pane_exec(struct cmd *self, struct cmd_q *cmdq)
@ -89,16 +82,15 @@ 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_s = cmdq->state.tflag.s;
if (dst_wl == NULL) dst_wl = cmdq->state.tflag.wl;
return (CMD_RETURN_ERROR); dst_wp = cmdq->state.tflag.wp;
dst_w = dst_wl->window; dst_w = dst_wl->window;
dst_idx = dst_wl->idx; dst_idx = dst_wl->idx;
server_unzoom_window(dst_w); server_unzoom_window(dst_w);
src_wl = cmd_find_pane(cmdq, args_get(args, 's'), NULL, &src_wp); src_wl = cmdq->state.sflag.wl;
if (src_wl == NULL) src_wp = cmdq->state.sflag.wp;
return (CMD_RETURN_ERROR);
src_w = src_wl->window; src_w = src_wl->window;
server_unzoom_window(src_w); server_unzoom_window(src_w);
@ -143,11 +135,7 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
layout_close_pane(src_wp); layout_close_pane(src_wp);
if (src_w->active == src_wp) { window_lost_pane(src_w, 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)

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -29,13 +29,16 @@
enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_kill_pane_entry = { const struct cmd_entry cmd_kill_pane_entry = {
"kill-pane", "killp", .name = "kill-pane",
"at:", 0, 0, .alias = "killp",
"[-a] " CMD_TARGET_PANE_USAGE,
0, .args = { "at:", 0, 0 },
NULL, .usage = "[-a] " CMD_TARGET_PANE_USAGE,
NULL,
cmd_kill_pane_exec .tflag = CMD_PANE,
.flags = 0,
.exec = cmd_kill_pane_exec
}; };
enum cmd_retval enum cmd_retval
@ -44,12 +47,9 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_q *cmdq)
#ifdef TMATE_SLAVE #ifdef TMATE_SLAVE
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
#else #else
struct args *args = self->args; struct winlink *wl = cmdq->state.tflag.wl;
struct winlink *wl; struct window_pane *loopwp, *tmpwp, *wp = cmdq->state.tflag.wp;
struct window_pane *loopwp, *tmpwp, *wp;
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL)
return (CMD_RETURN_ERROR);
server_unzoom_window(wl->window); server_unzoom_window(wl->window);
if (window_count_panes(wl->window) == 1) { if (window_count_panes(wl->window) == 1) {

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -30,18 +30,31 @@
enum cmd_retval cmd_kill_server_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_kill_server_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_kill_server_entry = { const struct cmd_entry cmd_kill_server_entry = {
"kill-server", NULL, .name = "kill-server",
"", 0, 0, .alias = NULL,
"",
0, .args = { "", 0, 0 },
NULL, .usage = "",
NULL,
cmd_kill_server_exec .flags = 0,
.exec = cmd_kill_server_exec
};
const struct cmd_entry cmd_start_server_entry = {
.name = "start-server",
.alias = "start",
.args = { "", 0, 0 },
.usage = "",
.flags = CMD_STARTSERVER,
.exec = cmd_kill_server_exec
}; };
enum cmd_retval enum cmd_retval
cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_q *cmdq) 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 (CMD_RETURN_NORMAL);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -30,29 +30,38 @@
enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_kill_session_entry = { const struct cmd_entry cmd_kill_session_entry = {
"kill-session", NULL, .name = "kill-session",
"at:", 0, 0, .alias = NULL,
"[-a] " CMD_TARGET_SESSION_USAGE,
0, .args = { "aCt:", 0, 0 },
NULL, .usage = "[-aC] " CMD_TARGET_SESSION_USAGE,
NULL,
cmd_kill_session_exec .tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_kill_session_exec
}; };
enum cmd_retval enum cmd_retval
cmd_kill_session_exec(struct cmd *self, struct cmd_q *cmdq) cmd_kill_session_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s, *s2, *s3; struct session *s, *sloop, *stmp;
struct winlink *wl;
if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL) s = cmdq->state.tflag.s;
return (CMD_RETURN_ERROR);
if (args_has(args, 'a')) { if (args_has(args, 'C')) {
RB_FOREACH_SAFE(s2, sessions, &sessions, s3) { RB_FOREACH(wl, winlinks, &s->windows) {
if (s != s2) { wl->window->flags &= ~WINDOW_ALERTFLAGS;
server_destroy_session(s2); wl->flags &= ~WINLINK_ALERTFLAGS;
session_destroy(s2); }
server_redraw_session(s);
} else if (args_has(args, 'a')) {
RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) {
if (sloop != s) {
server_destroy_session(sloop);
session_destroy(sloop);
} }
} }
} else { } else {

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -27,25 +27,46 @@
enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_kill_window_entry = { const struct cmd_entry cmd_kill_window_entry = {
"kill-window", "killw", .name = "kill-window",
"at:", 0, 0, .alias = "killw",
"[-a] " CMD_TARGET_WINDOW_USAGE,
0, .args = { "at:", 0, 0 },
NULL, .usage = "[-a] " CMD_TARGET_WINDOW_USAGE,
NULL,
cmd_kill_window_exec .tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_kill_window_exec
};
const struct cmd_entry cmd_unlink_window_entry = {
.name = "unlink-window",
.alias = "unlinkw",
.args = { "kt:", 0, 0 },
.usage = "[-k] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_kill_window_exec
}; };
enum cmd_retval enum cmd_retval
cmd_kill_window_exec(struct cmd *self, struct cmd_q *cmdq) 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 = cmdq->state.tflag.wl, *wl2, *wl3;
struct session *s; struct window *w = wl->window;
struct session *s = cmdq->state.tflag.s;
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL) if (self->entry == &cmd_unlink_window_entry) {
if (!args_has(self->args, 'k') && !session_is_linked(s, w)) {
cmdq_error(cmdq, "window only linked to one session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
}
server_unlink_window(s, wl);
} else {
if (args_has(args, 'a')) { if (args_has(args, 'a')) {
RB_FOREACH_SAFE(wl2, winlinks, &s->windows, wl3) { RB_FOREACH_SAFE(wl2, winlinks, &s->windows, wl3) {
if (wl != wl2) if (wl != wl2)
@ -53,6 +74,7 @@ cmd_kill_window_exec(struct cmd *self, struct cmd_q *cmdq)
} }
} else } else
server_kill_window(wl->window); server_kill_window(wl->window);
}
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@ -1,65 +0,0 @@
/* $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.
*/
enum cmd_retval cmd_link_window_exec(struct cmd *, struct cmd_q *);
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
};
enum cmd_retval
cmd_link_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct session *src, *dst;
struct winlink *wl;
char *cause;
int idx, kflag, dflag;
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');
dflag = args_has(self->args, 'd');
if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) {
cmdq_error(cmdq, "can't link window: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
recalculate_sizes();
return (CMD_RETURN_NORMAL);
}

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -27,36 +27,38 @@
* List paste buffers. * List paste buffers.
*/ */
#define LIST_BUFFERS_TEMPLATE \
"#{buffer_name}: #{buffer_size} bytes: \"#{buffer_sample}\""
enum cmd_retval cmd_list_buffers_exec(struct cmd *, struct cmd_q *); 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", .name = "list-buffers",
"F:", 0, 0, .alias = "lsb",
"[-F format]",
0, .args = { "F:", 0, 0 },
NULL, .usage = "[-F format]",
NULL,
cmd_list_buffers_exec .flags = 0,
.exec = cmd_list_buffers_exec
}; };
enum cmd_retval enum cmd_retval
cmd_list_buffers_exec(unused struct cmd *self, struct cmd_q *cmdq) cmd_list_buffers_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct paste_buffer *pb; struct paste_buffer *pb;
struct format_tree *ft; struct format_tree *ft;
u_int idx;
char *line; char *line;
const char *template; const char *template;
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = LIST_BUFFERS_TEMPLATE; template = LIST_BUFFERS_TEMPLATE;
idx = 0; pb = NULL;
while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) { while ((pb = paste_walk(pb)) != NULL) {
ft = format_create(); ft = format_create(cmdq, 0);
format_add(ft, "line", "%u", idx - 1); format_defaults_paste_buffer(ft, pb);
format_paste_buffer(ft, pb);
line = format_expand(ft, template); line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line); cmdq_print(cmdq, "%s", line);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -28,16 +28,24 @@
* List all clients. * List all clients.
*/ */
#define LIST_CLIENTS_TEMPLATE \
"#{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 *); 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", .name = "list-clients",
"F:t:", 0, 0, .alias = "lsc",
"[-F format] " CMD_TARGET_SESSION_USAGE,
CMD_READONLY, .args = { "F:t:", 0, 0 },
NULL, .usage = "[-F format] " CMD_TARGET_SESSION_USAGE,
NULL,
cmd_list_clients_exec .tflag = CMD_SESSION,
.flags = CMD_READONLY,
.exec = cmd_list_clients_exec
}; };
enum cmd_retval enum cmd_retval
@ -48,37 +56,33 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_q *cmdq)
struct session *s; struct session *s;
struct format_tree *ft; struct format_tree *ft;
const char *template; const char *template;
u_int i; u_int idx;
char *line; char *line;
if (args_has(args, 't')) { if (args_has(args, 't'))
s = cmd_find_session(cmdq, args_get(args, 't'), 0); s = cmdq->state.tflag.s;
if (s == NULL) else
return (CMD_RETURN_ERROR);
} else
s = NULL; s = NULL;
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = LIST_CLIENTS_TEMPLATE; template = LIST_CLIENTS_TEMPLATE;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { idx = 0;
c = ARRAY_ITEM(&clients, i); TAILQ_FOREACH(c, &clients, entry) {
if (c == NULL || c->session == NULL) if (c->session == NULL || (s != NULL && s != c->session))
continue; continue;
if (s != NULL && s != c->session) ft = format_create(cmdq, 0);
continue; format_add(ft, "line", "%u", idx);
format_defaults(ft, c, NULL, NULL, NULL);
ft = format_create();
format_add(ft, "line", "%u", i);
format_session(ft, c->session);
format_client(ft, c);
line = format_expand(ft, template); line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line); cmdq_print(cmdq, "%s", line);
free(line); free(line);
format_free(ft); format_free(ft);
idx++;
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@ -1,55 +0,0 @@
/* $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.
*/
enum cmd_retval cmd_list_commands_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_list_commands_entry = {
"list-commands", "lscm",
"", 0, 0,
"",
0,
NULL,
NULL,
cmd_list_commands_exec
};
enum cmd_retval
cmd_list_commands_exec(unused struct cmd *self, struct cmd_q *cmdq)
{
const struct cmd_entry **entryp;
for (entryp = cmd_table; *entryp != NULL; entryp++) {
if ((*entryp)->alias != NULL) {
cmdq_print(cmdq, "%s (%s) %s", (*entryp)->name,
(*entryp)->alias, (*entryp)->usage);
} else {
cmdq_print(cmdq, "%s %s", (*entryp)->name,
(*entryp)->usage);
}
}
return (CMD_RETURN_NORMAL);
}

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -18,6 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
@ -27,72 +28,105 @@
*/ */
enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmd_q *);
enum cmd_retval cmd_list_keys_table(struct cmd *, struct cmd_q *); enum cmd_retval cmd_list_keys_table(struct cmd *, struct cmd_q *);
enum cmd_retval cmd_list_keys_commands(struct cmd_q *);
const struct cmd_entry cmd_list_keys_entry = { const struct cmd_entry cmd_list_keys_entry = {
"list-keys", "lsk", .name = "list-keys",
"t:", 0, 0, .alias = "lsk",
"[-t key-table]",
0, .args = { "t:T:", 0, 0 },
NULL, .usage = "[-t mode-table] [-T key-table]",
NULL,
cmd_list_keys_exec .flags = CMD_STARTSERVER,
.exec = cmd_list_keys_exec
};
const struct cmd_entry cmd_list_commands_entry = {
.name = "list-commands",
.alias = "lscm",
.args = { "", 0, 0 },
.usage = "",
.flags = CMD_STARTSERVER,
.exec = cmd_list_keys_exec
}; };
enum cmd_retval enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq) cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct key_table *table;
struct key_binding *bd; struct key_binding *bd;
const char *key; const char *key, *tablename, *r;
char tmp[BUFSIZ], flags[8]; char *cp, tmp[BUFSIZ];
size_t used; int repeat, width, tablewidth, keywidth;
int width, keywidth;
if (self->entry == &cmd_list_commands_entry)
return (cmd_list_keys_commands(cmdq));
if (args_has(args, 't')) if (args_has(args, 't'))
return (cmd_list_keys_table(self, cmdq)); return (cmd_list_keys_table(self, cmdq));
width = 0; tablename = args_get(args, 'T');
if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) {
RB_FOREACH(bd, key_bindings, &key_bindings) { cmdq_error(cmdq, "table %s doesn't exist", tablename);
key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); return (CMD_RETURN_ERROR);
if (key == NULL)
continue;
keywidth = strlen(key);
if (!(bd->key & KEYC_PREFIX)) {
if (bd->can_repeat)
keywidth += 4;
else
keywidth += 3;
} else if (bd->can_repeat)
keywidth += 3;
if (keywidth > width)
width = keywidth;
} }
RB_FOREACH(bd, key_bindings, &key_bindings) { repeat = 0;
key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); tablewidth = keywidth = 0;
if (key == NULL) RB_FOREACH(table, key_tables, &key_tables) {
if (tablename != NULL && strcmp(table->name, tablename) != 0)
continue; continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
key = key_string_lookup_key(bd->key);
*flags = '\0';
if (!(bd->key & KEYC_PREFIX)) {
if (bd->can_repeat) if (bd->can_repeat)
xsnprintf(flags, sizeof flags, "-rn "); repeat = 1;
else
xsnprintf(flags, sizeof flags, "-n ");
} else if (bd->can_repeat)
xsnprintf(flags, sizeof flags, "-r ");
used = xsnprintf(tmp, sizeof tmp, "%s%*s ", width = utf8_cstrwidth(table->name);
flags, (int) (width - strlen(flags)), key); if (width > tablewidth)
if (used >= sizeof tmp) tablewidth = width;
width = utf8_cstrwidth(key);
if (width > keywidth)
keywidth = width;
}
}
RB_FOREACH(table, key_tables, &key_tables) {
if (tablename != NULL && strcmp(table->name, tablename) != 0)
continue; continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
key = key_string_lookup_key(bd->key);
if (!repeat)
r = "";
else if (bd->can_repeat)
r = "-r ";
else
r = " ";
xsnprintf(tmp, sizeof tmp, "%s-T ", r);
cp = utf8_padcstr(table->name, tablewidth);
strlcat(tmp, cp, sizeof tmp);
strlcat(tmp, " ", sizeof tmp);
free(cp);
cp = utf8_padcstr(key, keywidth);
strlcat(tmp, cp, sizeof tmp);
strlcat(tmp, " ", sizeof tmp);
free(cp);
cp = cmd_list_print(bd->cmdlist);
strlcat(tmp, cp, sizeof tmp);
free(cp);
cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used);
cmdq_print(cmdq, "bind-key %s", tmp); cmdq_print(cmdq, "bind-key %s", tmp);
} }
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@ -117,8 +151,6 @@ cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq)
any_mode = 0; any_mode = 0;
RB_FOREACH(mbind, mode_key_tree, mtab->tree) { RB_FOREACH(mbind, mode_key_tree, mtab->tree) {
key = key_string_lookup_key(mbind->key); key = key_string_lookup_key(mbind->key);
if (key == NULL)
continue;
if (mbind->mode != 0) if (mbind->mode != 0)
any_mode = 1; any_mode = 1;
@ -130,8 +162,6 @@ cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq)
RB_FOREACH(mbind, mode_key_tree, mtab->tree) { RB_FOREACH(mbind, mode_key_tree, mtab->tree) {
key = key_string_lookup_key(mbind->key); key = key_string_lookup_key(mbind->key);
if (key == NULL)
continue;
mode = ""; mode = "";
if (mbind->mode != 0) if (mbind->mode != 0)
@ -149,3 +179,22 @@ cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
enum cmd_retval
cmd_list_keys_commands(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 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* 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 <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
@ -30,41 +29,37 @@
enum cmd_retval cmd_list_panes_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_list_panes_exec(struct cmd *, struct cmd_q *);
void cmd_list_panes_server(struct cmd *, struct cmd_q *); void cmd_list_panes_server(struct cmd *, struct cmd_q *);
void cmd_list_panes_session( void cmd_list_panes_session(struct cmd *, struct session *, struct cmd_q *,
struct cmd *, struct session *, struct cmd_q *, int); int);
void cmd_list_panes_window(struct cmd *, void cmd_list_panes_window(struct cmd *, struct session *, struct winlink *,
struct session *, struct winlink *, struct cmd_q *, int); struct cmd_q *, int);
const struct cmd_entry cmd_list_panes_entry = { const struct cmd_entry cmd_list_panes_entry = {
"list-panes", "lsp", .name = "list-panes",
"asF:t:", 0, 0, .alias = "lsp",
"[-as] [-F format] " CMD_TARGET_WINDOW_USAGE,
0, .args = { "asF:t:", 0, 0 },
NULL, .usage = "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE,
NULL,
cmd_list_panes_exec .tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_list_panes_exec
}; };
enum cmd_retval enum cmd_retval
cmd_list_panes_exec(struct cmd *self, struct cmd_q *cmdq) cmd_list_panes_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s = cmdq->state.tflag.s;
struct winlink *wl; struct winlink *wl = cmdq->state.tflag.wl;
if (args_has(args, 'a')) if (args_has(args, 'a'))
cmd_list_panes_server(self, cmdq); cmd_list_panes_server(self, cmdq);
else if (args_has(args, 's')) { else if (args_has(args, 's'))
s = cmd_find_session(cmdq, args_get(args, 't'), 0);
if (s == NULL)
return (CMD_RETURN_ERROR);
cmd_list_panes_session(self, s, cmdq, 1); cmd_list_panes_session(self, s, cmdq, 1);
} else { else
wl = cmd_find_window(cmdq, args_get(args, 't'), &s);
if (wl == NULL)
return (CMD_RETURN_ERROR);
cmd_list_panes_window(self, s, wl, cmdq, 0); cmd_list_panes_window(self, s, wl, cmdq, 0);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@ -79,8 +74,8 @@ cmd_list_panes_server(struct cmd *self, struct cmd_q *cmdq)
} }
void void
cmd_list_panes_session( cmd_list_panes_session(struct cmd *self, struct session *s, struct cmd_q *cmdq,
struct cmd *self, struct session *s, struct cmd_q *cmdq, int type) int type)
{ {
struct winlink *wl; struct winlink *wl;
@ -89,8 +84,8 @@ cmd_list_panes_session(
} }
void void
cmd_list_panes_window(struct cmd *self, cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
struct session *s, struct winlink *wl, struct cmd_q *cmdq, int type) struct cmd_q *cmdq, int type)
{ {
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp; struct window_pane *wp;
@ -117,9 +112,9 @@ cmd_list_panes_window(struct cmd *self,
"#{?pane_active, (active),}#{?pane_dead, (dead),}"; "#{?pane_active, (active),}#{?pane_dead, (dead),}";
break; break;
case 2: case 2:
template = "#{session_name}:#{window_index}.#{pane_index}: " template = "#{session_name}:#{window_index}."
"[#{pane_width}x#{pane_height}] [history " "#{pane_index}: [#{pane_width}x#{pane_height}] "
"#{history_size}/#{history_limit}, " "[history #{history_size}/#{history_limit}, "
"#{history_bytes} bytes] #{pane_id}" "#{history_bytes} bytes] #{pane_id}"
"#{?pane_active, (active),}#{?pane_dead, (dead),}"; "#{?pane_active, (active),}#{?pane_dead, (dead),}";
break; break;
@ -128,11 +123,9 @@ cmd_list_panes_window(struct cmd *self,
n = 0; n = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) { TAILQ_FOREACH(wp, &wl->window->panes, entry) {
ft = format_create(); ft = format_create(cmdq, 0);
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_session(ft, s); format_defaults(ft, NULL, s, wl, wp);
format_winlink(ft, s, wl);
format_window_pane(ft, wp);
line = format_expand(ft, template); line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line); cmdq_print(cmdq, "%s", line);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -28,16 +28,25 @@
* List all sessions. * List all sessions.
*/ */
#define LIST_SESSIONS_TEMPLATE \
"#{session_name}: #{session_windows} windows " \
"(created #{t:session_created}) " \
"[#{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 *); 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", .name = "list-sessions",
"F:", 0, 0, .alias = "ls",
"[-F format]",
0, .args = { "F:", 0, 0 },
NULL, .usage = "[-F format]",
NULL,
cmd_list_sessions_exec .flags = 0,
.exec = cmd_list_sessions_exec
}; };
enum cmd_retval enum cmd_retval
@ -55,9 +64,9 @@ cmd_list_sessions_exec(struct cmd *self, struct cmd_q *cmdq)
n = 0; n = 0;
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
ft = format_create(); ft = format_create(cmdq, 0);
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_session(ft, s); format_defaults(ft, NULL, s, NULL, NULL);
line = format_expand(ft, template); line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line); cmdq_print(cmdq, "%s", line);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -27,36 +27,46 @@
* List windows on given session. * List windows on given session.
*/ */
#define LIST_WINDOWS_TEMPLATE \
"#{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 *); enum cmd_retval cmd_list_windows_exec(struct cmd *, struct cmd_q *);
void cmd_list_windows_server(struct cmd *, struct cmd_q *); void cmd_list_windows_server(struct cmd *, struct cmd_q *);
void cmd_list_windows_session( void cmd_list_windows_session(struct cmd *, struct session *,
struct cmd *, struct session *, struct cmd_q *, int); struct cmd_q *, int);
const struct cmd_entry cmd_list_windows_entry = { const struct cmd_entry cmd_list_windows_entry = {
"list-windows", "lsw", .name = "list-windows",
"F:at:", 0, 0, .alias = "lsw",
"[-a] [-F format] " CMD_TARGET_SESSION_USAGE,
0, .args = { "F:at:", 0, 0 },
NULL, .usage = "[-a] [-F format] " CMD_TARGET_SESSION_USAGE,
NULL,
cmd_list_windows_exec .tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_list_windows_exec
}; };
enum cmd_retval enum cmd_retval
cmd_list_windows_exec(struct cmd *self, struct cmd_q *cmdq) cmd_list_windows_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s;
if (args_has(args, 'a')) if (args_has(args, 'a'))
cmd_list_windows_server(self, cmdq); cmd_list_windows_server(self, cmdq);
else { else
s = cmd_find_session(cmdq, args_get(args, 't'), 0); cmd_list_windows_session(self, cmdq->state.tflag.s, cmdq, 0);
if (s == NULL)
return (CMD_RETURN_ERROR);
cmd_list_windows_session(self, s, cmdq, 0);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@ -71,8 +81,8 @@ cmd_list_windows_server(struct cmd *self, struct cmd_q *cmdq)
} }
void void
cmd_list_windows_session( cmd_list_windows_session(struct cmd *self, struct session *s,
struct cmd *self, struct session *s, struct cmd_q *cmdq, int type) struct cmd_q *cmdq, int type)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl;
@ -95,11 +105,9 @@ cmd_list_windows_session(
n = 0; n = 0;
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
ft = format_create(); ft = format_create(cmdq, 0);
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_session(ft, s); format_defaults(ft, NULL, s, wl, NULL);
format_winlink(ft, s, wl);
format_window_pane(ft, wl->window->active);
line = format_expand(ft, template); line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line); cmdq_print(cmdq, "%s", line);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -99,21 +99,28 @@ cmd_list_free(struct cmd_list *cmdlist)
free(cmdlist); free(cmdlist);
} }
size_t char *
cmd_list_print(struct cmd_list *cmdlist, char *buf, size_t len) cmd_list_print(struct cmd_list *cmdlist)
{ {
struct cmd *cmd; struct cmd *cmd;
size_t off; char *buf, *this;
size_t len;
len = 1;
buf = xcalloc(1, len);
off = 0;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
if (off >= len) this = cmd_print(cmd);
break;
off += cmd_print(cmd, buf + off, len - off); len += strlen(this) + 3;
if (off >= len) buf = xrealloc(buf, len);
break;
strlcat(buf, this, len);
if (TAILQ_NEXT(cmd, qentry) != NULL) if (TAILQ_NEXT(cmd, qentry) != NULL)
off += xsnprintf(buf + off, len - off, " ; "); strlcat(buf, " ; ", len);
free(this);
} }
return (off);
return (buf);
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@ -19,6 +19,7 @@
#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>
@ -34,13 +35,14 @@ enum cmd_retval cmd_load_buffer_exec(struct cmd *, struct cmd_q *);
void cmd_load_buffer_callback(struct client *, int, void *); void cmd_load_buffer_callback(struct client *, int, void *);
const struct cmd_entry cmd_load_buffer_entry = { const struct cmd_entry cmd_load_buffer_entry = {
"load-buffer", "loadb", .name = "load-buffer",
"b:", 1, 1, .alias = "loadb",
CMD_BUFFER_USAGE " path",
0, .args = { "b:", 1, 1 },
NULL, .usage = CMD_BUFFER_USAGE " path",
NULL,
cmd_load_buffer_exec .flags = 0,
.exec = cmd_load_buffer_exec
}; };
enum cmd_retval enum cmd_retval
@ -50,30 +52,19 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
struct client *c = cmdq->client; struct client *c = cmdq->client;
struct session *s; struct session *s;
FILE *f; FILE *f;
const char *path, *newpath, *wd; const char *path, *bufname, *cwd;
char *pdata, *new_pdata, *cause; char *pdata, *new_pdata, *cause, *file, resolved[PATH_MAX];
size_t psize; size_t psize;
u_int limit; int ch, error;
int ch, error, buffer, *buffer_ptr;
if (!args_has(args, 'b')) bufname = NULL;
buffer = -1; if (args_has(args, 'b'))
else { bufname = args_get(args, 'b');
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(cmdq, "buffer %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
path = args->argv[0]; path = args->argv[0];
if (strcmp(path, "-") == 0) { if (strcmp(path, "-") == 0) {
buffer_ptr = xmalloc(sizeof *buffer_ptr);
*buffer_ptr = buffer;
error = server_set_stdin_callback(c, cmd_load_buffer_callback, error = server_set_stdin_callback(c, cmd_load_buffer_callback,
buffer_ptr, &cause); (void *)bufname, &cause);
if (error != 0) { if (error != 0) {
cmdq_error(cmdq, "%s: %s", path, cause); cmdq_error(cmdq, "%s: %s", path, cause);
free(cause); free(cause);
@ -82,21 +73,26 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
if (c != NULL) if (c != NULL && c->session == NULL)
wd = c->cwd; cwd = c->cwd;
else if ((s = cmd_current_session(cmdq, 0)) != NULL) { else if ((s = c->session) != NULL)
wd = options_get_string(&s->options, "default-path"); cwd = s->cwd;
if (*wd == '\0') else
wd = s->cwd; cwd = ".";
} else
wd = NULL; if (*path == '/')
if (wd != NULL && *wd != '\0') { file = xstrdup(path);
newpath = get_full_path(wd, path); else
if (newpath != NULL) xasprintf(&file, "%s/%s", cwd, path);
path = newpath; if (realpath(file, resolved) == NULL &&
strlcpy(resolved, file, sizeof resolved) >= sizeof resolved) {
cmdq_error(cmdq, "%s: %s", file, strerror(ENAMETOOLONG));
return (CMD_RETURN_ERROR);
} }
if ((f = fopen(path, "rb")) == NULL) { f = fopen(resolved, "rb");
cmdq_error(cmdq, "%s: %s", path, strerror(errno)); free(file);
if (f == NULL) {
cmdq_error(cmdq, "%s: %s", resolved, strerror(errno));
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@ -112,7 +108,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
pdata[psize++] = ch; pdata[psize++] = ch;
} }
if (ferror(f)) { if (ferror(f)) {
cmdq_error(cmdq, "%s: read error", path); cmdq_error(cmdq, "%s: read error", resolved);
goto error; goto error;
} }
if (pdata != NULL) if (pdata != NULL)
@ -120,14 +116,10 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
fclose(f); fclose(f);
limit = options_get_number(&global_options, "buffer-limit"); if (paste_set(pdata, psize, bufname, &cause) != 0) {
if (buffer == -1) { cmdq_error(cmdq, "%s", cause);
paste_add(&global_buffers, pdata, psize, limit);
return (CMD_RETURN_NORMAL);
}
if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) {
cmdq_error(cmdq, "no buffer %d", buffer);
free(pdata); free(pdata);
free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@ -143,38 +135,38 @@ error:
void void
cmd_load_buffer_callback(struct client *c, int closed, void *data) cmd_load_buffer_callback(struct client *c, int closed, void *data)
{ {
int *buffer = data; const char *bufname = data;
char *pdata; char *pdata, *cause, *saved;
size_t psize; size_t psize;
u_int limit;
if (!closed) if (!closed)
return; return;
c->stdin_callback = NULL; c->stdin_callback = NULL;
c->references--; server_client_unref(c);
if (c->flags & CLIENT_DEAD) if (c->flags & CLIENT_DEAD)
return; return;
psize = EVBUFFER_LENGTH(c->stdin_data); psize = EVBUFFER_LENGTH(c->stdin_data);
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) { if (psize == 0 || (pdata = malloc(psize + 1)) == NULL)
free(data);
goto out; goto out;
}
memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize); memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize);
pdata[psize] = '\0'; pdata[psize] = '\0';
evbuffer_drain(c->stdin_data, psize); evbuffer_drain(c->stdin_data, psize);
limit = options_get_number(&global_options, "buffer-limit"); if (paste_set(pdata, psize, bufname, &cause) != 0) {
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, "no buffer %d\n", *buffer); if (~c->flags & CLIENT_UTF8) {
server_push_stderr(c); saved = cause;
cause = utf8_sanitize(saved);
free(saved);
}
evbuffer_add_printf(c->stderr_data, "%s", cause);
server_client_push_stderr(c);
free(pdata);
free(cause);
} }
free(data);
out: out:
cmdq_continue(c->cmdq); cmdq_continue(c->cmdq);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -18,10 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
/* /*
@ -31,55 +27,52 @@
enum cmd_retval cmd_lock_server_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_lock_server_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_lock_server_entry = { const struct cmd_entry cmd_lock_server_entry = {
"lock-server", "lock", .name = "lock-server",
"", 0, 0, .alias = "lock",
"",
0, .args = { "", 0, 0 },
NULL, .usage = "",
NULL,
cmd_lock_server_exec .flags = 0,
.exec = cmd_lock_server_exec
}; };
const struct cmd_entry cmd_lock_session_entry = { const struct cmd_entry cmd_lock_session_entry = {
"lock-session", "locks", .name = "lock-session",
"t:", 0, 0, .alias = "locks",
CMD_TARGET_SESSION_USAGE,
0, .args = { "t:", 0, 0 },
NULL, .usage = CMD_TARGET_SESSION_USAGE,
NULL,
cmd_lock_server_exec .tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_lock_server_exec
}; };
const struct cmd_entry cmd_lock_client_entry = { const struct cmd_entry cmd_lock_client_entry = {
"lock-client", "lockc", .name = "lock-client",
"t:", 0, 0, .alias = "lockc",
CMD_TARGET_CLIENT_USAGE,
0, .args = { "t:", 0, 0 },
NULL, .usage = CMD_TARGET_CLIENT_USAGE,
NULL,
cmd_lock_server_exec .tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_lock_server_exec
}; };
enum cmd_retval enum cmd_retval
cmd_lock_server_exec(struct cmd *self, unused struct cmd_q *cmdq) cmd_lock_server_exec(struct cmd *self, __unused struct cmd_q *cmdq)
{ {
struct args *args = self->args;
struct client *c;
struct session *s;
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); server_lock_session(cmdq->state.tflag.s);
if (s == NULL) else
return (CMD_RETURN_ERROR); server_lock_client(cmdq->state.c);
server_lock_session(s);
} else {
c = cmd_find_client(cmdq, args_get(args, 't'), 0);
if (c == NULL)
return (CMD_RETURN_ERROR);
server_lock_client(c);
}
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -29,47 +29,79 @@
enum cmd_retval cmd_move_window_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_move_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_move_window_entry = { const struct cmd_entry cmd_move_window_entry = {
"move-window", "movew", .name = "move-window",
"dkrs:t:", 0, 0, .alias = "movew",
"[-dkr] " CMD_SRCDST_WINDOW_USAGE,
0, .args = { "adkrs:t:", 0, 0 },
NULL, .usage = "[-dkr] " CMD_SRCDST_WINDOW_USAGE,
NULL,
cmd_move_window_exec .sflag = CMD_WINDOW,
.tflag = CMD_MOVEW_R,
.flags = 0,
.exec = cmd_move_window_exec
};
const struct cmd_entry cmd_link_window_entry = {
.name = "link-window",
.alias = "linkw",
.args = { "adks:t:", 0, 0 },
.usage = "[-dk] " CMD_SRCDST_WINDOW_USAGE,
.sflag = CMD_WINDOW,
.tflag = CMD_WINDOW_INDEX,
.flags = 0,
.exec = cmd_move_window_exec
}; };
enum cmd_retval enum cmd_retval
cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *src, *dst, *s; struct session *src = cmdq->state.sflag.s;
struct winlink *wl; struct session *dst = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.sflag.wl;
char *cause; char *cause;
int idx, kflag, dflag; int idx = cmdq->state.tflag.idx, kflag, dflag, sflag;
if (args_has(args, 'r')) {
if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
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, &cause) != 0) {
cmdq_error(cmdq, "can't move window: %s", cause); if (args_has(args, 'r')) {
free(cause); session_renumber_windows(dst);
return (CMD_RETURN_ERROR); recalculate_sizes();
}
server_unlink_window(src, wl); return (CMD_RETURN_NORMAL);
}
kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd');
sflag = args_has(self->args, 's');
if (args_has(self->args, 'a')) {
if ((idx = winlink_shuffle_up(dst, dst->curw)) == -1)
return (CMD_RETURN_ERROR);
}
if (server_link_window(src, wl, dst, idx, kflag, !dflag,
&cause) != 0) {
cmdq_error(cmdq, "can't link window: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (self->entry == &cmd_move_window_entry)
server_unlink_window(src, wl);
/*
* Renumber the winlinks in the src session only, the destination
* session already has the correct winlink id to us, either
* automatically or specified by -s.
*/
if (!sflag && options_get_number(src->options, "renumber-windows"))
session_renumber_windows(src);
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -18,7 +18,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <pwd.h> #include <errno.h>
#include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <termios.h> #include <termios.h>
@ -30,45 +31,68 @@
* 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.
*/ */
enum cmd_retval cmd_new_session_check(struct args *); #define NEW_SESSION_TEMPLATE "#{session_name}:"
enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_q *); 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", .name = "new-session",
"AdDF:n:Ps:t:x:y:", 0, 1, .alias = "new",
"[-AdDP] [-F format] [-n window-name] [-s session-name] "
CMD_TARGET_SESSION_USAGE " [-x width] [-y height] [command]", .args = { "Ac:dDEF:n:Ps:t:x:y:", 0, -1 },
CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, .usage = "[-AdDEP] [-c start-directory] [-F format] [-n window-name] "
NULL, "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
cmd_new_session_check, "[-y height] [command]",
cmd_new_session_exec
.tflag = CMD_SESSION_CANFAIL,
.flags = CMD_STARTSERVER,
.exec = cmd_new_session_exec
}; };
enum cmd_retval const struct cmd_entry cmd_has_session_entry = {
cmd_new_session_check(struct args *args) .name = "has-session",
{ .alias = "has",
if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n')))
return (CMD_RETURN_ERROR); .args = { "t:", 0, 0 },
return (CMD_RETURN_NORMAL); .usage = CMD_TARGET_SESSION_USAGE,
}
.tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_new_session_exec
};
enum cmd_retval enum cmd_retval
cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) cmd_new_session_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 = cmdq->client;
struct session *s, *groupwith; struct session *s, *attach_sess;
struct session *groupwith = cmdq->state.tflag.s;
struct window *w; struct window *w;
struct environ env; struct environ *env;
struct termios tio, *tiop; struct termios tio, *tiop;
struct passwd *pw; const char *newname, *target, *update, *errstr, *template;
const char *newname, *target, *update, *cwd, *errstr; const char *path, *cwd, *to_free;
const char *template; char **argv, *cmd, *cause, *cp;
char *cmd, *cause, *cp; int detached, already_attached, idx, argc;
int detached, idx;
u_int sx, sy; u_int sx, sy;
int already_attached;
struct format_tree *ft; struct format_tree *ft;
struct environ_entry *envent;
if (self->entry == &cmd_has_session_entry) {
/*
* cmd_prepare() will fail if the session cannot be found,
* hence always return success here.
*/
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) {
@ -76,22 +100,25 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
cmdq_error(cmdq, "bad session name: %s", newname); cmdq_error(cmdq, "bad session name: %s", newname);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (session_find(newname) != NULL) { if ((attach_sess = session_find(newname)) != NULL) {
if (args_has(args, 'A')) { if (args_has(args, 'A')) {
return (cmd_attach_session(cmdq, newname, /*
args_has(args, 'D'), 0)); * This cmdq is now destined for
* attach-session. Because attach-session
* will have already been prepared, copy this
* session into its tflag so it can be used.
*/
cmdq->state.tflag.s = attach_sess;
return (cmd_attach_session(cmdq,
args_has(args, 'D'), 0, NULL,
args_has(args, 'E')));
} }
cmdq_error(cmdq, "duplicate session: %s", newname); cmdq_error(cmdq, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
target = args_get(args, 't'); if ((target = args_get(args, 't')) == NULL)
if (target != NULL) {
groupwith = cmd_find_session(cmdq, target, 0);
if (groupwith == NULL)
return (CMD_RETURN_ERROR);
} else
groupwith = NULL; groupwith = NULL;
/* Set -d if no client. */ /* Set -d if no client. */
@ -104,16 +131,33 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
if (c != NULL && c->session != NULL) if (c != NULL && c->session != NULL)
already_attached = 1; already_attached = 1;
/* Get the new session working directory. */
to_free = NULL;
if (args_has(args, 'c')) {
ft = format_create(cmdq, 0);
format_defaults(ft, c, NULL, NULL, NULL);
to_free = cwd = format_expand(ft, args_get(args, 'c'));
format_free(ft);
} else if (c != NULL && c->session == NULL)
cwd = c->cwd;
else
cwd = ".";
/* /*
* Save the termios settings, part of which is used for new windows in * If this is a new client, check for nesting and save the termios
* this session. * settings (part of which is used for new windows in this session).
* *
* This is read again with tcgetattr() rather than using tty.tio as if * tcgetattr() is used rather than using tty.tio since if the client is
* detached, tty_open won't be called. Because of this, it must be done * detached, tty_open won't be called. It must be done before opening
* before opening the terminal as that calls tcsetattr() to prepare for * the terminal as that calls tcsetattr() to prepare for tmux taking
* tmux taking over. * over.
*/ */
if (!detached && !already_attached && c->tty.fd != -1) { if (!detached && !already_attached && c->tty.fd != -1) {
if (server_client_check_nested(cmdq->client)) {
cmdq_error(cmdq, "sessions should be nested with care, "
"unset $TMUX to force");
return (CMD_RETURN_ERROR);
}
if (tcgetattr(c->tty.fd, &tio) != 0) if (tcgetattr(c->tty.fd, &tio) != 0)
fatal("tcgetattr failed"); fatal("tcgetattr failed");
tiop = &tio; tiop = &tio;
@ -122,24 +166,13 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
/* Open the terminal if necessary. */ /* Open the terminal if necessary. */
if (!detached && !already_attached) { if (!detached && !already_attached) {
if (server_client_open(c, NULL, &cause) != 0) { if (server_client_open(c, &cause) != 0) {
cmdq_error(cmdq, "open terminal failed: %s", cause); cmdq_error(cmdq, "open terminal failed: %s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); goto error;
} }
} }
/* Get the new session working directory. */
if (c != NULL && c->cwd != NULL)
cwd = c->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 (c != NULL) {
sx = c->tty.sx; sx = c->tty.sx;
@ -152,17 +185,17 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr); sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
cmdq_error(cmdq, "width %s", errstr); cmdq_error(cmdq, "width %s", errstr);
return (CMD_RETURN_ERROR); goto error;
} }
} }
if (detached && args_has(args, 'y')) { if (detached && args_has(args, 'y')) {
sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr); sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
cmdq_error(cmdq, "height %s", errstr); cmdq_error(cmdq, "height %s", errstr);
return (CMD_RETURN_ERROR); goto error;
} }
} }
if (sy > 0 && options_get_number(&global_s_options, "status")) if (sy > 0 && options_get_number(global_s_options, "status"))
sy--; sy--;
if (sx == 0) if (sx == 0)
sx = 1; sx = 1;
@ -170,44 +203,64 @@ 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. */
if (target != NULL) argc = -1;
cmd = NULL; argv = NULL;
else if (args->argc != 0) if (!args_has(args, 't') && args->argc != 0) {
cmd = args->argv[0]; argc = args->argc;
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
cmd = options_get_string(&global_s_options, "default-command"); envent = environ_find(global_environ, "PATH");
if (envent != NULL)
path = envent->value;
/* Construct the environment. */ /* Construct the environment. */
environ_init(&env); env = environ_create();
update = options_get_string(&global_s_options, "update-environment"); if (c != NULL && !args_has(args, 'E')) {
if (c != NULL) update = options_get_string(global_s_options,
environ_update(update, &c->environ, &env); "update-environment");
environ_update(update, c->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, cmd, cwd, &env, tiop, idx, sx, sy, &cause); s = session_create(newname, argc, argv, path, cwd, env, tiop, idx, sx,
sy, &cause);
environ_free(env);
if (s == NULL) { if (s == NULL) {
cmdq_error(cmdq, "create session failed: %s", cause); cmdq_error(cmdq, "create session failed: %s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); goto error;
} }
environ_free(&env);
/* Set the initial window name if one given. */ /* Set the initial window name if one given. */
if (cmd != NULL && args_has(args, 'n')) { if (argc >= 0 && args_has(args, 'n')) {
w = s->curw->window; w = s->curw->window;
window_set_name(w, args_get(args, 'n')); window_set_name(w, args_get(args, 'n'));
options_set_number(&w->options, "automatic-rename", 0); options_set_number(w->options, "automatic-rename", 0);
} }
/* /*
* If a target session is given, this is to be part of a session group, * If a target session is given, this is to be part of a session group,
* so add it to the group and synchronize. * so add it to the group and synchronize.
*/ */
if (groupwith != NULL) { if (args_has(args, 't')) {
session_group_add(groupwith, s); session_group_add(groupwith, s);
session_group_synchronize_to(s); session_group_synchronize_to(s);
session_select(s, RB_ROOT(&s->windows)->idx); session_select(s, RB_MIN(winlinks, &s->windows)->idx);
} }
/* /*
@ -215,13 +268,17 @@ 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 (!already_attached) {
server_write_ready(c); if (~c->flags & CLIENT_CONTROL)
else if (c->session != NULL) proc_send(c->peer, MSG_READY, -1, NULL, 0);
} else if (c->session != NULL)
c->last_session = c->session; c->last_session = c->session;
c->session = s; c->session = s;
server_client_set_key_table(c, NULL);
status_timer_start(c);
notify_attached_session_changed(c); notify_attached_session_changed(c);
session_update_activity(s); session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c); server_redraw_client(c);
} }
recalculate_sizes(); recalculate_sizes();
@ -239,10 +296,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = NEW_SESSION_TEMPLATE; template = NEW_SESSION_TEMPLATE;
ft = format_create(); ft = format_create(cmdq, 0);
if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) format_defaults(ft, c, s, NULL, NULL);
format_client(ft, c);
format_session(ft, s);
cp = format_expand(ft, template); cp = format_expand(ft, template);
cmdq_print(cmdq, "%s", cp); cmdq_print(cmdq, "%s", cp);
@ -253,5 +308,13 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
if (!detached) if (!detached)
cmdq->client_exit = 0; cmdq->client_exit = 0;
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
error:
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_ERROR);
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -18,7 +18,11 @@
#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"
@ -26,59 +30,79 @@
* Create a new window. * Create a new window.
*/ */
#define NEW_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmd_q *); 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", .name = "new-window",
"ac:dF:kn:Pt:", 0, 1, .alias = "neww",
"[-adkP] [-c start-directory] [-F format] [-n window-name] "
.args = { "ac:dF:kn:Pt:", 0, -1 },
.usage = "[-adkP] [-c start-directory] [-F format] [-n window-name] "
CMD_TARGET_WINDOW_USAGE " [command]", CMD_TARGET_WINDOW_USAGE " [command]",
0,
NULL, .tflag = CMD_WINDOW_INDEX,
NULL,
cmd_new_window_exec .flags = 0,
.exec = cmd_new_window_exec
}; };
enum cmd_retval enum cmd_retval
cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s = cmdq->state.tflag.s;
struct winlink *wl; struct winlink *wl = cmdq->state.tflag.wl;
struct client *c; struct client *c = cmdq->state.c;
const char *cmd, *cwd, *template; int idx = cmdq->state.tflag.idx;
char *cause, *cp; const char *cmd, *path, *template, *cwd, *to_free;
int idx, last, detached; char **argv, *cause, *cp;
int argc, detached;
struct format_tree *ft; 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); if ((idx = winlink_shuffle_up(s, wl)) == -1) {
if (wl == NULL)
return (CMD_RETURN_ERROR);
idx = wl->idx + 1;
/* Find the next free index. */
for (last = idx; last < INT_MAX; last++) {
if (winlink_find_by_index(&s->windows, last) == NULL)
break;
}
if (last == INT_MAX) {
cmdq_error(cmdq, "no free window indexes"); cmdq_error(cmdq, "no free window indexes");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
/* Move everything from last - 1 to idx up a bit. */
for (; last > idx; last--) {
wl = winlink_find_by_index(&s->windows, last - 1);
server_link_window(s, wl, s, last, 0, 0, NULL);
server_unlink_window(s, wl);
}
} else {
if ((idx = cmd_find_index(cmdq, args_get(args, 't'), &s)) == -2)
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;
to_free = NULL;
if (args_has(args, 'c')) {
ft = format_create(cmdq, 0);
format_defaults(ft, c, s, NULL, NULL);
cwd = to_free = format_expand(ft, args_get(args, 'c'));
format_free(ft);
} 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);
@ -99,19 +123,14 @@ 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 = cmd_get_default_path(cmdq, args_get(args, 'c'));
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'), cmd, cwd, idx, &cause); wl = session_new(s, args_get(args, 'n'), argc, argv, path, cwd, idx,
&cause);
if (wl == NULL) { if (wl == NULL) {
cmdq_error(cmdq, "create window failed: %s", cause); cmdq_error(cmdq, "create window failed: %s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); goto error;
} }
if (!detached) { if (!detached) {
session_select(s, wl->idx); session_select(s, wl->idx);
@ -123,12 +142,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = NEW_WINDOW_TEMPLATE; template = NEW_WINDOW_TEMPLATE;
ft = format_create(); ft = format_create(cmdq, 0);
if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) format_defaults(ft, c, s, wl, NULL);
format_client(ft, c);
format_session(ft, s);
format_winlink(ft, s, wl);
format_window_pane(ft, wl->window->active);
cp = format_expand(ft, template); cp = format_expand(ft, template);
cmdq_print(cmdq, "%s", cp); cmdq_print(cmdq, "%s", cp);
@ -137,5 +152,12 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
format_free(ft); format_free(ft);
} }
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
error:
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_ERROR);
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -33,13 +33,17 @@ void cmd_paste_buffer_filter(struct window_pane *,
const char *, size_t, const char *, int); const char *, size_t, const char *, int);
const struct cmd_entry cmd_paste_buffer_entry = { const struct cmd_entry cmd_paste_buffer_entry = {
"paste-buffer", "pasteb", .name = "paste-buffer",
"db:prs:t:", 0, 0, .alias = "pasteb",
"[-dpr] [-s separator] [-b buffer-index] " CMD_TARGET_PANE_USAGE,
0, .args = { "db:prs:t:", 0, 0 },
NULL, .usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " "
NULL, CMD_TARGET_PANE_USAGE,
cmd_paste_buffer_exec
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_paste_buffer_exec
}; };
enum cmd_retval enum cmd_retval
@ -49,39 +53,27 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
#else #else
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp; struct window_pane *wp = cmdq->state.tflag.wp;
struct session *s;
struct paste_buffer *pb; struct paste_buffer *pb;
const char *sepstr; const char *sepstr, *bufname, *bufdata, *bufend, *line;
char *cause; size_t seplen, bufsize;
int buffer; int bracket = args_has(args, 'p');
int pflag;
if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL) bufname = NULL;
return (CMD_RETURN_ERROR); if (args_has(args, 'b'))
bufname = args_get(args, 'b');
if (!args_has(args, 'b')) if (bufname == NULL)
buffer = -1; pb = paste_get_top(NULL);
else { else {
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); pb = paste_get_name(bufname);
if (cause != NULL) {
cmdq_error(cmdq, "buffer %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
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 %d", buffer); cmdq_error(cmdq, "no buffer %s", bufname);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
if (pb != NULL) { if (pb != NULL && ~wp->flags & PANE_INPUTOFF) {
sepstr = args_get(args, 's'); sepstr = args_get(args, 's');
if (sepstr == NULL) { if (sepstr == NULL) {
if (args_has(args, 'r')) if (args_has(args, 'r'))
@ -89,17 +81,33 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
else else
sepstr = "\r"; sepstr = "\r";
} }
pflag = (wp->screen->mode & MODE_BRACKETPASTE); seplen = strlen(sepstr);
paste_send_pane(pb, wp, sepstr, args_has(args, 'p') && pflag);
if (bracket && (wp->screen->mode & MODE_BRACKETPASTE))
bufferevent_write(wp->event, "\033[200~", 6);
bufdata = paste_buffer_data(pb, &bufsize);
bufend = bufdata + bufsize;
for (;;) {
line = memchr(bufdata, '\n', bufend - bufdata);
if (line == NULL)
break;
bufferevent_write(wp->event, bufdata, line - bufdata);
bufferevent_write(wp->event, sepstr, seplen);
bufdata = line + 1;
}
if (bufdata != bufend)
bufferevent_write(wp->event, bufdata, bufend - bufdata);
if (bracket && (wp->screen->mode & MODE_BRACKETPASTE))
bufferevent_write(wp->event, "\033[201~", 6);
} }
/* Delete the buffer if -d. */ if (pb != NULL && args_has(args, 'd'))
if (args_has(args, 'd')) { paste_free(pb);
if (buffer == -1)
paste_free_top(&global_buffers);
else
paste_free_index(&global_buffers, buffer);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
#endif #endif

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -21,6 +21,7 @@
#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>
@ -36,13 +37,16 @@ enum cmd_retval cmd_pipe_pane_exec(struct cmd *, struct cmd_q *);
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", .name = "pipe-pane",
"ot:", 0, 1, .alias = "pipep",
"[-o] " CMD_TARGET_PANE_USAGE " [command]",
0, .args = { "ot:", 0, 1 },
NULL, .usage = "[-o] " CMD_TARGET_PANE_USAGE " [command]",
NULL,
cmd_pipe_pane_exec .tflag = CMD_PANE,
.flags = 0,
.exec = cmd_pipe_pane_exec
}; };
enum cmd_retval enum cmd_retval
@ -52,14 +56,13 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
#else #else
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c = cmdq->state.c;
struct window_pane *wp; struct window_pane *wp = cmdq->state.tflag.wp;
char *command; struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl;
char *cmd;
int old_fd, pipe_fd[2], null_fd; int old_fd, pipe_fd[2], null_fd;
struct format_tree *ft;
if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
return (CMD_RETURN_ERROR);
c = cmd_find_client(cmdq, NULL, 1);
/* Destroy the old pipe. */ /* Destroy the old pipe. */
old_fd = wp->pipe_fd; old_fd = wp->pipe_fd;
@ -88,10 +91,18 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
/* Expand the command. */
ft = format_create(cmdq, 0);
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)); cmdq_error(cmdq, "fork error: %s", strerror(errno));
free(cmd);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
case 0: case 0:
/* Child process. */ /* Child process. */
@ -113,9 +124,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
closefrom(STDERR_FILENO + 1); closefrom(STDERR_FILENO + 1);
command = status_replace( execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
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. */
@ -129,14 +138,16 @@ 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);
free(cmd);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
#endif #endif
} }
void void
cmd_pipe_pane_error_callback( cmd_pipe_pane_error_callback(__unused struct bufferevent *bufev,
unused struct bufferevent *bufev, unused short what, void *data) __unused short what, void *data)
{ {
struct window_pane *wp = data; struct window_pane *wp = data;

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net>
@ -20,11 +20,14 @@
#include <ctype.h> #include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <time.h> #include <time.h>
#include "tmux.h" #include "tmux.h"
#include "tmate.h" #include "tmate.h"
static enum cmd_retval cmdq_continue_one(struct cmd_q *);
/* Create new command queue. */ /* Create new command queue. */
struct cmd_q * struct cmd_q *
cmdq_new(struct client *c) cmdq_new(struct client *c)
@ -33,15 +36,18 @@ cmdq_new(struct client *c)
cmdq = xcalloc(1, sizeof *cmdq); cmdq = xcalloc(1, sizeof *cmdq);
cmdq->references = 1; cmdq->references = 1;
cmdq->dead = 0; cmdq->flags = 0;
cmdq->client = c; cmdq->client = c;
cmdq->client_exit = 0; cmdq->client_exit = -1;
TAILQ_INIT(&cmdq->queue); TAILQ_INIT(&cmdq->queue);
cmdq->item = NULL; cmdq->item = NULL;
cmdq->cmd = NULL; cmdq->cmd = NULL;
cmd_find_clear_state(&cmdq->current, NULL, 0);
cmdq->parent = NULL;
return (cmdq); return (cmdq);
} }
@ -49,8 +55,11 @@ cmdq_new(struct client *c)
int int
cmdq_free(struct cmd_q *cmdq) cmdq_free(struct cmd_q *cmdq)
{ {
if (--cmdq->references != 0) if (--cmdq->references != 0) {
return (cmdq->dead); if (cmdq->flags & CMD_Q_DEAD)
return (1);
return (0);
}
cmdq_flush(cmdq); cmdq_flush(cmdq);
free(cmdq); free(cmdq);
@ -58,24 +67,29 @@ cmdq_free(struct cmd_q *cmdq)
} }
/* Show message from command. */ /* Show message from command. */
void printflike2 void
cmdq_print(struct cmd_q *cmdq, const char *fmt, ...) cmdq_print(struct cmd_q *cmdq, const char *fmt, ...)
{ {
struct client *c = cmdq->client; struct client *c = cmdq->client;
struct window *w; struct window *w;
va_list ap; va_list ap;
char *tmp, *msg;
va_start(ap, fmt); va_start(ap, fmt);
if (c == NULL) if (c == NULL)
/* nothing */; /* nothing */;
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) { else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
va_start(ap, fmt); if (~c->flags & CLIENT_UTF8) {
vasprintf(&tmp, fmt, ap);
msg = utf8_sanitize(tmp);
free(tmp);
evbuffer_add(c->stdout_data, msg, strlen(msg));
free(msg);
} else
evbuffer_add_vprintf(c->stdout_data, fmt, ap); evbuffer_add_vprintf(c->stdout_data, fmt, ap);
va_end(ap);
evbuffer_add(c->stdout_data, "\n", 1); evbuffer_add(c->stdout_data, "\n", 1);
server_push_stdout(c); server_client_push_stdout(c);
} else { } else {
w = c->session->curw->window; w = c->session->curw->window;
if (w->active->mode != &window_copy_mode) { if (w->active->mode != &window_copy_mode) {
@ -89,62 +103,34 @@ cmdq_print(struct cmd_q *cmdq, const char *fmt, ...)
va_end(ap); va_end(ap);
} }
/* Show info from command. */
void printflike2
cmdq_info(struct cmd_q *cmdq, const char *fmt, ...)
{
struct client *c = cmdq->client;
va_list ap;
char *msg;
if (options_get_number(&global_options, "quiet"))
return;
va_start(ap, fmt);
if (c == NULL)
/* nothing */;
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
va_start(ap, fmt);
evbuffer_add_vprintf(c->stdout_data, fmt, ap);
va_end(ap);
evbuffer_add(c->stdout_data, "\n", 1);
server_push_stdout(c);
} else {
xvasprintf(&msg, fmt, ap);
*msg = toupper((u_char) *msg);
status_message_set(c, "%s", msg);
free(msg);
}
va_end(ap);
}
/* Show error from command. */ /* Show error from command. */
void printflike2 void
cmdq_error(struct cmd_q *cmdq, const char *fmt, ...) cmdq_error(struct cmd_q *cmdq, const char *fmt, ...)
{ {
struct client *c = cmdq->client; struct client *c = cmdq->client;
struct cmd *cmd = cmdq->cmd; struct cmd *cmd = cmdq->cmd;
va_list ap; va_list ap;
char *msg, *cause; char *msg;
size_t msglen; size_t msglen;
char *tmp;
va_start(ap, fmt); va_start(ap, fmt);
msglen = xvasprintf(&msg, fmt, ap); msglen = xvasprintf(&msg, fmt, ap);
va_end(ap); va_end(ap);
if (c == NULL) { if (c == NULL)
xasprintf(&cause, "%s:%u: %s", cmd->file, cmd->line, msg); cfg_add_cause("%s:%u: %s", cmd->file, cmd->line, msg);
ARRAY_ADD(&cfg_causes, cause); else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
} else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) { if (~c->flags & CLIENT_UTF8) {
tmp = msg;
msg = utf8_sanitize(tmp);
free(tmp);
msglen = strlen(msg);
}
evbuffer_add(c->stderr_data, msg, msglen); evbuffer_add(c->stderr_data, msg, msglen);
evbuffer_add(c->stderr_data, "\n", 1); evbuffer_add(c->stderr_data, "\n", 1);
server_client_push_stderr(c);
server_push_stderr(c); c->retval = 1;
c->retcode = 1;
} else { } else {
*msg = toupper((u_char) *msg); *msg = toupper((u_char) *msg);
status_message_set(c, "%s", msg); status_message_set(c, "%s", msg);
@ -154,27 +140,24 @@ cmdq_error(struct cmd_q *cmdq, const char *fmt, ...)
} }
/* Print a guard line. */ /* Print a guard line. */
int void
cmdq_guard(struct cmd_q *cmdq, const char *guard) cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags)
{ {
struct client *c = cmdq->client; struct client *c = cmdq->client;
if (c == NULL || c->session == NULL) if (c == NULL || !(c->flags & CLIENT_CONTROL))
return 0; return;
if (!(c->flags & CLIENT_CONTROL))
return 0;
evbuffer_add_printf(c->stdout_data, "%%%s %ld %u\n", guard, evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
(long) cmdq->time, cmdq->number); (long) cmdq->time, cmdq->number, flags);
server_push_stdout(c); server_client_push_stdout(c);
return 1;
} }
/* Add command list to queue and begin processing if needed. */ /* Add command list to queue and begin processing if needed. */
void void
cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist) cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m)
{ {
cmdq_append(cmdq, cmdlist); cmdq_append(cmdq, cmdlist, m);
if (cmdq->item == NULL) { if (cmdq->item == NULL) {
cmdq->cmd = NULL; cmdq->cmd = NULL;
@ -184,7 +167,7 @@ cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist)
/* Add command list to queue. */ /* Add command list to queue. */
void void
cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist) cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m)
{ {
struct cmd_q_item *item; struct cmd_q_item *item;
@ -192,20 +175,70 @@ cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist)
item->cmdlist = cmdlist; item->cmdlist = cmdlist;
TAILQ_INSERT_TAIL(&cmdq->queue, item, qentry); TAILQ_INSERT_TAIL(&cmdq->queue, item, qentry);
cmdlist->references++; cmdlist->references++;
if (m != NULL)
memcpy(&item->mouse, m, sizeof item->mouse);
else
item->mouse.valid = 0;
}
/* Process one command. */
static enum cmd_retval
cmdq_continue_one(struct cmd_q *cmdq)
{
struct cmd *cmd = cmdq->cmd;
enum cmd_retval retval;
char *tmp;
int flags = !!(cmd->flags & CMD_CONTROL);
#ifdef TMATE_SLAVE
int client_id;
#endif
tmp = cmd_print(cmd);
log_debug("cmdq %p: %s", cmdq, tmp);
#ifdef TMATE_SLAVE
if (!tmate_should_exec_cmd_locally(cmd->entry)) {
client_id = cmdq->client ? cmdq->client->id : -1;
tmate_client_cmd(client_id, tmp);
return CMD_RETURN_NORMAL;
}
#endif
free(tmp);
cmdq->time = time(NULL);
cmdq->number++;
cmdq_guard(cmdq, "begin", flags);
if (cmd_prepare_state(cmd, cmdq) != 0)
goto error;
retval = cmd->entry->exec(cmd, cmdq);
if (retval == CMD_RETURN_ERROR)
goto error;
cmdq_guard(cmdq, "end", flags);
return (retval);
error:
cmdq_guard(cmdq, "error", flags);
return (CMD_RETURN_ERROR);
} }
/* Continue processing command queue. Returns 1 if finishes empty. */ /* Continue processing command queue. Returns 1 if finishes empty. */
int int
cmdq_continue(struct cmd_q *cmdq) cmdq_continue(struct cmd_q *cmdq)
{ {
struct client *c = cmdq->client;
struct cmd_q_item *next; struct cmd_q_item *next;
enum cmd_retval retval; enum cmd_retval retval;
int empty, guard; int empty;
char s[1024];
int client_id;
cmdq->references++;
notify_disable(); notify_disable();
log_debug("continuing cmdq %p: flags %#x, client %p", cmdq, cmdq->flags,
c);
empty = TAILQ_EMPTY(&cmdq->queue); empty = TAILQ_EMPTY(&cmdq->queue);
if (empty) if (empty)
goto empty; goto empty;
@ -217,34 +250,8 @@ cmdq_continue(struct cmd_q *cmdq)
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry); cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
do { do {
next = TAILQ_NEXT(cmdq->item, qentry);
while (cmdq->cmd != NULL) { while (cmdq->cmd != NULL) {
cmd_print(cmdq->cmd, s, sizeof s); retval = cmdq_continue_one(cmdq);
log_debug("cmdq %p: %s (client %d)", cmdq, s,
cmdq->client != NULL ? cmdq->client->ibuf.fd : -1);
cmdq->time = time(NULL);
cmdq->number++;
#ifdef TMATE_SLAVE
if (!tmate_should_exec_cmd_locally(cmdq->cmd->entry)) {
client_id = cmdq->client ? cmdq->client->id : -1;
tmate_client_cmd(client_id, s);
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
continue;
}
#endif
guard = cmdq_guard(cmdq, "begin");
retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq);
if (guard) {
if (retval == CMD_RETURN_ERROR)
cmdq_guard(cmdq, "error");
else
cmdq_guard(cmdq, "end");
}
if (retval == CMD_RETURN_ERROR) if (retval == CMD_RETURN_ERROR)
break; break;
if (retval == CMD_RETURN_WAIT) if (retval == CMD_RETURN_WAIT)
@ -253,9 +260,9 @@ cmdq_continue(struct cmd_q *cmdq)
cmdq_flush(cmdq); cmdq_flush(cmdq);
goto empty; goto empty;
} }
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry); cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
} }
next = TAILQ_NEXT(cmdq->item, qentry);
TAILQ_REMOVE(&cmdq->queue, cmdq->item, qentry); TAILQ_REMOVE(&cmdq->queue, cmdq->item, qentry);
cmd_list_free(cmdq->item->cmdlist); cmd_list_free(cmdq->item->cmdlist);
@ -267,14 +274,16 @@ cmdq_continue(struct cmd_q *cmdq)
} while (cmdq->item != NULL); } while (cmdq->item != NULL);
empty: empty:
if (cmdq->client_exit) if (cmdq->client_exit > 0)
cmdq->client->flags |= CLIENT_EXIT; cmdq->client->flags |= CLIENT_EXIT;
if (cmdq->emptyfn != NULL) if (cmdq->emptyfn != NULL)
cmdq->emptyfn(cmdq); /* may free cmdq */ cmdq->emptyfn(cmdq);
empty = 1; empty = 1;
out: out:
notify_enable(); notify_enable();
cmdq_free(cmdq);
return (empty); return (empty);
} }
@ -291,3 +300,4 @@ cmdq_flush(struct cmd_q *cmdq)
} }
cmdq->item = NULL; cmdq->item = NULL;
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -27,26 +27,26 @@
enum cmd_retval cmd_refresh_client_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_refresh_client_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_refresh_client_entry = { const struct cmd_entry cmd_refresh_client_entry = {
"refresh-client", "refresh", .name = "refresh-client",
"C:St:", 0, 0, .alias = "refresh",
"[-S] [-C size]" CMD_TARGET_CLIENT_USAGE,
0, .args = { "C:St:", 0, 0 },
NULL, .usage = "[-S] [-C size] " CMD_TARGET_CLIENT_USAGE,
NULL,
cmd_refresh_client_exec .tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_refresh_client_exec
}; };
enum cmd_retval enum cmd_retval
cmd_refresh_client_exec(struct cmd *self, struct cmd_q *cmdq) cmd_refresh_client_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c = cmdq->state.c;
const char *size; const char *size;
u_int w, h; u_int w, h;
if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (args_has(args, 'C')) { if (args_has(args, 'C')) {
if ((size = args_get(args, 'C')) == NULL) { if ((size = args_get(args, 'C')) == NULL) {
cmdq_error(cmdq, "missing size"); cmdq_error(cmdq, "missing size");
@ -68,10 +68,12 @@ cmd_refresh_client_exec(struct cmd *self, struct cmd_q *cmdq)
if (tty_set_size(&c->tty, w, h)) if (tty_set_size(&c->tty, w, h))
recalculate_sizes(); recalculate_sizes();
} else if (args_has(args, 'S')) { } else if (args_has(args, 'S')) {
status_update_jobs(c); c->flags |= CLIENT_STATUSFORCE;
server_status_client(c); server_status_client(c);
} else } else {
c->flags |= CLIENT_STATUSFORCE;
server_redraw_client(c); server_redraw_client(c);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -29,20 +29,23 @@
enum cmd_retval cmd_rename_session_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_rename_session_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_rename_session_entry = { const struct cmd_entry cmd_rename_session_entry = {
"rename-session", "rename", .name = "rename-session",
"t:", 1, 1, .alias = "rename",
CMD_TARGET_SESSION_USAGE " new-name",
0, .args = { "t:", 1, 1 },
NULL, .usage = CMD_TARGET_SESSION_USAGE " new-name",
NULL,
cmd_rename_session_exec .tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_rename_session_exec
}; };
enum cmd_retval enum cmd_retval
cmd_rename_session_exec(struct cmd *self, struct cmd_q *cmdq) cmd_rename_session_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s = cmdq->state.tflag.s;
const char *newname; const char *newname;
newname = args->argv[0]; newname = args->argv[0];
@ -55,9 +58,6 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
RB_REMOVE(sessions, &sessions, s); RB_REMOVE(sessions, &sessions, s);
free(s->name); free(s->name);
s->name = xstrdup(newname); s->name = xstrdup(newname);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -29,27 +29,26 @@
enum cmd_retval cmd_rename_window_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_rename_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_rename_window_entry = { const struct cmd_entry cmd_rename_window_entry = {
"rename-window", "renamew", .name = "rename-window",
"t:", 1, 1, .alias = "renamew",
CMD_TARGET_WINDOW_USAGE " new-name",
0, .args = { "t:", 1, 1 },
NULL, .usage = CMD_TARGET_WINDOW_USAGE " new-name",
NULL,
cmd_rename_window_exec .tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_rename_window_exec
}; };
enum cmd_retval enum cmd_retval
cmd_rename_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_rename_window_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct winlink *wl = cmdq->state.tflag.wl;
struct winlink *wl;
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL)
return (CMD_RETURN_ERROR);
window_set_name(wl->window, args->argv[0]); window_set_name(wl->window, args->argv[0]);
options_set_number(&wl->window->options, "automatic-rename", 0); options_set_number(wl->window->options, "automatic-rename", 0);
server_status_window(wl->window); server_status_window(wl->window);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -26,64 +26,23 @@
* Increase or decrease pane size. * Increase or decrease pane size.
*/ */
void cmd_resize_pane_key_binding(struct cmd *, int);
enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_resize_pane_entry = { void cmd_resize_pane_mouse_update(struct client *, struct mouse_event *);
"resize-pane", "resizep",
"DLRt:Ux:y:Z", 0, 1,
"[-DLRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " [adjustment]",
0,
cmd_resize_pane_key_binding,
NULL,
cmd_resize_pane_exec
};
void const struct cmd_entry cmd_resize_pane_entry = {
cmd_resize_pane_key_binding(struct cmd *self, int key) .name = "resize-pane",
{ .alias = "resizep",
switch (key) {
case KEYC_UP | KEYC_CTRL: .args = { "DLMRt:Ux:y:Z", 0, 1 },
self->args = args_create(0); .usage = "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
args_set(self->args, 'U', NULL); "[adjustment]",
break;
case KEYC_DOWN | KEYC_CTRL: .tflag = CMD_PANE,
self->args = args_create(0);
args_set(self->args, 'D', NULL); .flags = 0,
break; .exec = cmd_resize_pane_exec
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;
case 'z':
self->args = args_create(0);
args_set(self->args, 'Z', NULL);
break;
default:
self->args = args_create(0);
break;
}
}
enum cmd_retval enum cmd_retval
cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq)
@ -92,18 +51,27 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
#else #else
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct window_pane *wp = cmdq->state.tflag.wp;
struct window *w; struct winlink *wl = cmdq->state.tflag.wl;
struct window *w = wl->window;
struct client *c = cmdq->client;
struct session *s = cmdq->state.tflag.s;
const char *errstr; const char *errstr;
char *cause; char *cause;
struct window_pane *wp;
u_int adjust; u_int adjust;
int x, y; int x, y;
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL) if (args_has(args, 'M')) {
return (CMD_RETURN_ERROR); if (cmd_mouse_window(&cmdq->item->mouse, &s) == NULL)
w = wl->window; return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update;
cmd_resize_pane_mouse_update(c, &cmdq->item->mouse);
return (CMD_RETURN_NORMAL);
}
w = wl->window;
if (args_has(args, 'Z')) { if (args_has(args, 'Z')) {
if (w->flags & WINDOW_ZOOMED) if (w->flags & WINDOW_ZOOMED)
window_unzoom(w); window_unzoom(w);
@ -159,3 +127,50 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
#endif #endif
} }
void
cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m)
{
struct winlink *wl;
struct window_pane *wp;
int found;
u_int y, ly;
wl = cmd_mouse_window(m, NULL);
if (wl == NULL) {
c->tty.mouse_drag_update = NULL;
return;
}
y = m->y;
if (m->statusat == 0 && y > 0)
y--;
else if (m->statusat > 0 && y >= (u_int)m->statusat)
y = m->statusat - 1;
ly = m->ly;
if (m->statusat == 0 && ly > 0)
ly--;
else if (m->statusat > 0 && ly >= (u_int)m->statusat)
ly = m->statusat - 1;
found = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
if (!window_pane_visible(wp))
continue;
if (wp->xoff + wp->sx == m->lx &&
wp->yoff <= 1 + ly && wp->yoff + wp->sy >= ly) {
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, m->x - m->lx);
found = 1;
}
if (wp->yoff + wp->sy == ly &&
wp->xoff <= 1 + m->lx && wp->xoff + wp->sx >= m->lx) {
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, y - ly);
found = 1;
}
}
if (found)
server_redraw_window(wl->window);
else
c->tty.mouse_drag_update = NULL;
}

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -31,13 +31,16 @@
enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_respawn_pane_entry = { const struct cmd_entry cmd_respawn_pane_entry = {
"respawn-pane", "respawnp", .name = "respawn-pane",
"kt:", 0, 1, .alias = "respawnp",
"[-k] " CMD_TARGET_PANE_USAGE " [command]",
0, .args = { "kt:", 0, -1 },
NULL, .usage = "[-k] " CMD_TARGET_PANE_USAGE " [command]",
NULL,
cmd_respawn_pane_exec .tflag = CMD_PANE,
.flags = 0,
.exec = cmd_respawn_pane_exec
}; };
enum cmd_retval enum cmd_retval
@ -47,50 +50,52 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
#else #else
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl = cmdq->state.tflag.wl;
struct window *w; struct window *w = wl->window;
struct window_pane *wp; struct window_pane *wp = cmdq->state.tflag.wp;
struct session *s; struct session *s = cmdq->state.tflag.s;
struct environ env; struct environ *env;
const char *cmd; const char *path;
char *cause; char *cause;
u_int idx; u_int idx;
struct environ_entry *envent;
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL)
return (CMD_RETURN_ERROR);
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) if (window_pane_index(wp, &idx) != 0)
fatalx("index not found"); fatalx("index not found");
cmdq_error(cmdq, "pane still active: %s:%u.%u", cmdq_error(cmdq, "pane still active: %s:%d.%u",
s->name, wl->idx, idx); s->name, wl->idx, idx);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
environ_init(&env); env = environ_create();
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);
window_pane_reset_mode(wp); window_pane_reset_mode(wp);
screen_reinit(&wp->base); screen_reinit(&wp->base);
input_init(wp); input_init(wp);
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
cmd = NULL; envent = environ_find(s->environ, "PATH");
if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) { if (envent != NULL)
path = envent->value;
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env,
s->tio, &cause) != 0) {
cmdq_error(cmdq, "respawn pane failed: %s", cause); cmdq_error(cmdq, "respawn pane failed: %s", cause);
free(cause); free(cause);
environ_free(&env); environ_free(env);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
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 (CMD_RETURN_NORMAL);
#endif #endif
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -30,13 +30,16 @@
enum cmd_retval cmd_respawn_window_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_respawn_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_respawn_window_entry = { const struct cmd_entry cmd_respawn_window_entry = {
"respawn-window", "respawnw", .name = "respawn-window",
"kt:", 0, 1, .alias = "respawnw",
"[-k] " CMD_TARGET_WINDOW_USAGE " [command]",
0, .args = { "kt:", 0, -1 },
NULL, .usage = "[-k] " CMD_TARGET_WINDOW_USAGE " [command]",
NULL,
cmd_respawn_window_exec .tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_respawn_window_exec
}; };
enum cmd_retval enum cmd_retval
@ -46,32 +49,29 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
#else #else
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct session *s = cmdq->state.tflag.s;
struct window *w; struct winlink *wl = cmdq->state.tflag.wl;
struct window *w = wl->window;
struct window_pane *wp; struct window_pane *wp;
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)
return (CMD_RETURN_ERROR);
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, cmdq_error(cmdq, "window still active: %s:%d", s->name,
"window still active: %s:%d", s->name, wl->idx); wl->idx);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
environ_init(&env); env = environ_create();
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);
wp = TAILQ_FIRST(&w->panes); wp = TAILQ_FIRST(&w->panes);
TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_REMOVE(&w->panes, wp, entry);
@ -79,15 +79,21 @@ 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)
cmd = args->argv[0]; path = NULL;
if (cmdq->client != NULL && cmdq->client->session == NULL)
envent = environ_find(cmdq->client->environ, "PATH");
else else
cmd = NULL; envent = environ_find(s->environ, "PATH");
if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) { if (envent != NULL)
path = envent->value;
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env,
s->tio, &cause) != 0) {
cmdq_error(cmdq, "respawn window failed: %s", cause); cmdq_error(cmdq, "respawn window failed: %s", cause);
free(cause); free(cause);
environ_free(&env); environ_free(env);
server_destroy_pane(wp); server_destroy_pane(wp, 0);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
layout_init(w, wp); layout_init(w, wp);
@ -99,7 +105,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
recalculate_sizes(); recalculate_sizes();
server_redraw_window(w); server_redraw_window(w);
environ_free(&env); environ_free(env);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
#endif #endif
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -24,26 +24,20 @@
* Rotate the panes in a window. * Rotate the panes in a window.
*/ */
void cmd_rotate_window_key_binding(struct cmd *, int);
enum cmd_retval cmd_rotate_window_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_rotate_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_rotate_window_entry = { const struct cmd_entry cmd_rotate_window_entry = {
"rotate-window", "rotatew", .name = "rotate-window",
"Dt:U", 0, 0, .alias = "rotatew",
"[-DU] " CMD_TARGET_WINDOW_USAGE,
0,
cmd_rotate_window_key_binding,
NULL,
cmd_rotate_window_exec
};
void .args = { "Dt:U", 0, 0 },
cmd_rotate_window_key_binding(struct cmd *self, int key) .usage = "[-DU] " CMD_TARGET_WINDOW_USAGE,
{
self->args = args_create(0); .tflag = CMD_WINDOW,
if (key == ('o' | KEYC_ESCAPE))
args_set(self->args, 'D', NULL); .flags = 0,
} .exec = cmd_rotate_window_exec
};
enum cmd_retval enum cmd_retval
cmd_rotate_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_rotate_window_exec(struct cmd *self, struct cmd_q *cmdq)
@ -51,17 +45,12 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_q *cmdq)
#ifdef TMATE_SLAVE #ifdef TMATE_SLAVE
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
#else #else
struct args *args = self->args; struct winlink *wl = cmdq->state.tflag.wl;
struct winlink *wl; struct window *w = wl->window;
struct window *w;
struct window_pane *wp, *wp2; struct window_pane *wp, *wp2;
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)
return (CMD_RETURN_ERROR);
w = wl->window;
if (args_has(self->args, 'D')) { if (args_has(self->args, 'D')) {
wp = TAILQ_LAST(&w->panes, window_panes); wp = TAILQ_LAST(&w->panes, window_panes);
TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_REMOVE(&w->panes, wp, entry);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@ -36,13 +36,16 @@ void cmd_run_shell_free(void *);
void cmd_run_shell_print(struct job *, const char *); 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", .name = "run-shell",
"bt:", 1, 1, .alias = "run",
"[-b] " CMD_TARGET_PANE_USAGE " shell-command",
0, .args = { "bt:", 1, 1 },
NULL, .usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
NULL,
cmd_run_shell_exec .tflag = CMD_PANE_CANFAIL,
.flags = 0,
.exec = cmd_run_shell_exec
}; };
struct cmd_run_shell_data { struct cmd_run_shell_data {
@ -77,30 +80,20 @@ 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; char *shellcmd;
struct client *c; struct session *s = cmdq->state.tflag.s;
struct session *s = NULL; struct winlink *wl = cmdq->state.tflag.wl;
struct winlink *wl = NULL; struct window_pane *wp = cmdq->state.tflag.wp;
struct window_pane *wp = NULL;
struct format_tree *ft; struct format_tree *ft;
const char *cwd;
if (args_has(args, 't')) if (cmdq->client != NULL && cmdq->client->session == NULL)
wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); cwd = cmdq->client->cwd;
else { else if (s != NULL)
c = cmd_find_client(cmdq, NULL, 1); cwd = s->cwd;
if (c != NULL && c->session != NULL) { else
s = c->session; cwd = NULL;
wl = s->curw; ft = format_create(cmdq, 0);
wp = wl->window->active; format_defaults(ft, NULL, s, wl, wp);
}
}
ft = format_create();
if (s != NULL)
format_session(ft, s);
if (s != NULL && wl != NULL)
format_winlink(ft, s, wl);
if (wp != NULL)
format_window_pane(ft, wp);
shellcmd = format_expand(ft, args->argv[0]); shellcmd = format_expand(ft, args->argv[0]);
format_free(ft); format_free(ft);
@ -112,7 +105,8 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq)
cdata->cmdq = cmdq; cdata->cmdq = cmdq;
cmdq->references++; cmdq->references++;
job_run(shellcmd, s, cmd_run_shell_callback, cmd_run_shell_free, cdata); job_run(shellcmd, s, cwd, cmd_run_shell_callback, cmd_run_shell_free,
cdata);
if (cdata->bflag) if (cdata->bflag)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@ -129,7 +123,7 @@ cmd_run_shell_callback(struct job *job)
int retcode; int retcode;
u_int lines; u_int lines;
if (cmdq->dead) if (cmdq->flags & CMD_Q_DEAD)
return; return;
cmd = cdata->cmd; cmd = cdata->cmd;
@ -162,14 +156,10 @@ 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)
if (lines == 0)
cmdq_info(cmdq, "%s", msg);
else
cmd_run_shell_print(job, msg); cmd_run_shell_print(job, msg);
free(msg); free(msg);
} }
}
void void
cmd_run_shell_free(void *data) cmd_run_shell_free(void *data)

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@ -20,8 +20,10 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
@ -32,67 +34,60 @@
enum cmd_retval cmd_save_buffer_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_save_buffer_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_save_buffer_entry = { const struct cmd_entry cmd_save_buffer_entry = {
"save-buffer", "saveb", .name = "save-buffer",
"ab:", 1, 1, .alias = "saveb",
"[-a] " CMD_BUFFER_USAGE " path",
0, .args = { "ab:", 1, 1 },
NULL, .usage = "[-a] " CMD_BUFFER_USAGE " path",
NULL,
cmd_save_buffer_exec .flags = 0,
.exec = cmd_save_buffer_exec
}; };
const struct cmd_entry cmd_show_buffer_entry = { const struct cmd_entry cmd_show_buffer_entry = {
"show-buffer", "showb", .name = "show-buffer",
"b:", 0, 0, .alias = "showb",
CMD_BUFFER_USAGE,
0, .args = { "b:", 0, 0 },
NULL, .usage = CMD_BUFFER_USAGE,
NULL,
cmd_save_buffer_exec .flags = 0,
.exec = cmd_save_buffer_exec
}; };
enum cmd_retval enum cmd_retval
cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq) cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c = cmdq->client;
struct session *s; struct session *s;
struct paste_buffer *pb; struct paste_buffer *pb;
const char *path, *newpath, *wd; const char *path, *bufname, *bufdata, *start, *end, *cwd;
char *cause, *start, *end; const char *flags;
size_t size, used; char *msg, *file, resolved[PATH_MAX];
int buffer; size_t size, used, msglen, bufsize;
mode_t mask;
FILE *f; FILE *f;
char *msg;
size_t msglen;
if (!args_has(args, 'b')) { if (!args_has(args, 'b')) {
if ((pb = paste_get_top(&global_buffers)) == NULL) { if ((pb = paste_get_top(NULL)) == NULL) {
cmdq_error(cmdq, "no buffers"); cmdq_error(cmdq, "no buffers");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else { } else {
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); bufname = args_get(args, 'b');
if (cause != NULL) { pb = paste_get_name(bufname);
cmdq_error(cmdq, "buffer %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
pb = paste_get_index(&global_buffers, buffer);
if (pb == NULL) { if (pb == NULL) {
cmdq_error(cmdq, "no buffer %d", buffer); cmdq_error(cmdq, "no buffer %s", bufname);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
bufdata = paste_buffer_data(pb, &bufsize);
if (self->entry == &cmd_show_buffer_entry) if (self->entry == &cmd_show_buffer_entry)
path = "-"; path = "-";
else else
path = args->argv[0]; path = args->argv[0];
if (strcmp(path, "-") == 0) { if (strcmp(path, "-") == 0) {
c = cmdq->client;
if (c == NULL) { if (c == NULL) {
cmdq_error(cmdq, "can't write to stdout"); cmdq_error(cmdq, "can't write to stdout");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@ -102,33 +97,35 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
goto do_print; goto do_print;
} }
c = cmdq->client; if (c != NULL && c->session == NULL)
if (c != NULL) cwd = c->cwd;
wd = c->cwd; else if ((s = c->session) != NULL)
else if ((s = cmd_current_session(cmdq, 0)) != NULL) { cwd = s->cwd;
wd = options_get_string(&s->options, "default-path");
if (*wd == '\0')
wd = s->cwd;
} else
wd = NULL;
if (wd != NULL && *wd != '\0') {
newpath = get_full_path(wd, path);
if (newpath != NULL)
path = newpath;
}
mask = umask(S_IRWXG | S_IRWXO);
if (args_has(self->args, 'a'))
f = fopen(path, "ab");
else else
f = fopen(path, "wb"); cwd = ".";
umask(mask);
if (f == NULL) { flags = "wb";
cmdq_error(cmdq, "%s: %s", path, strerror(errno)); if (args_has(self->args, 'a'))
flags = "ab";
if (*path == '/')
file = xstrdup(path);
else
xasprintf(&file, "%s/%s", cwd, path);
if (realpath(file, resolved) == NULL &&
strlcpy(resolved, file, sizeof resolved) >= sizeof resolved) {
cmdq_error(cmdq, "%s: %s", file, strerror(ENAMETOOLONG));
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (fwrite(pb->data, 1, pb->size, f) != pb->size) { f = fopen(resolved, flags);
cmdq_error(cmdq, "%s: fwrite error", path); free(file);
if (f == NULL) {
cmdq_error(cmdq, "%s: %s", resolved, strerror(errno));
return (CMD_RETURN_ERROR);
}
if (fwrite(bufdata, 1, bufsize, f) != bufsize) {
cmdq_error(cmdq, "%s: write error", resolved);
fclose(f); fclose(f);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@ -137,29 +134,28 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
do_stdout: do_stdout:
evbuffer_add(c->stdout_data, pb->data, pb->size); evbuffer_add(c->stdout_data, bufdata, bufsize);
server_push_stdout(c); server_client_push_stdout(c);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
do_print: do_print:
if (pb->size > (INT_MAX / 4) - 1) { if (bufsize > (INT_MAX / 4) - 1) {
cmdq_error(cmdq, "buffer too big"); cmdq_error(cmdq, "buffer too big");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
msg = NULL; msg = NULL;
msglen = 0;
used = 0; used = 0;
while (used != pb->size) { while (used != bufsize) {
start = pb->data + used; start = bufdata + used;
end = memchr(start, '\n', pb->size - used); end = memchr(start, '\n', bufsize - used);
if (end != NULL) if (end != NULL)
size = end - start; size = end - start;
else else
size = pb->size - used; size = bufsize - used;
msglen = size * 4 + 1; msglen = size * 4 + 1;
msg = xrealloc(msg, 1, msglen); msg = xrealloc(msg, msglen);
strvisx(msg, start, size, VIS_OCTAL|VIS_TAB); strvisx(msg, start, size, VIS_OCTAL|VIS_TAB);
cmdq_print(cmdq, "%s", msg); cmdq_print(cmdq, "%s", msg);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -18,69 +18,54 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Switch window to selected layout. * Switch window to selected layout.
*/ */
void cmd_select_layout_key_binding(struct cmd *, int);
enum cmd_retval cmd_select_layout_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_select_layout_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_select_layout_entry = { const struct cmd_entry cmd_select_layout_entry = {
"select-layout", "selectl", .name = "select-layout",
"npt:", 0, 1, .alias = "selectl",
"[-np] " CMD_TARGET_WINDOW_USAGE " [layout-name]",
0, .args = { "nopt:", 0, 1 },
cmd_select_layout_key_binding, .usage = "[-nop] " CMD_TARGET_WINDOW_USAGE " [layout-name]",
NULL,
cmd_select_layout_exec .tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_select_layout_exec
}; };
const struct cmd_entry cmd_next_layout_entry = { const struct cmd_entry cmd_next_layout_entry = {
"next-layout", "nextl", .name = "next-layout",
"t:", 0, 0, .alias = "nextl",
CMD_TARGET_WINDOW_USAGE,
0, .args = { "t:", 0, 0 },
NULL, .usage = CMD_TARGET_WINDOW_USAGE,
NULL,
cmd_select_layout_exec .tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_select_layout_exec
}; };
const struct cmd_entry cmd_previous_layout_entry = { const struct cmd_entry cmd_previous_layout_entry = {
"previous-layout", "prevl", .name = "previous-layout",
"t:", 0, 0, .alias = "prevl",
CMD_TARGET_WINDOW_USAGE,
0,
NULL,
NULL,
cmd_select_layout_exec
};
void .args = { "t:", 0, 0 },
cmd_select_layout_key_binding(struct cmd *self, int key) .usage = CMD_TARGET_WINDOW_USAGE,
{
switch (key) { .tflag = CMD_WINDOW,
case '1' | KEYC_ESCAPE:
self->args = args_create(1, "even-horizontal"); .flags = 0,
break; .exec = cmd_select_layout_exec
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;
}
}
enum cmd_retval enum cmd_retval
cmd_select_layout_exec(struct cmd *self, struct cmd_q *cmdq) cmd_select_layout_exec(struct cmd *self, struct cmd_q *cmdq)
@ -89,51 +74,70 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
#else #else
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl = cmdq->state.tflag.wl;
struct window *w;
const char *layoutname; const char *layoutname;
char *oldlayout;
int next, previous, layout; int next, previous, layout;
if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) w = wl->window;
return (CMD_RETURN_ERROR); server_unzoom_window(w);
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(args, 'n'))
next = 1; next = 1;
previous = self->entry == &cmd_previous_layout_entry; previous = self->entry == &cmd_previous_layout_entry;
if (args_has(self->args, 'p')) if (args_has(args, 'p'))
previous = 1; previous = 1;
oldlayout = w->old_layout;
w->old_layout = layout_dump(w->layout_root);
if (next || previous) { if (next || previous) {
if (next) if (next)
layout = layout_set_next(wl->window); layout_set_next(w);
else else
layout = layout_set_previous(wl->window); layout_set_previous(w);
server_redraw_window(wl->window); goto changed;
cmdq_info(cmdq, "arranging in: %s", layout_set_name(layout));
return (CMD_RETURN_NORMAL);
} }
if (!args_has(args, 'o')) {
if (args->argc == 0) if (args->argc == 0)
layout = wl->window->lastlayout; layout = w->lastlayout;
else else
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_set_select(w, layout);
server_redraw_window(wl->window); goto changed;
cmdq_info(cmdq, "arranging in: %s", layout_set_name(layout)); }
return (CMD_RETURN_NORMAL);
} }
if (args->argc != 0) { if (args->argc != 0)
layoutname = args->argv[0]; layoutname = args->argv[0];
if (layout_parse(wl->window, layoutname) == -1) { else if (args_has(args, 'o'))
layoutname = oldlayout;
else
layoutname = NULL;
if (layoutname != NULL) {
if (layout_parse(w, layoutname) == -1) {
cmdq_error(cmdq, "can't set layout: %s", layoutname); cmdq_error(cmdq, "can't set layout: %s", layoutname);
return (CMD_RETURN_ERROR); goto error;
} }
server_redraw_window(wl->window); goto changed;
cmdq_info(cmdq, "arranging in: %s", layoutname);
} }
free(oldlayout);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
changed:
free(oldlayout);
server_redraw_window(w);
return (CMD_RETURN_NORMAL);
error:
free(w->old_layout);
w->old_layout = oldlayout;
return (CMD_RETURN_ERROR);
#endif #endif
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -24,95 +24,147 @@
* Select pane. * Select pane.
*/ */
void cmd_select_pane_key_binding(struct cmd *, int);
enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_select_pane_entry = { const struct cmd_entry cmd_select_pane_entry = {
"select-pane", "selectp", .name = "select-pane",
"lDLRt:U", 0, 0, .alias = "selectp",
"[-lDLRU] " CMD_TARGET_PANE_USAGE,
0, .args = { "DdegLlMmP:Rt:U", 0, 0 },
cmd_select_pane_key_binding, .usage = "[-DdegLlMmRU] [-P style] " CMD_TARGET_PANE_USAGE,
NULL,
cmd_select_pane_exec .tflag = CMD_PANE,
.flags = 0,
.exec = cmd_select_pane_exec
}; };
const struct cmd_entry cmd_last_pane_entry = { const struct cmd_entry cmd_last_pane_entry = {
"last-pane", "lastp", .name = "last-pane",
"t:", 0, 0, .alias = "lastp",
CMD_TARGET_WINDOW_USAGE,
0,
NULL,
NULL,
cmd_select_pane_exec
};
void .args = { "det:", 0, 0 },
cmd_select_pane_key_binding(struct cmd *self, int key) .usage = "[-de] " CMD_TARGET_WINDOW_USAGE,
{
self->args = args_create(0); .tflag = CMD_WINDOW,
if (key == KEYC_UP)
args_set(self->args, 'U', NULL); .flags = 0,
if (key == KEYC_DOWN) .exec = cmd_select_pane_exec
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', ":.+");
}
enum cmd_retval enum cmd_retval
cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl = cmdq->state.tflag.wl;
struct window_pane *wp; struct window *w = wl->window;
struct session *s = cmdq->state.tflag.s;
struct window_pane *wp = cmdq->state.tflag.wp, *lastwp, *markedwp;
const char *style;
if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) { if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
wl = cmd_find_window(cmdq, args_get(args, 't'), NULL);
if (wl == NULL)
return (CMD_RETURN_ERROR);
if (wl->window->last == NULL) { if (wl->window->last == NULL) {
cmdq_error(cmdq, "no last pane"); cmdq_error(cmdq, "no last pane");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
server_unzoom_window(wl->window); if (args_has(self->args, 'e'))
window_set_active_pane(wl->window, wl->window->last); w->last->flags &= ~PANE_INPUTOFF;
server_status_window(wl->window); else if (args_has(self->args, 'd'))
server_redraw_window_borders(wl->window); w->last->flags |= PANE_INPUTOFF;
else {
server_unzoom_window(w);
window_redraw_active_switch(w, w->last);
if (window_set_active_pane(w, w->last)) {
server_status_window(w);
server_redraw_window_borders(w);
}
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL)
return (CMD_RETURN_ERROR);
server_unzoom_window(wp->window); server_unzoom_window(wp->window);
if (!window_pane_visible(wp)) { if (!window_pane_visible(wp)) {
cmdq_error(cmdq, "pane not visible"); cmdq_error(cmdq, "pane not visible");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(self->args, 'L')) if (args_has(args, 'm') || args_has(args, 'M')) {
wp = window_pane_find_left(wp); if (args_has(args, 'm') && !window_pane_visible(wp))
else if (args_has(self->args, 'R')) return (CMD_RETURN_NORMAL);
wp = window_pane_find_right(wp); lastwp = marked_pane.wp;
else if (args_has(self->args, 'U'))
wp = window_pane_find_up(wp); if (args_has(args, 'M') || server_is_marked(s, wl, wp))
else if (args_has(self->args, 'D')) server_clear_marked();
wp = window_pane_find_down(wp); else
if (wp == NULL) { server_set_marked(s, wl, wp);
cmdq_error(cmdq, "pane not found"); markedwp = marked_pane.wp;
return (CMD_RETURN_ERROR);
if (lastwp != NULL) {
server_redraw_window_borders(lastwp->window);
server_status_window(lastwp->window);
}
if (markedwp != NULL) {
server_redraw_window_borders(markedwp->window);
server_status_window(markedwp->window);
}
return (CMD_RETURN_NORMAL);
} }
window_set_active_pane(wl->window, wp); if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
server_status_window(wl->window); if (args_has(args, 'P')) {
server_redraw_window_borders(wl->window); style = args_get(args, 'P');
if (style_parse(&grid_default_cell, &wp->colgc,
style) == -1) {
cmdq_error(cmdq, "bad style: %s", style);
return (CMD_RETURN_ERROR);
}
wp->flags |= PANE_REDRAW;
}
if (args_has(self->args, 'g'))
cmdq_print(cmdq, "%s", style_tostring(&wp->colgc));
return (CMD_RETURN_NORMAL);
}
if (args_has(self->args, 'L')) {
server_unzoom_window(wp->window);
wp = window_pane_find_left(wp);
} else if (args_has(self->args, 'R')) {
server_unzoom_window(wp->window);
wp = window_pane_find_right(wp);
} else if (args_has(self->args, 'U')) {
server_unzoom_window(wp->window);
wp = window_pane_find_up(wp);
} else if (args_has(self->args, 'D')) {
server_unzoom_window(wp->window);
wp = window_pane_find_down(wp);
}
if (wp == NULL)
return (CMD_RETURN_NORMAL);
if (args_has(self->args, 'e')) {
wp->flags &= ~PANE_INPUTOFF;
return (CMD_RETURN_NORMAL);
}
if (args_has(self->args, 'd')) {
wp->flags |= PANE_INPUTOFF;
return (CMD_RETURN_NORMAL);
}
if (wp == w->active)
return (CMD_RETURN_NORMAL);
server_unzoom_window(wp->window);
if (!window_pane_visible(wp)) {
cmdq_error(cmdq, "pane not visible");
return (CMD_RETURN_ERROR);
}
window_redraw_active_switch(w, wp);
if (window_set_active_pane(w, wp)) {
server_status_window(w);
server_redraw_window_borders(w);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -26,69 +26,65 @@
* Select window by index. * Select window by index.
*/ */
void cmd_select_window_key_binding(struct cmd *, int);
enum cmd_retval cmd_select_window_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_select_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_select_window_entry = { const struct cmd_entry cmd_select_window_entry = {
"select-window", "selectw", .name = "select-window",
"lnpTt:", 0, 0, .alias = "selectw",
"[-lnpT] " CMD_TARGET_WINDOW_USAGE,
0, .args = { "lnpTt:", 0, 0 },
cmd_select_window_key_binding, .usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE,
NULL,
cmd_select_window_exec .tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_select_window_exec
}; };
const struct cmd_entry cmd_next_window_entry = { const struct cmd_entry cmd_next_window_entry = {
"next-window", "next", .name = "next-window",
"at:", 0, 0, .alias = "next",
"[-a] " CMD_TARGET_SESSION_USAGE,
0, .args = { "at:", 0, 0 },
cmd_select_window_key_binding, .usage = "[-a] " CMD_TARGET_SESSION_USAGE,
NULL,
cmd_select_window_exec .tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_select_window_exec
}; };
const struct cmd_entry cmd_previous_window_entry = { const struct cmd_entry cmd_previous_window_entry = {
"previous-window", "prev", .name = "previous-window",
"at:", 0, 0, .alias = "prev",
"[-a] " CMD_TARGET_SESSION_USAGE,
0, .args = { "at:", 0, 0 },
cmd_select_window_key_binding, .usage = "[-a] " CMD_TARGET_SESSION_USAGE,
NULL,
cmd_select_window_exec .tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_select_window_exec
}; };
const struct cmd_entry cmd_last_window_entry = { const struct cmd_entry cmd_last_window_entry = {
"last-window", "last", .name = "last-window",
"t:", 0, 0, .alias = "last",
CMD_TARGET_SESSION_USAGE,
0, .args = { "t:", 0, 0 },
NULL, .usage = CMD_TARGET_SESSION_USAGE,
NULL,
cmd_select_window_exec .tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_select_window_exec
}; };
void
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);
}
enum cmd_retval enum cmd_retval
cmd_select_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_select_window_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct winlink *wl = cmdq->state.tflag.wl;
struct winlink *wl; struct session *s = cmdq->state.tflag.s;
struct session *s;
int next, previous, last, activity; int next, previous, last, activity;
next = self->entry == &cmd_next_window_entry; next = self->entry == &cmd_next_window_entry;
@ -102,10 +98,6 @@ 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);
if (s == NULL)
return (CMD_RETURN_ERROR);
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) {
@ -126,10 +118,6 @@ cmd_select_window_exec(struct cmd *self, struct cmd_q *cmdq)
server_redraw_session(s); server_redraw_session(s);
} else { } else {
wl = cmd_find_window(cmdq, args_get(args, 't'), &s);
if (wl == NULL)
return (CMD_RETURN_ERROR);
/* /*
* If -T and select-window is invoked on same window as * If -T and select-window is invoked on same window as
* current, switch to previous window. * current, switch to previous window.

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -30,23 +30,29 @@
enum cmd_retval cmd_send_keys_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_send_keys_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_send_keys_entry = { const struct cmd_entry cmd_send_keys_entry = {
"send-keys", "send", .name = "send-keys",
"lRt:", 0, -1, .alias = "send",
"[-lR] " CMD_TARGET_PANE_USAGE " key ...",
0, .args = { "lRMt:", 0, -1 },
NULL, .usage = "[-lRM] " CMD_TARGET_PANE_USAGE " key ...",
NULL,
cmd_send_keys_exec .tflag = CMD_PANE,
.flags = 0,
.exec = cmd_send_keys_exec
}; };
const struct cmd_entry cmd_send_prefix_entry = { const struct cmd_entry cmd_send_prefix_entry = {
"send-prefix", NULL, .name = "send-prefix",
"2t:", 0, 0, .alias = NULL,
"[-2] " CMD_TARGET_PANE_USAGE,
0, .args = { "2t:", 0, 0 },
NULL, .usage = "[-2] " CMD_TARGET_PANE_USAGE,
NULL,
cmd_send_keys_exec .tflag = CMD_PANE,
.flags = 0,
.exec = cmd_send_keys_exec
}; };
enum cmd_retval enum cmd_retval
@ -56,49 +62,47 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
#else #else
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp; struct window_pane *wp = cmdq->state.tflag.wp;
struct session *s; struct session *s = cmdq->state.tflag.s;
struct input_ctx *ictx; struct mouse_event *m = &cmdq->item->mouse;
const char *str; const u_char *keystr;
int i, key; int i, literal;
key_code key;
if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL) if (args_has(args, 'M')) {
wp = cmd_mouse_pane(m, &s, NULL);
if (wp == NULL) {
cmdq_error(cmdq, "no mouse target");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
}
if (self->entry == &cmd_send_prefix_entry) { window_pane_key(wp, NULL, s, m->key, m);
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); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'R')) { if (self->entry == &cmd_send_prefix_entry) {
ictx = &wp->ictx; if (args_has(args, '2'))
key = options_get_number(s->options, "prefix2");
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 else
screen_write_start(&ictx->ctx, NULL, &wp->base); key = options_get_number(s->options, "prefix");
screen_write_reset(&ictx->ctx); window_pane_key(wp, NULL, s, key, NULL);
screen_write_stop(&ictx->ctx); return (CMD_RETURN_NORMAL);
} }
for (i = 0; i < args->argc; i++) { if (args_has(args, 'R'))
str = args->argv[i]; input_reset(wp, 1);
if (!args_has(args, 'l') && for (i = 0; i < args->argc; i++) {
(key = key_string_lookup_string(str)) != KEYC_NONE) { literal = args_has(args, 'l');
window_pane_key(wp, s, key); if (!literal) {
} else { key = key_string_lookup_string(args->argv[i]);
for (; *str != '\0'; str++) if (key != KEYC_NONE && key != KEYC_UNKNOWN)
window_pane_key(wp, s, *str); window_pane_key(wp, NULL, s, key, NULL);
else
literal = 1;
}
if (literal) {
for (keystr = args->argv[i]; *keystr != '\0'; keystr++)
window_pane_key(wp, NULL, s, *keystr, NULL);
} }
} }

View File

@ -1,174 +0,0 @@
/* $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.
*/
enum cmd_retval cmd_server_info_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_server_info_entry = {
"server-info", "info",
"", 0, 0,
"",
0,
NULL,
NULL,
cmd_server_info_exec
};
enum cmd_retval
cmd_server_info_exec(unused struct cmd *self, struct cmd_q *cmdq)
{
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, lines;
size_t size;
char out[80];
char *tim;
time_t t;
tim = ctime(&start_time);
*strchr(tim, '\n') = '\0';
cmdq_print(cmdq,
"tmux " VERSION ", pid %ld, started %s", (long) getpid(), tim);
cmdq_print(cmdq, "socket path %s, debug level %d", socket_path,
debug_level);
if (uname(&un) >= 0) {
cmdq_print(cmdq, "system is %s %s %s %s",
un.sysname, un.release, un.version, un.machine);
}
if (cfg_file != NULL)
cmdq_print(cmdq, "configuration file is %s", cfg_file);
else
cmdq_print(cmdq, "configuration file not specified");
cmdq_print(cmdq, "protocol version is %d", PROTOCOL_VERSION);
cmdq_print(cmdq, "%s", "");
cmdq_print(cmdq, "Clients:");
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
continue;
cmdq_print(cmdq,"%2d: %s (%d, %d): %s [%ux%u %s bs=%hho "
"class=%u] [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->tty.class,
c->flags, c->tty.flags, c->references);
}
cmdq_print(cmdq, "%s", "");
cmdq_print(cmdq, "Sessions: [%zu]", sizeof (struct grid_cell));
RB_FOREACH(s, sessions, &sessions) {
t = s->creation_time.tv_sec;
tim = ctime(&t);
*strchr(tim, '\n') = '\0';
cmdq_print(cmdq, "%2u: %s: %u windows (created %s) [%ux%u] "
"[flags=0x%x]", s->id, s->name,
winlink_count(&s->windows), tim, s->sx, s->sy, s->flags);
RB_FOREACH(wl, winlinks, &s->windows) {
w = wl->window;
cmdq_print(cmdq, "%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 = size = 0;
gd = wp->base.grid;
for (k = 0; k < gd->hsize + gd->sy; k++) {
gl = &gd->linedata[k];
if (gl->celldata == NULL)
continue;
lines++;
size += gl->cellsize *
sizeof *gl->celldata;
}
cmdq_print(cmdq,
"%6u: %s %lu %u/%u, %zu bytes", j,
wp->tty, (u_long) wp->pid, lines,
gd->hsize + gd->sy, size);
j++;
}
}
}
cmdq_print(cmdq, "%s", "");
cmdq_print(cmdq, "Terminals:");
LIST_FOREACH(term, &tty_terms, entry) {
cmdq_print(cmdq, "%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:
cmdq_print(cmdq, "%2u: %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, "%2u: %s: (string) %s",
ent->code, ent->name, out);
break;
case TTYCODE_NUMBER:
cmdq_print(cmdq, "%2u: %s: (number) %d",
ent->code, ent->name, code->value.number);
break;
case TTYCODE_FLAG:
cmdq_print(cmdq, "%2u: %s: (flag) %s",
ent->code, ent->name,
code->value.flag ? "true" : "false");
break;
}
}
}
cmdq_print(cmdq, "%s", "");
cmdq_print(cmdq, "Jobs:");
LIST_FOREACH(job, &all_jobs, lentry) {
cmdq_print(cmdq, "%s [fd=%d, pid=%d, status=%d]",
job->cmd, job->fd, job->pid, job->status);
}
return (CMD_RETURN_NORMAL);
}

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -24,51 +24,98 @@
#include "tmux.h" #include "tmux.h"
/* /*
* Add or set a paste buffer. * Add, set, append to or delete a paste buffer.
*/ */
enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_set_buffer_entry = { const struct cmd_entry cmd_set_buffer_entry = {
"set-buffer", "setb", .name = "set-buffer",
"b:", 1, 1, .alias = "setb",
CMD_BUFFER_USAGE " data",
0, .args = { "ab:n:", 0, 1 },
NULL, .usage = "[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data",
NULL,
cmd_set_buffer_exec .flags = 0,
.exec = cmd_set_buffer_exec
};
const struct cmd_entry cmd_delete_buffer_entry = {
.name = "delete-buffer",
.alias = "deleteb",
.args = { "b:", 0, 0 },
.usage = CMD_BUFFER_USAGE,
.flags = 0,
.exec = cmd_set_buffer_exec
}; };
enum cmd_retval enum cmd_retval
cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq) cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
u_int limit; struct paste_buffer *pb;
char *pdata, *cause; char *bufdata, *cause;
size_t psize; const char *bufname, *olddata;
int buffer; size_t bufsize, newsize;
limit = options_get_number(&global_options, "buffer-limit"); bufname = args_get(args, 'b');
if (bufname == NULL)
pb = NULL;
else
pb = paste_get_name(bufname);
pdata = xstrdup(args->argv[0]); if (self->entry == &cmd_delete_buffer_entry) {
psize = strlen(pdata); if (pb == NULL)
pb = paste_get_top(&bufname);
if (!args_has(args, 'b')) { if (pb == NULL) {
paste_add(&global_buffers, pdata, psize, limit); cmdq_error(cmdq, "no buffer");
return (CMD_RETURN_ERROR);
}
paste_free(pb);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (args_has(args, 'n')) {
if (cause != NULL) { if (pb == NULL)
cmdq_error(cmdq, "buffer %s", cause); pb = paste_get_top(&bufname);
if (pb == NULL) {
cmdq_error(cmdq, "no buffer");
return (CMD_RETURN_ERROR);
}
if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) {
cmdq_error(cmdq, "%s", cause);
free(cause); free(cause);
free(pdata);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
return (CMD_RETURN_NORMAL);
}
if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) { if (args->argc != 1) {
cmdq_error(cmdq, "no buffer %d", buffer); cmdq_error(cmdq, "no data specified");
free(pdata); return (CMD_RETURN_ERROR);
}
if ((newsize = strlen(args->argv[0])) == 0)
return (CMD_RETURN_NORMAL);
bufsize = 0;
bufdata = NULL;
if (args_has(args, 'a') && pb != NULL) {
olddata = paste_buffer_data(pb, &bufsize);
bufdata = xmalloc(bufsize);
memcpy(bufdata, olddata, bufsize);
}
bufdata = xrealloc(bufdata, bufsize + newsize);
memcpy(bufdata + bufsize, args->argv[0], newsize);
bufsize += newsize;
if (paste_set(bufdata, bufsize, bufname, &cause) != 0) {
cmdq_error(cmdq, "%s", cause);
free(bufdata);
free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -30,20 +30,22 @@
enum cmd_retval cmd_set_environment_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_set_environment_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_set_environment_entry = { const struct cmd_entry cmd_set_environment_entry = {
"set-environment", "setenv", .name = "set-environment",
"grt:u", 1, 2, .alias = "setenv",
"[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
0, .args = { "grt:u", 1, 2 },
NULL, .usage = "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
NULL,
cmd_set_environment_exec .tflag = CMD_SESSION_CANFAIL,
.flags = 0,
.exec = cmd_set_environment_exec
}; };
enum cmd_retval enum cmd_retval
cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq) cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s;
struct environ *env; struct environ *env;
const char *name, *value; const char *name, *value;
@ -62,13 +64,10 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq)
else else
value = args->argv[1]; value = args->argv[1];
if (args_has(self->args, 'g')) if (args_has(self->args, 'g') || cmdq->state.tflag.s == NULL)
env = &global_environ; env = global_environ;
else { else
if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL) env = cmdq->state.tflag.s->environ;
return (CMD_RETURN_ERROR);
env = &s->environ;
}
if (args_has(self->args, 'u')) { if (args_has(self->args, 'u')) {
if (value != NULL) { if (value != NULL) {
@ -81,13 +80,13 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq)
cmdq_error(cmdq, "can't specify a value with -r"); cmdq_error(cmdq, "can't specify a value with -r");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
environ_set(env, name, NULL); environ_clear(env, name);
} else { } else {
if (value == NULL) { if (value == NULL) {
cmdq_error(cmdq, "no value specified"); cmdq_error(cmdq, "no value specified");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
environ_set(env, name, value); environ_set(env, name, "%s", value);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

120
cmd-set-hook.c Normal file
View File

@ -0,0 +1,120 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Set or show global or session hooks.
*/
enum cmd_retval cmd_set_hook_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_set_hook_entry = {
.name = "set-hook",
.alias = NULL,
.args = { "gt:u", 1, 2 },
.usage = "[-gu] " CMD_TARGET_SESSION_USAGE " hook-name [command]",
.tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_set_hook_exec
};
const struct cmd_entry cmd_show_hooks_entry = {
.name = "show-hooks",
.alias = NULL,
.args = { "gt:", 0, 1 },
.usage = "[-g] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_set_hook_exec
};
enum cmd_retval
cmd_set_hook_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct cmd_list *cmdlist;
struct hooks *hooks;
struct hook *hook;
char *cause, *tmp;
const char *name, *cmd;
if (args_has(args, 'g'))
hooks = global_hooks;
else
hooks = cmdq->state.tflag.s->hooks;
if (self->entry == &cmd_show_hooks_entry) {
hook = hooks_first(hooks);
while (hook != NULL) {
tmp = cmd_list_print(hook->cmdlist);
cmdq_print(cmdq, "%s -> %s", hook->name, tmp);
free(tmp);
hook = hooks_next(hook);
}
return (CMD_RETURN_NORMAL);
}
name = args->argv[0];
if (*name == '\0') {
cmdq_error(cmdq, "invalid hook name");
return (CMD_RETURN_ERROR);
}
if (args->argc < 2)
cmd = NULL;
else
cmd = args->argv[1];
if (args_has(args, 'u')) {
if (cmd != NULL) {
cmdq_error(cmdq, "command passed to unset hook: %s",
name);
return (CMD_RETURN_ERROR);
}
hooks_remove(hooks, name);
return (CMD_RETURN_NORMAL);
}
if (cmd == NULL) {
cmdq_error(cmdq, "no command to set hook: %s", name);
return (CMD_RETURN_ERROR);
}
if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) {
cmdq_error(cmdq, "%s", cause);
free(cause);
}
return (CMD_RETURN_ERROR);
}
hooks_add(hooks, name, cmdlist);
cmd_list_free(cmdlist);
return (CMD_RETURN_NORMAL);
}

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -60,39 +60,47 @@ struct options_entry *cmd_set_option_flag(struct cmd *, struct cmd_q *,
struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_q *, struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *, const struct options_table_entry *, struct options *,
const char *); const char *);
struct options_entry *cmd_set_option_style(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
const struct cmd_entry cmd_set_option_entry = { const struct cmd_entry cmd_set_option_entry = {
"set-option", "set", .name = "set-option",
"agoqst:uw", 1, 2, .alias = "set",
"[-agosquw] [-t target-session|target-window] option [value]",
0, .args = { "agoqst:uw", 1, 2 },
NULL, .usage = "[-agosquw] [-t target-window] option [value]",
NULL,
cmd_set_option_exec .tflag = CMD_WINDOW_CANFAIL,
.flags = 0,
.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", .name = "set-window-option",
"agoqt:u", 1, 2, .alias = "setw",
"[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
0, .args = { "agoqt:u", 1, 2 },
NULL, .usage = "[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
NULL,
cmd_set_option_exec .tflag = CMD_WINDOW_CANFAIL,
.flags = 0,
.exec = cmd_set_option_exec
}; };
enum cmd_retval enum cmd_retval
cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq) cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
const struct options_table_entry *table, *oe; struct session *s = cmdq->state.tflag.s;
struct session *s; struct winlink *wl = cmdq->state.tflag.wl;
struct winlink *wl;
struct client *c;
struct options *oo;
struct window *w; struct window *w;
struct client *c;
const struct options_table_entry *oe;
struct options *oo;
const char *optstr, *valstr; const char *optstr, *valstr;
u_int i;
/* Get the option name and value. */ /* Get the option name and value. */
optstr = args->argv[0]; optstr = args->argv[0];
@ -110,36 +118,50 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq)
return (cmd_set_option_user(self, cmdq, optstr, valstr)); 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; oe = NULL;
if (options_table_find(optstr, &table, &oe) != 0) { if (options_table_find(optstr, &oe) != 0) {
if (!args_has(args, 'q')) {
cmdq_error(cmdq, "ambiguous option: %s", optstr); cmdq_error(cmdq, "ambiguous option: %s", optstr);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
return (CMD_RETURN_NORMAL);
}
if (oe == NULL) { if (oe == NULL) {
if (!args_has(args, 'q')) {
cmdq_error(cmdq, "unknown option: %s", optstr); cmdq_error(cmdq, "unknown option: %s", optstr);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
return (CMD_RETURN_NORMAL);
/* Work out the tree from the table. */
if (table == server_options_table)
oo = &global_options;
else if (table == window_options_table) {
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 (table == session_options_table) {
/* Work out the tree from the scope of the option. */
if (oe->scope == OPTIONS_TABLE_SERVER)
oo = global_options;
else if (oe->scope == OPTIONS_TABLE_WINDOW) {
if (args_has(self->args, 'g')) if (args_has(self->args, 'g'))
oo = &global_s_options; oo = global_w_options;
else { else {
s = cmd_find_session(cmdq, args_get(args, 't'), 0); if (wl == NULL) {
if (s == NULL) cmdq_error(cmdq,
"couldn't set '%s'%s", optstr,
(!args_has(args, 't') && !args_has(args,
'g')) ? " need target window or -g" : "");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
oo = &s->options; }
oo = wl->window->options;
}
} else if (oe->scope == OPTIONS_TABLE_SESSION) {
if (args_has(self->args, 'g'))
oo = global_s_options;
else {
if (s == NULL) {
cmdq_error(cmdq,
"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;
} }
} else { } else {
cmdq_error(cmdq, "unknown table"); cmdq_error(cmdq, "unknown table");
@ -152,33 +174,39 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} else { } else {
if (args_has(args, 'o') && options_find1(oo, optstr) != NULL) { if (args_has(args, 'o') && options_find1(oo, optstr) != NULL) {
if (!args_has(args, 'q')) if (!args_has(args, 'q')) {
cmdq_print(cmdq, "already set: %s", optstr); cmdq_error(cmdq, "already set: %s", optstr);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (cmd_set_option_set(self, cmdq, oe, oo, valstr) != 0) if (cmd_set_option_set(self, cmdq, oe, oo, valstr) != 0)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
/* Start or stop timers when automatic-rename changed. */ /* Start or stop timers if necessary. */
#ifndef TMATE_SLAVE #ifndef TMATE_SLAVE
if (strcmp(oe->name, "automatic-rename") == 0) { if (strcmp(oe->name, "automatic-rename") == 0) {
for (i = 0; i < ARRAY_LENGTH(&windows); i++) { RB_FOREACH(w, windows, &windows) {
if ((w = ARRAY_ITEM(&windows, i)) == NULL) if (options_get_number(w->options, "automatic-rename"))
continue; w->active->flags |= PANE_CHANGED;
if (options_get_number(&w->options, "automatic-rename"))
queue_window_name(w);
else if (event_initialized(&w->name_timer))
evtimer_del(&w->name_timer);
} }
} }
#endif #endif
if (strcmp(oe->name, "key-table") == 0) {
TAILQ_FOREACH(c, &clients, entry)
server_client_set_key_table(c, NULL);
}
if (strcmp(oe->name, "status") == 0 ||
strcmp(oe->name, "status-interval") == 0)
status_timer_start_all();
if (strcmp(oe->name, "monitor-silence") == 0)
alerts_reset_all();
/* Update sizes and redraw. May not need it but meh. */ /* Update sizes and redraw. May not need it but meh. */
recalculate_sizes(); recalculate_sizes();
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { TAILQ_FOREACH(c, &clients, entry) {
c = ARRAY_ITEM(&clients, i); if (c->session != NULL)
if (c != NULL && c->session != NULL)
server_redraw_client(c); server_redraw_client(c);
} }
@ -191,38 +219,33 @@ cmd_set_option_user(struct cmd *self, struct cmd_q *cmdq, const char* optstr,
const char *valstr) const char *valstr)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s = cmdq->state.tflag.s;
struct winlink *wl; struct winlink *wl = cmdq->state.tflag.wl;
struct options *oo; struct options *oo;
if (args_has(args, 's')) if (args_has(args, 's'))
oo = &global_options; oo = global_options;
else if (args_has(self->args, 'w') || else if (args_has(self->args, 'w') ||
self->entry == &cmd_set_window_option_entry) { self->entry == &cmd_set_window_option_entry) {
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); oo = wl->window->options;
if (wl == NULL)
return (CMD_RETURN_ERROR);
oo = &wl->window->options;
}
} else { } else {
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); oo = s->options;
if (s == NULL)
return (CMD_RETURN_ERROR);
oo = &s->options;
}
} }
if (args_has(args, 'u')) { if (args_has(args, 'u')) {
if (options_find1(oo, optstr) == NULL) { if (options_find1(oo, optstr) == NULL) {
if (!args_has(args, 'q')) {
cmdq_error(cmdq, "unknown option: %s", optstr); cmdq_error(cmdq, "unknown option: %s", optstr);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
return (CMD_RETURN_NORMAL);
}
if (valstr != NULL) { if (valstr != NULL) {
cmdq_error(cmdq, "value passed to unset option: %s", cmdq_error(cmdq, "value passed to unset option: %s",
optstr); optstr);
@ -235,55 +258,65 @@ cmd_set_option_user(struct cmd *self, struct cmd_q *cmdq, const char* optstr,
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(args, 'o') && options_find1(oo, optstr) != NULL) { if (args_has(args, 'o') && options_find1(oo, optstr) != NULL) {
if (!args_has(args, 'q')) if (!args_has(args, 'q')) {
cmdq_print(cmdq, "already set: %s", optstr); cmdq_error(cmdq, "already set: %s", optstr);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
options_set_string(oo, optstr, "%s", valstr); options_set_string(oo, optstr, "%s", valstr);
if (!args_has(args, 'q')) {
cmdq_info(cmdq, "set option: %s -> %s", optstr,
valstr);
}
} }
return (CMD_RETURN_NORMAL); 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_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value) const struct options_table_entry *oe, struct options *oo,
const char *value)
{ {
struct args *args = self->args; struct args *args = self->args;
if (args_has(args, 'g')) {
cmdq_error(cmdq, "can't unset global option: %s", oe->name);
return (-1);
}
if (value != NULL) { if (value != NULL) {
cmdq_error(cmdq, "value passed to unset option: %s", oe->name); cmdq_error(cmdq, "value passed to unset option: %s", oe->name);
return (-1); return (-1);
} }
if (args_has(args, 'g') || oo == global_options) {
switch (oe->type) {
case OPTIONS_TABLE_STRING:
options_set_string(oo, oe->name, "%s", oe->default_str);
break;
case OPTIONS_TABLE_STYLE:
options_set_style(oo, oe->name, oe->default_str, 0);
break;
default:
options_set_number(oo, oe->name, oe->default_num);
break;
}
} else
options_remove(oo, oe->name); options_remove(oo, oe->name);
if (!args_has(args, 'q'))
cmdq_info(cmdq, "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_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value) const struct options_table_entry *oe, struct options *oo,
const char *value)
{ {
struct args *args = self->args;
struct options_entry *o; struct options_entry *o;
const char *s;
if (oe->type != OPTIONS_TABLE_FLAG && value == NULL) { switch (oe->type) {
case OPTIONS_TABLE_FLAG:
case OPTIONS_TABLE_CHOICE:
break;
default:
if (value == NULL) {
cmdq_error(cmdq, "empty value"); cmdq_error(cmdq, "empty value");
return (-1); return (-1);
} }
}
o = NULL; o = NULL;
switch (oe->type) { switch (oe->type) {
@ -298,9 +331,13 @@ cmd_set_option_set(struct cmd *self, struct cmd_q *cmdq,
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, cmdq, 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, cmdq, 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, cmdq, oe, oo, value);
@ -308,20 +345,20 @@ cmd_set_option_set(struct cmd *self, struct cmd_q *cmdq,
case OPTIONS_TABLE_CHOICE: case OPTIONS_TABLE_CHOICE:
o = cmd_set_option_choice(self, cmdq, oe, oo, value); o = cmd_set_option_choice(self, cmdq, oe, oo, value);
break; break;
case OPTIONS_TABLE_STYLE:
o = cmd_set_option_style(self, cmdq, oe, oo, value);
break;
} }
if (o == NULL) if (o == NULL)
return (-1); return (-1);
s = options_table_print_entry(oe, o, 0);
if (!args_has(args, 'q'))
cmdq_info(cmdq, "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_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value) const struct options_table_entry *oe, struct options *oo,
const char *value)
{ {
struct args *args = self->args; struct args *args = self->args;
struct options_entry *o; struct options_entry *o;
@ -341,8 +378,9 @@ cmd_set_option_string(struct cmd *self, unused struct cmd_q *cmdq,
/* 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_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value) const struct options_table_entry *oe, struct options *oo,
const char *value)
{ {
long long ll; long long ll;
const char *errstr; const char *errstr;
@ -358,12 +396,14 @@ cmd_set_option_number(unused struct cmd *self, struct cmd_q *cmdq,
/* Set a key option. */ /* Set a key option. */
struct options_entry * struct options_entry *
cmd_set_option_key(unused struct cmd *self, struct cmd_q *cmdq, cmd_set_option_key(__unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value) const struct options_table_entry *oe, struct options *oo,
const char *value)
{ {
int key; key_code key;
if ((key = key_string_lookup_string(value)) == KEYC_NONE) { key = key_string_lookup_string(value);
if (key == KEYC_UNKNOWN) {
cmdq_error(cmdq, "bad key: %s", value); cmdq_error(cmdq, "bad key: %s", value);
return (NULL); return (NULL);
} }
@ -373,8 +413,9 @@ cmd_set_option_key(unused struct cmd *self, struct cmd_q *cmdq,
/* 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_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value) const struct options_table_entry *oe, struct options *oo,
const char *value)
{ {
int colour; int colour;
@ -388,8 +429,9 @@ 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_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value) const struct options_table_entry *oe, struct options *oo,
const char *value)
{ {
int attr; int attr;
@ -403,8 +445,9 @@ 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_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value) const struct options_table_entry *oe, struct options *oo,
const char *value)
{ {
int flag; int flag;
@ -430,13 +473,18 @@ 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_q *cmdq,
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;
if (value == NULL) {
choice = options_get_number(oo, oe->name);
if (choice < 2)
choice = !choice;
} else {
n = 0; n = 0;
for (choicep = oe->choices; *choicep != NULL; choicep++) { for (choicep = oe->choices; *choicep != NULL; choicep++) {
n++; n++;
@ -453,6 +501,27 @@ cmd_set_option_choice(unused struct cmd *self, struct cmd_q *cmdq,
cmdq_error(cmdq, "unknown value: %s", value); cmdq_error(cmdq, "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);
}

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -29,31 +29,75 @@
enum cmd_retval cmd_show_environment_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_show_environment_exec(struct cmd *, struct cmd_q *);
char *cmd_show_environment_escape(struct environ_entry *);
void cmd_show_environment_print(struct cmd *, struct cmd_q *,
struct environ_entry *);
const struct cmd_entry cmd_show_environment_entry = { const struct cmd_entry cmd_show_environment_entry = {
"show-environment", "showenv", .name = "show-environment",
"gt:", 0, 1, .alias = "showenv",
"[-g] " CMD_TARGET_SESSION_USAGE " [name]",
0, .args = { "gst:", 0, 1 },
NULL, .usage = "[-gs] " CMD_TARGET_SESSION_USAGE " [name]",
NULL,
cmd_show_environment_exec .tflag = CMD_SESSION_CANFAIL,
.flags = 0,
.exec = cmd_show_environment_exec
}; };
char *
cmd_show_environment_escape(struct environ_entry *envent)
{
const char *value = envent->value;
char c, *out, *ret;
out = ret = xmalloc(strlen(value) * 2 + 1); /* at most twice the size */
while ((c = *value++) != '\0') {
/* POSIX interprets $ ` " and \ in double quotes. */
if (c == '$' || c == '`' || c == '"' || c == '\\')
*out++ = '\\';
*out++ = c;
}
*out = '\0';
return (ret);
}
void
cmd_show_environment_print(struct cmd *self, struct cmd_q *cmdq,
struct environ_entry *envent)
{
char *escaped;
if (!args_has(self->args, 's')) {
if (envent->value != NULL)
cmdq_print(cmdq, "%s=%s", envent->name, envent->value);
else
cmdq_print(cmdq, "-%s", envent->name);
return;
}
if (envent->value != NULL) {
escaped = cmd_show_environment_escape(envent);
cmdq_print(cmdq, "%s=\"%s\"; export %s;", envent->name, escaped,
envent->name);
free(escaped);
} else
cmdq_print(cmdq, "unset %s;", envent->name);
}
enum cmd_retval enum cmd_retval
cmd_show_environment_exec(struct cmd *self, struct cmd_q *cmdq) cmd_show_environment_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s;
struct environ *env; struct environ *env;
struct environ_entry *envent; struct environ_entry *envent;
if (args_has(self->args, 'g')) if (args_has(self->args, 'g') || cmdq->state.tflag.s == NULL)
env = &global_environ; env = global_environ;
else { else
if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL) env = cmdq->state.tflag.s->environ;
return (CMD_RETURN_ERROR);
env = &s->environ;
}
if (args->argc != 0) { if (args->argc != 0) {
envent = environ_find(env, args->argv[0]); envent = environ_find(env, args->argv[0]);
@ -61,19 +105,14 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_q *cmdq)
cmdq_error(cmdq, "unknown variable: %s", args->argv[0]); cmdq_error(cmdq, "unknown variable: %s", args->argv[0]);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (envent->value != NULL) cmd_show_environment_print(self, cmdq, envent);
cmdq_print(cmdq, "%s=%s", envent->name, envent->value);
else
cmdq_print(cmdq, "-%s", envent->name);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
RB_FOREACH(envent, environ, env) { envent = environ_first(env);
if (envent->value != NULL) while (envent != NULL) {
cmdq_print(cmdq, "%s=%s", envent->name, envent->value); cmd_show_environment_print(self, cmdq, envent);
else envent = environ_next(envent);
cmdq_print(cmdq, "-%s", envent->name);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -20,6 +20,7 @@
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
@ -30,30 +31,94 @@
enum cmd_retval cmd_show_messages_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_show_messages_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_show_messages_entry = { const struct cmd_entry cmd_show_messages_entry = {
"show-messages", "showmsgs", .name = "show-messages",
"t:", 0, 0, .alias = "showmsgs",
CMD_TARGET_CLIENT_USAGE,
0, .args = { "JTt:", 0, 0 },
NULL, .usage = "[-JT] " CMD_TARGET_CLIENT_USAGE,
NULL,
cmd_show_messages_exec .tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_show_messages_exec
}; };
const struct cmd_entry cmd_server_info_entry = {
.name = "server-info",
.alias = "info",
.args = { "", 0, 0 },
.usage = "",
.flags = 0,
.exec = cmd_show_messages_exec
};
int cmd_show_messages_terminals(struct cmd_q *, int);
int cmd_show_messages_jobs(struct cmd_q *, int);
int
cmd_show_messages_terminals(struct cmd_q *cmdq, int blank)
{
struct tty_term *term;
u_int i, n;
n = 0;
LIST_FOREACH(term, &tty_terms, entry) {
if (blank) {
cmdq_print(cmdq, "%s", "");
blank = 0;
}
cmdq_print(cmdq, "Terminal %u: %s [references=%u, flags=0x%x]:",
n, term->name, term->references, term->flags);
n++;
for (i = 0; i < tty_term_ncodes(); i++)
cmdq_print(cmdq, "%s", tty_term_describe(term, i));
}
return (n != 0);
}
int
cmd_show_messages_jobs(struct cmd_q *cmdq, int blank)
{
struct job *job;
u_int n;
n = 0;
LIST_FOREACH(job, &all_jobs, lentry) {
if (blank) {
cmdq_print(cmdq, "%s", "");
blank = 0;
}
cmdq_print(cmdq, "Job %u: %s [fd=%d, pid=%d, status=%d]",
n, job->cmd, job->fd, job->pid, job->status);
n++;
}
return (n != 0);
}
enum cmd_retval enum cmd_retval
cmd_show_messages_exec(struct cmd *self, struct cmd_q *cmdq) 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 = cmdq->state.c;
struct message_entry *msg; struct message_entry *msg;
char *tim; char *tim;
u_int i; int done, blank;
if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL) done = blank = 0;
return (CMD_RETURN_ERROR); if (args_has(args, 'T') || self->entry == &cmd_server_info_entry) {
blank = cmd_show_messages_terminals(cmdq, blank);
for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) { done = 1;
msg = &ARRAY_ITEM(&c->message_log, i); }
if (args_has(args, 'J') || self->entry == &cmd_server_info_entry) {
cmd_show_messages_jobs(cmdq, blank);
done = 1;
}
if (done)
return (CMD_RETURN_NORMAL);
TAILQ_FOREACH(msg, &c->message_log, entry) {
tim = ctime(&msg->msg_time); tim = ctime(&msg->msg_time);
*strchr(tim, '\n') = '\0'; *strchr(tim, '\n') = '\0';

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -32,67 +32,65 @@ enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmd_q *);
enum cmd_retval cmd_show_options_one(struct cmd *, struct cmd_q *, enum cmd_retval cmd_show_options_one(struct cmd *, struct cmd_q *,
struct options *, int); struct options *, int);
enum cmd_retval cmd_show_options_all(struct cmd *, struct cmd_q *, enum cmd_retval cmd_show_options_all(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *); struct options *, enum options_table_scope);
const struct cmd_entry cmd_show_options_entry = { const struct cmd_entry cmd_show_options_entry = {
"show-options", "show", .name = "show-options",
"gqst:vw", 0, 1, .alias = "show",
"[-gqsvw] [-t target-session|target-window] [option]",
0, .args = { "gqst:vw", 0, 1 },
NULL, .usage = "[-gqsvw] [-t target-session|target-window] [option]",
NULL,
cmd_show_options_exec .tflag = CMD_WINDOW_CANFAIL,
.flags = 0,
.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", .name = "show-window-options",
"gvt:", 0, 1, .alias = "showw",
"[-gv] " CMD_TARGET_WINDOW_USAGE " [option]",
0, .args = { "gvt:", 0, 1 },
NULL, .usage = "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]",
NULL,
cmd_show_options_exec .tflag = CMD_WINDOW_CANFAIL,
.flags = 0,
.exec = cmd_show_options_exec
}; };
enum cmd_retval enum cmd_retval
cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq) cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s = cmdq->state.tflag.s;
struct winlink *wl; struct winlink *wl = cmdq->state.tflag.wl;
const struct options_table_entry *table;
struct options *oo; struct options *oo;
enum options_table_scope scope;
int quiet; int quiet;
if (args_has(self->args, 's')) { if (args_has(self->args, 's')) {
oo = &global_options; oo = global_options;
table = server_options_table; scope = OPTIONS_TABLE_SERVER;
} else if (args_has(self->args, 'w') || } else if (args_has(self->args, 'w') ||
self->entry == &cmd_show_window_options_entry) { self->entry == &cmd_show_window_options_entry) {
table = window_options_table; scope = OPTIONS_TABLE_WINDOW;
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); oo = wl->window->options;
if (wl == NULL)
return (CMD_RETURN_ERROR);
oo = &wl->window->options;
}
} else { } else {
table = session_options_table; scope = OPTIONS_TABLE_SESSION;
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); oo = s->options;
if (s == NULL)
return (CMD_RETURN_ERROR);
oo = &s->options;
}
} }
quiet = args_has(self->args, 'q'); quiet = args_has(self->args, 'q');
if (args->argc == 0) if (args->argc == 0)
return (cmd_show_options_all(self, cmdq, table, oo)); return (cmd_show_options_all(self, cmdq, oo, scope));
else else
return (cmd_show_options_one(self, cmdq, oo, quiet)); return (cmd_show_options_one(self, cmdq, oo, quiet));
} }
@ -102,15 +100,17 @@ cmd_show_options_one(struct cmd *self, struct cmd_q *cmdq,
struct options *oo, int quiet) struct options *oo, int quiet)
{ {
struct args *args = self->args; struct args *args = self->args;
const struct options_table_entry *table, *oe; const char *name = args->argv[0];
const struct options_table_entry *oe;
struct options_entry *o; struct options_entry *o;
const char *optval; const char *optval;
if (*args->argv[0] == '@') { retry:
if ((o = options_find1(oo, args->argv[0])) == NULL) { if (*name == '@') {
if ((o = options_find1(oo, name)) == NULL) {
if (quiet) if (quiet)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
cmdq_error(cmdq, "unknown option: %s", args->argv[0]); cmdq_error(cmdq, "unknown option: %s", name);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(self->args, 'v')) if (args_has(self->args, 'v'))
@ -120,17 +120,21 @@ cmd_show_options_one(struct cmd *self, struct cmd_q *cmdq,
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
table = oe = NULL; oe = NULL;
if (options_table_find(args->argv[0], &table, &oe) != 0) { if (options_table_find(name, &oe) != 0) {
cmdq_error(cmdq, "ambiguous option: %s", args->argv[0]); cmdq_error(cmdq, "ambiguous option: %s", name);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (oe == NULL) { if (oe == NULL) {
if (quiet) if (quiet)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
cmdq_error(cmdq, "unknown option: %s", args->argv[0]); cmdq_error(cmdq, "unknown option: %s", name);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (oe->style != NULL) {
name = oe->style;
goto retry;
}
if ((o = options_find1(oo, oe->name)) == NULL) if ((o = options_find1(oo, oe->name)) == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
optval = options_table_print_entry(oe, o, args_has(self->args, 'v')); optval = options_table_print_entry(oe, o, args_has(self->args, 'v'));
@ -142,28 +146,33 @@ cmd_show_options_one(struct cmd *self, struct cmd_q *cmdq,
} }
enum cmd_retval enum cmd_retval
cmd_show_options_all(struct cmd *self, struct cmd_q *cmdq, cmd_show_options_all(struct cmd *self, struct cmd_q *cmdq, struct options *oo,
const struct options_table_entry *table, struct options *oo) enum options_table_scope scope)
{ {
const struct options_table_entry *oe; const struct options_table_entry *oe;
struct options_entry *o; struct options_entry *o;
const char *optval; const char *optval;
int vflag;
RB_FOREACH(o, options_tree, &oo->tree) { o = options_first(oo);
while (o != NULL) {
if (*o->name == '@') { if (*o->name == '@') {
if (args_has(self->args, 'v')) if (args_has(self->args, 'v'))
cmdq_print(cmdq, "%s", o->str); cmdq_print(cmdq, "%s", o->str);
else else
cmdq_print(cmdq, "%s \"%s\"", o->name, o->str); cmdq_print(cmdq, "%s \"%s\"", o->name, o->str);
} }
o = options_next(o);
} }
for (oe = table; oe->name != NULL; oe++) { vflag = args_has(self->args, 'v');
for (oe = options_table; oe->name != NULL; oe++) {
if (oe->style != NULL || oe->scope != scope)
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, vflag);
args_has(self->args, 'v')); if (vflag)
if (args_has(self->args, 'v'))
cmdq_print(cmdq, "%s", optval); cmdq_print(cmdq, "%s", optval);
else else
cmdq_print(cmdq, "%s %s", oe->name, optval); cmdq_print(cmdq, "%s %s", oe->name, optval);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2008 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2008 Tiago Cunha <me@tiagocunha.org>
@ -28,17 +28,17 @@
enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmd_q *);
void cmd_source_file_show(struct cmd_q *);
void cmd_source_file_done(struct cmd_q *); 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", .name = "source-file",
"", 1, 1, .alias = "source",
"path",
0, .args = { "", 1, 1 },
NULL, .usage = "path",
NULL,
cmd_source_file_exec .flags = 0,
.exec = cmd_source_file_exec
}; };
enum cmd_retval enum cmd_retval
@ -48,7 +48,7 @@ cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq)
struct cmd_q *cmdq1; struct cmd_q *cmdq1;
char *cause; char *cause;
cmdq1 = cmdq_new(NULL); cmdq1 = cmdq_new(cmdq->client);
cmdq1->emptyfn = cmd_source_file_done; cmdq1->emptyfn = cmd_source_file_done;
cmdq1->data = cmdq; cmdq1->data = cmdq;
@ -60,11 +60,12 @@ cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq)
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
ARRAY_ADD(&cfg_causes, cause); cfg_add_cause("%s", cause);
free(cause);
/* FALLTHROUGH */ /* FALLTHROUGH */
case 0: case 0:
if (cfg_references == 0) if (cfg_references == 0)
cmd_source_file_show(cmdq); cfg_print_causes(cmdq);
cmdq_free(cmdq1); cmdq_free(cmdq1);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@ -76,25 +77,14 @@ cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
void
cmd_source_file_show(struct cmd_q *cmdq)
{
u_int i;
char *cause;
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
cause = ARRAY_ITEM(&cfg_causes, i);
cmdq_print(cmdq, "%s", cause);
free(cause);
}
ARRAY_FREE(&cfg_causes);
}
void void
cmd_source_file_done(struct cmd_q *cmdq1) cmd_source_file_done(struct cmd_q *cmdq1)
{ {
struct cmd_q *cmdq = cmdq1->data; struct cmd_q *cmdq = cmdq1->data;
if (cmdq1->client_exit >= 0)
cmdq->client_exit = cmdq1->client_exit;
cmdq_free(cmdq1); cmdq_free(cmdq1);
cfg_references--; cfg_references--;
@ -103,6 +93,6 @@ cmd_source_file_done(struct cmd_q *cmdq1)
return; return;
if (cfg_references == 0) if (cfg_references == 0)
cmd_source_file_show(cmdq); cfg_print_causes(cmdq);
cmdq_continue(cmdq); cmdq_continue(cmdq);
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -18,7 +18,10 @@
#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"
@ -27,27 +30,23 @@
* Split a window (add a new pane). * Split a window (add a new pane).
*/ */
void cmd_split_window_key_binding(struct cmd *, int); #define SPLIT_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmd_q *); 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", .name = "split-window",
"c:dF:l:hp:Pt:v", 0, 1, .alias = "splitw",
"[-dhvP] [-c start-directory] [-F format] [-p percentage|-l size] "
CMD_TARGET_PANE_USAGE " [command]",
0,
cmd_split_window_key_binding,
NULL,
cmd_split_window_exec
};
void .args = { "bc:dF:l:hp:Pt:v", 0, -1 },
cmd_split_window_key_binding(struct cmd *self, int key) .usage = "[-bdhvP] [-c start-directory] [-F format] "
{ "[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]",
self->args = args_create(0);
if (key == '%') .tflag = CMD_PANE,
args_set(self->args, 'h', NULL);
} .flags = 0,
.exec = cmd_split_window_exec
};
enum cmd_retval enum cmd_retval
cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
@ -56,37 +55,51 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
#else #else
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s = cmdq->state.tflag.s;
struct winlink *wl; struct winlink *wl = cmdq->state.tflag.wl;
struct window *w; struct window *w = wl->window;
struct window_pane *wp, *new_wp = NULL; struct window_pane *wp = cmdq->state.tflag.wp, *new_wp = NULL;
struct environ env; struct environ *env;
const char *cmd, *cwd, *shell; const char *cmd, *path, *shell, *template, *cwd, *to_free;
char *cause, *new_cause; char **argv, *cause, *new_cause, *cp;
u_int hlimit; u_int hlimit;
int size, percentage; int argc, size, percentage;
enum layout_type type; enum layout_type type;
struct layout_cell *lc; struct layout_cell *lc;
const char *template;
struct client *c;
struct format_tree *ft; struct format_tree *ft;
char *cp; struct environ_entry *envent;
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL)
return (CMD_RETURN_ERROR);
w = wl->window;
server_unzoom_window(w); server_unzoom_window(w);
environ_init(&env); env = environ_create();
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;
}
to_free = NULL;
if (args_has(args, 'c')) {
ft = format_create(cmdq, 0);
format_defaults(ft, cmdq->state.c, s, NULL, NULL);
to_free = cwd = format_expand(ft, args_get(args, 'c'));
format_free(ft);
} else if (cmdq->client != NULL && cmdq->client->session == NULL)
cwd = cmdq->client->cwd;
else else
cmd = args->argv[0]; cwd = s->cwd;
cwd = cmd_get_default_path(cmdq, args_get(args, 'c'));
type = LAYOUT_TOPBOTTOM; type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h')) if (args_has(args, 'h'))
@ -114,20 +127,32 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
else else
size = (wp->sx * percentage) / 100; size = (wp->sx * percentage) / 100;
} }
hlimit = options_get_number(&s->options, "history-limit"); hlimit = options_get_number(s->options, "history-limit");
shell = options_get_string(s->options, "default-shell");
if (*shell == '\0' || areshell(shell))
shell = _PATH_BSHELL; shell = _PATH_BSHELL;
if ((lc = layout_split_pane(wp, type, size, 0)) == NULL) { lc = layout_split_pane(wp, type, size, args_has(args, 'b'));
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(
new_wp, cmd, shell, cwd, &env, s->tio, &cause) != 0)
goto error;
layout_assign_pane(lc, new_wp); layout_assign_pane(lc, new_wp);
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 (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, env,
s->tio, &cause) != 0)
goto error;
server_redraw_window(w); server_redraw_window(w);
if (!args_has(args, 'd')) { if (!args_has(args, 'd')) {
@ -137,18 +162,14 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
} else } else
server_status_session(s); server_status_session(s);
environ_free(&env); environ_free(env);
if (args_has(args, 'P')) { if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = SPLIT_WINDOW_TEMPLATE; template = SPLIT_WINDOW_TEMPLATE;
ft = format_create(); ft = format_create(cmdq, 0);
if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) format_defaults(ft, cmdq->state.c, s, wl, new_wp);
format_client(ft, c);
format_session(ft, s);
format_winlink(ft, s, wl);
format_window_pane(ft, new_wp);
cp = format_expand(ft, template); cp = format_expand(ft, template);
cmdq_print(cmdq, "%s", cp); cmdq_print(cmdq, "%s", cp);
@ -157,14 +178,22 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
format_free(ft); format_free(ft);
} }
notify_window_layout_changed(w); notify_window_layout_changed(w);
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
error: error:
environ_free(&env); environ_free(env);
if (new_wp != NULL) if (new_wp != NULL) {
layout_close_pane(new_wp);
window_remove_pane(w, new_wp); window_remove_pane(w, new_wp);
}
cmdq_error(cmdq, "create pane failed: %s", cause); cmdq_error(cmdq, "create pane failed: %s", cause);
free(cause); free(cause);
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
#endif #endif
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -107,10 +107,11 @@ 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, 1, len + 1); buf = xrealloc(buf, len + 1);
buf[len] = '\0'; buf[len] = '\0';
argv = xrealloc(argv, argc + 1, sizeof *argv); argv = xreallocarray(argv, argc + 1,
sizeof *argv);
argv[argc++] = buf; argv[argc++] = buf;
buf = NULL; buf = NULL;
@ -125,7 +126,7 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, const char *file,
whitespace = argv[0] + strcspn(argv[0], " \t"); whitespace = argv[0] + strcspn(argv[0], " \t");
if (equals == NULL || equals > whitespace) if (equals == NULL || equals > whitespace)
break; break;
environ_put(&global_environ, argv[0]); environ_put(global_environ, argv[0]);
argc--; argc--;
memmove(argv, argv + 1, argc * (sizeof *argv)); memmove(argv, argv + 1, argc * (sizeof *argv));
} }
@ -151,7 +152,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, 1, len + 1); buf = xrealloc(buf, len + 1);
buf[len++] = ch; buf[len++] = ch;
break; break;
} }
@ -179,7 +180,7 @@ cmd_string_copy(char **dst, char *src, size_t *len)
srclen = strlen(src); srclen = strlen(src);
*dst = xrealloc(*dst, 1, *len + srclen + 1); *dst = xrealloc(*dst, *len + srclen + 1);
strlcpy(*dst + *len, src, srclen + 1); strlcpy(*dst + *len, src, srclen + 1);
*len += srclen; *len += srclen;
@ -231,11 +232,11 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc)
if (len >= SIZE_MAX - 2) if (len >= SIZE_MAX - 2)
goto error; goto error;
buf = xrealloc(buf, 1, len + 1); buf = xrealloc(buf, len + 1);
buf[len++] = ch; buf[len++] = ch;
} }
buf = xrealloc(buf, 1, len + 1); buf = xrealloc(buf, len + 1);
buf[len] = '\0'; buf[len] = '\0';
return (buf); return (buf);
@ -278,7 +279,7 @@ cmd_string_variable(const char *s, size_t *p)
return (t); return (t);
} }
buf = xrealloc(buf, 1, len + 1); buf = xrealloc(buf, len + 1);
buf[len++] = ch; buf[len++] = ch;
for (;;) { for (;;) {
@ -288,7 +289,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, 1, len + 1); buf = xrealloc(buf, len + 1);
buf[len++] = ch; buf[len++] = ch;
} }
} }
@ -299,10 +300,10 @@ 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, 1, len + 1); buf = xrealloc(buf, len + 1);
buf[len] = '\0'; buf[len] = '\0';
envent = environ_find(&global_environ, buf); envent = environ_find(global_environ, buf);
free(buf); free(buf);
if (envent == NULL) if (envent == NULL)
return (xstrdup("")); return (xstrdup(""));
@ -318,26 +319,41 @@ 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, *username; char *home, *path, *user, *cp;
int last;
home = NULL; home = NULL;
if (cmd_string_getc(s, p) == '/') {
envent = environ_find(&global_environ, "HOME"); last = cmd_string_getc(s, p);
if (last == EOF || last == '/' || last == ' '|| last == '\t') {
envent = environ_find(global_environ, "HOME");
if (envent != NULL && *envent->value != '\0') if (envent != NULL && *envent->value != '\0')
home = envent->value; home = envent->value;
else if ((pw = getpwuid(getuid())) != NULL) else if ((pw = getpwuid(getuid())) != NULL)
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)
return (NULL); cp = user = xmalloc(strlen(s));
if ((pw = getpwnam(username)) != NULL) for (;;) {
home = pw->pw_dir; last = cmd_string_getc(s, p);
free(username); if (last == EOF || last == '/' || last == ' '|| last == '\t')
break;
*cp++ = last;
} }
*cp = '\0';
if ((pw = getpwnam(user)) != NULL)
home = pw->pw_dir;
free(user);
}
if (home == NULL) if (home == NULL)
return (NULL); return (NULL);
xasprintf(&path, "%s/", home); if (last != EOF)
xasprintf(&path, "%s%c", home, last);
else
xasprintf(&path, "%s", home);
return (path); return (path);
} }

View File

@ -1,56 +0,0 @@
/* $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 <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Suspend client with SIGTSTP.
*/
enum cmd_retval cmd_suspend_client_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_suspend_client_entry = {
"suspend-client", "suspendc",
"t:", 0, 0,
CMD_TARGET_CLIENT_USAGE,
0,
NULL,
NULL,
cmd_suspend_client_exec
};
enum cmd_retval
cmd_suspend_client_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c;
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);
}

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -26,28 +26,21 @@
* Swap two panes. * Swap two panes.
*/ */
void cmd_swap_pane_key_binding(struct cmd *, int);
enum cmd_retval cmd_swap_pane_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_swap_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_swap_pane_entry = { const struct cmd_entry cmd_swap_pane_entry = {
"swap-pane", "swapp", .name = "swap-pane",
"dDs:t:U", 0, 0, .alias = "swapp",
"[-dDU] " CMD_SRCDST_PANE_USAGE,
0,
cmd_swap_pane_key_binding,
NULL,
cmd_swap_pane_exec
};
void .args = { "dDs:t:U", 0, 0 },
cmd_swap_pane_key_binding(struct cmd *self, int key) .usage = "[-dDU] " CMD_SRCDST_PANE_USAGE,
{
self->args = args_create(0); .sflag = CMD_PANE_MARKED,
if (key == '{') .tflag = CMD_PANE,
args_set(self->args, 'U', NULL);
else if (key == '}') .flags = 0,
args_set(self->args, 'D', NULL); .exec = cmd_swap_pane_exec
} };
enum cmd_retval enum cmd_retval
cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq)
@ -55,36 +48,32 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq)
#ifdef TMATE_SLAVE #ifdef TMATE_SLAVE
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
#else #else
struct args *args = self->args;
struct winlink *src_wl, *dst_wl; struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w; struct window *src_w, *dst_w;
struct window_pane *tmp_wp, *src_wp, *dst_wp; struct window_pane *tmp_wp, *src_wp, *dst_wp;
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 = cmdq->state.tflag.wl;
if (dst_wl == NULL)
return (CMD_RETURN_ERROR);
dst_w = dst_wl->window; dst_w = dst_wl->window;
dst_wp = cmdq->state.tflag.wp;
src_wl = cmdq->state.sflag.wl;
src_w = src_wl->window;
src_wp = cmdq->state.sflag.wp;
server_unzoom_window(dst_w); server_unzoom_window(dst_w);
if (!args_has(args, 's')) {
src_w = dst_w;
if (args_has(self->args, 'D')) { if (args_has(self->args, 'D')) {
src_wl = dst_wl;
src_w = dst_w;
src_wp = TAILQ_NEXT(dst_wp, entry); src_wp = TAILQ_NEXT(dst_wp, entry);
if (src_wp == NULL) if (src_wp == NULL)
src_wp = TAILQ_FIRST(&dst_w->panes); src_wp = TAILQ_FIRST(&dst_w->panes);
} else if (args_has(self->args, 'U')) { } else if (args_has(self->args, 'U')) {
src_wl = dst_wl;
src_w = dst_w;
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
return (CMD_RETURN_NORMAL);
} else {
src_wl = cmd_find_pane(cmdq, args_get(args, 's'), NULL, &src_wp);
if (src_wl == NULL)
return (CMD_RETURN_ERROR);
src_w = src_wl->window;
} }
server_unzoom_window(src_w); server_unzoom_window(src_w);

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -29,36 +29,37 @@
enum cmd_retval cmd_swap_window_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_swap_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_swap_window_entry = { const struct cmd_entry cmd_swap_window_entry = {
"swap-window", "swapw", .name = "swap-window",
"ds:t:", 0, 0, .alias = "swapw",
"[-d] " CMD_SRCDST_WINDOW_USAGE,
0, .args = { "ds:t:", 0, 0 },
NULL, .usage = "[-d] " CMD_SRCDST_WINDOW_USAGE,
NULL,
cmd_swap_window_exec .sflag = CMD_WINDOW_MARKED,
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_swap_window_exec
}; };
enum cmd_retval enum cmd_retval
cmd_swap_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd_swap_window_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args;
const char *target_src, *target_dst;
struct session *src, *dst; struct session *src, *dst;
struct session_group *sg_src, *sg_dst; struct session_group *sg_src, *sg_dst;
struct winlink *wl_src, *wl_dst; struct winlink *wl_src, *wl_dst;
struct window *w; struct window *w;
target_src = args_get(args, 's'); wl_src = cmdq->state.sflag.wl;
if ((wl_src = cmd_find_window(cmdq, target_src, &src)) == NULL) src = cmdq->state.sflag.s;
return (CMD_RETURN_ERROR);
target_dst = args_get(args, 't');
if ((wl_dst = cmd_find_window(cmdq, target_dst, &dst)) == NULL)
return (CMD_RETURN_ERROR);
sg_src = session_group_find(src); sg_src = session_group_find(src);
wl_dst = cmdq->state.tflag.wl;
dst = cmdq->state.tflag.s;
sg_dst = session_group_find(dst); sg_dst = session_group_find(dst);
if (src != dst &&
sg_src != NULL && sg_dst != NULL && sg_src == sg_dst) { if (src != dst && sg_src != NULL && sg_dst != NULL &&
sg_src == sg_dst) {
cmdq_error(cmdq, "can't move window, sessions are grouped"); cmdq_error(cmdq, "can't move window, sessions are grouped");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -27,35 +27,22 @@
* Switch client to a different session. * Switch client to a different session.
*/ */
void cmd_switch_client_key_binding(struct cmd *, int);
enum cmd_retval cmd_switch_client_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_switch_client_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_switch_client_entry = { const struct cmd_entry cmd_switch_client_entry = {
"switch-client", "switchc", .name = "switch-client",
"lc:npt:r", 0, 0, .alias = "switchc",
"[-lnpr] [-c target-client] [-t target-session]",
CMD_READONLY,
cmd_switch_client_key_binding,
NULL,
cmd_switch_client_exec
};
void .args = { "lc:Enpt:rT:", 0, 0 },
cmd_switch_client_key_binding(struct cmd *self, int key) .usage = "[-Elnpr] [-c target-client] [-t target-session] "
{ "[-T key-table]",
self->args = args_create(0);
switch (key) { .cflag = CMD_CLIENT,
case '(': .tflag = CMD_SESSION_WITHPANE,
args_set(self->args, 'p', NULL);
break; .flags = CMD_READONLY,
case ')': .exec = cmd_switch_client_exec
args_set(self->args, 'n', NULL); };
break;
case 'L':
args_set(self->args, 'l', NULL);
break;
}
}
enum cmd_retval enum cmd_retval
cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq) cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
@ -65,23 +52,29 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
#else #else
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct cmd_state *state = &cmdq->state;
struct session *s; struct client *c = state->c;
struct session *s = cmdq->state.tflag.s;
struct window_pane *wp;
const char *tablename, *update;
struct key_table *table;
if ((c = cmd_find_client(cmdq, args_get(args, 'c'), 0)) == NULL) if (args_has(args, 'r'))
c->flags ^= CLIENT_READONLY;
tablename = args_get(args, 'T');
if (tablename != NULL) {
table = key_bindings_get_table(tablename, 0);
if (table == NULL) {
cmdq_error(cmdq, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
if (args_has(args, 'r')) {
if (c->flags & CLIENT_READONLY) {
c->flags &= ~CLIENT_READONLY;
cmdq_info(cmdq, "made client writable");
} else {
c->flags |= CLIENT_READONLY;
cmdq_info(cmdq, "made client read-only");
} }
table->references++;
key_bindings_unref_table(c->keytable);
c->keytable = table;
return (CMD_RETURN_NORMAL);
} }
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"); cmdq_error(cmdq, "can't find next session");
@ -95,24 +88,42 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
} 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;
else
s = NULL;
if (s == NULL) { if (s == NULL) {
cmdq_error(cmdq, "can't find last session"); cmdq_error(cmdq, "can't find last session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else if (cmdq->client == NULL)
s = cmd_find_session(cmdq, args_get(args, 't'), 0); return (CMD_RETURN_NORMAL);
if (s == NULL)
return (CMD_RETURN_ERROR);
if (c->session != NULL) s = state->tflag.s;
if (state->tflag.wl != NULL) {
wp = state->tflag.wp;
if (wp != NULL)
window_set_active_pane(wp->window, wp);
session_set_current(s, state->tflag.wl);
}
}
if (c != NULL && !args_has(args, 'E')) {
update = options_get_string(s->options, "update-environment");
environ_update(update, c->environ, s->environ);
}
if (c->session != NULL && c->session != s)
c->last_session = c->session; c->last_session = c->session;
c->session = s; c->session = s;
session_update_activity(s); server_client_set_key_table(c, NULL);
status_timer_start(c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
recalculate_sizes(); recalculate_sizes();
server_check_unattached(); server_check_unattached();
server_redraw_client(c); server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS; s->curw->flags &= ~WINLINK_ALERTFLAGS;
alerts_check_session(s);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
#endif #endif

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -26,65 +26,80 @@
* Unbind key from command. * Unbind key from command.
*/ */
enum cmd_retval cmd_unbind_key_check(struct args *);
enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmd_q *);
enum cmd_retval cmd_unbind_key_table(struct cmd *, struct cmd_q *, int); enum cmd_retval cmd_unbind_key_mode_table(struct cmd *, struct cmd_q *,
key_code);
const struct cmd_entry cmd_unbind_key_entry = { const struct cmd_entry cmd_unbind_key_entry = {
"unbind-key", "unbind", .name = "unbind-key",
"acnt:", 0, 1, .alias = "unbind",
"[-acn] [-t key-table] key",
0,
NULL,
cmd_unbind_key_check,
cmd_unbind_key_exec
};
enum cmd_retval .args = { "acnt:T:", 0, 1 },
cmd_unbind_key_check(struct args *args) .usage = "[-acn] [-t mode-table] [-T key-table] key",
{
if (args_has(args, 'a') && args->argc != 0) .flags = 0,
return (CMD_RETURN_ERROR); .exec = cmd_unbind_key_exec
if (!args_has(args, 'a') && args->argc != 1) };
return (CMD_RETURN_ERROR);
return (CMD_RETURN_NORMAL);
}
enum cmd_retval enum cmd_retval
cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct key_binding *bd; key_code key;
int key; const char *tablename;
if (!args_has(args, 'a')) { if (!args_has(args, 'a')) {
if (args->argc != 1) {
cmdq_error(cmdq, "missing key");
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 || key == KEYC_UNKNOWN) {
cmdq_error(cmdq, "unknown key: %s", args->argv[0]); cmdq_error(cmdq, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else } else {
key = KEYC_NONE; if (args->argc != 0) {
cmdq_error(cmdq, "key given with -a");
return (CMD_RETURN_ERROR);
}
key = KEYC_UNKNOWN;
}
if (args_has(args, 't')) if (args_has(args, 't'))
return (cmd_unbind_key_table(self, cmdq, key)); return (cmd_unbind_key_mode_table(self, cmdq, key));
if (key == KEYC_NONE) { if (key == KEYC_UNKNOWN) {
while (!RB_EMPTY(&key_bindings)) { tablename = args_get(args, 'T');
bd = RB_ROOT(&key_bindings); if (tablename == NULL) {
key_bindings_remove(bd->key); key_bindings_remove_table("root");
key_bindings_remove_table("prefix");
return (CMD_RETURN_NORMAL);
} }
if (key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(cmdq, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR);
}
key_bindings_remove_table(tablename);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (!args_has(args, 'n')) if (args_has(args, 'T')) {
key |= KEYC_PREFIX; tablename = args_get(args, 'T');
key_bindings_remove(key); if (key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(cmdq, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'n'))
tablename = "root";
else
tablename = "prefix";
key_bindings_remove(tablename, key);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
enum cmd_retval enum cmd_retval
cmd_unbind_key_table(struct cmd *self, struct cmd_q *cmdq, int key) cmd_unbind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, key_code key)
{ {
struct args *args = self->args; struct args *args = self->args;
const char *tablename; const char *tablename;
@ -97,7 +112,7 @@ cmd_unbind_key_table(struct cmd *self, struct cmd_q *cmdq, int key)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (key == KEYC_NONE) { if (key == KEYC_UNKNOWN) {
while (!RB_EMPTY(mtab->tree)) { while (!RB_EMPTY(mtab->tree)) {
mbind = RB_ROOT(mtab->tree); mbind = RB_ROOT(mtab->tree);
RB_REMOVE(mode_key_tree, mtab->tree, mbind); RB_REMOVE(mode_key_tree, mtab->tree, mbind);

View File

@ -1,70 +0,0 @@
/* $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).
*/
enum cmd_retval cmd_unlink_window_exec(struct cmd *, struct cmd_q *);
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
};
enum cmd_retval
cmd_unlink_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
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(cmdq, args_get(args, 't'), &s)) == NULL)
return (CMD_RETURN_ERROR);
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) {
cmdq_error(cmdq, "window is only linked to one session");
return (CMD_RETURN_ERROR);
}
server_unlink_window(s, wl);
recalculate_sizes();
return (CMD_RETURN_NORMAL);
}

View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net>
@ -31,18 +31,20 @@
enum cmd_retval cmd_wait_for_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_wait_for_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_wait_for_entry = { const struct cmd_entry cmd_wait_for_entry = {
"wait-for", "wait", .name = "wait-for",
"LSU", 1, 1, .alias = "wait",
"[-LSU] channel",
0, .args = { "LSU", 1, 1 },
NULL, .usage = "[-L|-S|-U] channel",
NULL,
cmd_wait_for_exec .flags = 0,
.exec = cmd_wait_for_exec
}; };
struct wait_channel { struct wait_channel {
const char *name; const char *name;
int locked; int locked;
int woken;
TAILQ_HEAD(, cmd_q) waiters; TAILQ_HEAD(, cmd_q) waiters;
TAILQ_HEAD(, cmd_q) lockers; TAILQ_HEAD(, cmd_q) lockers;
@ -71,6 +73,46 @@ enum cmd_retval cmd_wait_for_lock(struct cmd_q *, const char *,
enum cmd_retval cmd_wait_for_unlock(struct cmd_q *, const char *, enum cmd_retval cmd_wait_for_unlock(struct cmd_q *, const char *,
struct wait_channel *); struct wait_channel *);
struct wait_channel *cmd_wait_for_add(const char *);
void cmd_wait_for_remove(struct wait_channel *wc);
struct wait_channel *
cmd_wait_for_add(const char *name)
{
struct wait_channel *wc;
wc = xmalloc(sizeof *wc);
wc->name = xstrdup(name);
wc->locked = 0;
wc->woken = 0;
TAILQ_INIT(&wc->waiters);
TAILQ_INIT(&wc->lockers);
RB_INSERT(wait_channels, &wait_channels, wc);
log_debug("add wait channel %s", wc->name);
return (wc);
}
void
cmd_wait_for_remove(struct wait_channel *wc)
{
if (wc->locked)
return;
if (!TAILQ_EMPTY(&wc->waiters) || !wc->woken)
return;
log_debug("remove wait channel %s", wc->name);
RB_REMOVE(wait_channels, &wait_channels, wc);
free((void *)wc->name);
free(wc);
}
enum cmd_retval enum cmd_retval
cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq) cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
@ -91,15 +133,20 @@ cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
} }
enum cmd_retval enum cmd_retval
cmd_wait_for_signal(struct cmd_q *cmdq, const char *name, cmd_wait_for_signal(__unused struct cmd_q *cmdq, const char *name,
struct wait_channel *wc) struct wait_channel *wc)
{ {
struct cmd_q *wq, *wq1; struct cmd_q *wq, *wq1;
if (wc == NULL || TAILQ_EMPTY(&wc->waiters)) { if (wc == NULL)
cmdq_error(cmdq, "no waiting clients on %s", name); wc = cmd_wait_for_add(name);
return (CMD_RETURN_ERROR);
if (TAILQ_EMPTY(&wc->waiters) && !wc->woken) {
log_debug("signal wait channel %s, no waiters", wc->name);
wc->woken = 1;
return (CMD_RETURN_NORMAL);
} }
log_debug("signal wait channel %s, with waiters", wc->name);
TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) { TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) {
TAILQ_REMOVE(&wc->waiters, wq, waitentry); TAILQ_REMOVE(&wc->waiters, wq, waitentry);
@ -107,12 +154,7 @@ cmd_wait_for_signal(struct cmd_q *cmdq, const char *name,
cmdq_continue(wq); cmdq_continue(wq);
} }
if (!wc->locked) { cmd_wait_for_remove(wc);
RB_REMOVE(wait_channels, &wait_channels, wc);
free((void*) wc->name);
free(wc);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@ -120,19 +162,22 @@ enum cmd_retval
cmd_wait_for_wait(struct cmd_q *cmdq, const char *name, cmd_wait_for_wait(struct cmd_q *cmdq, const char *name,
struct wait_channel *wc) struct wait_channel *wc)
{ {
if (cmdq->client == NULL || cmdq->client->session != NULL) { struct client *c = cmdq->client;
if (c == NULL || c->session != NULL) {
cmdq_error(cmdq, "not able to wait"); cmdq_error(cmdq, "not able to wait");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (wc == NULL) { if (wc == NULL)
wc = xmalloc(sizeof *wc); wc = cmd_wait_for_add(name);
wc->name = xstrdup(name);
wc->locked = 0; if (wc->woken) {
TAILQ_INIT(&wc->waiters); log_debug("wait channel %s already woken (%p)", wc->name, c);
TAILQ_INIT(&wc->lockers); cmd_wait_for_remove(wc);
RB_INSERT(wait_channels, &wait_channels, wc); return (CMD_RETURN_NORMAL);
} }
log_debug("wait channel %s not woken (%p)", wc->name, c);
TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry); TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry);
cmdq->references++; cmdq->references++;
@ -149,14 +194,8 @@ cmd_wait_for_lock(struct cmd_q *cmdq, const char *name,
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (wc == NULL) { if (wc == NULL)
wc = xmalloc(sizeof *wc); wc = cmd_wait_for_add(name);
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) { if (wc->locked) {
TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry); TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry);
@ -185,13 +224,31 @@ cmd_wait_for_unlock(struct cmd_q *cmdq, const char *name,
cmdq_continue(wq); cmdq_continue(wq);
} else { } else {
wc->locked = 0; wc->locked = 0;
if (TAILQ_EMPTY(&wc->waiters)) { cmd_wait_for_remove(wc);
RB_REMOVE(wait_channels, &wait_channels, wc);
free((void*) wc->name);
free(wc);
}
} }
return (CMD_RETURN_NORMAL); 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);
}
wc->woken = 1;
TAILQ_FOREACH_SAFE(wq, &wc->lockers, waitentry, wq1) {
TAILQ_REMOVE(&wc->lockers, wq, waitentry);
if (!cmdq_free(wq))
cmdq_continue(wq);
}
wc->locked = 0;
cmd_wait_for_remove(wc);
}
}

1347
cmd.c

File diff suppressed because it is too large Load Diff

414
colour.c
View File

@ -1,4 +1,4 @@
/* $Id$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -29,91 +29,305 @@
* of the 256 colour palette. * of the 256 colour palette.
*/ */
/* An RGB colour. */
struct colour_rgb { struct colour_rgb {
u_char i;
u_char r; u_char r;
u_char g; u_char g;
u_char b; u_char b;
}; };
/* 256 colour RGB table, generated on first use. */ const struct colour_rgb colour_from_256[] = {
struct colour_rgb *colour_rgb_256; { 0, 0x00, 0x00, 0x00 }, { 1, 0x00, 0x00, 0x5f },
{ 2, 0x00, 0x00, 0x87 }, { 3, 0x00, 0x00, 0xaf },
{ 4, 0x00, 0x00, 0xd7 }, { 5, 0x00, 0x00, 0xff },
{ 6, 0x00, 0x5f, 0x00 }, { 7, 0x00, 0x5f, 0x5f },
{ 8, 0x00, 0x5f, 0x87 }, { 9, 0x00, 0x5f, 0xaf },
{ 10, 0x00, 0x5f, 0xd7 }, { 11, 0x00, 0x5f, 0xff },
{ 12, 0x00, 0x87, 0x00 }, { 13, 0x00, 0x87, 0x5f },
{ 14, 0x00, 0x87, 0x87 }, { 15, 0x00, 0x87, 0xaf },
{ 16, 0x00, 0x87, 0xd7 }, { 17, 0x00, 0x87, 0xff },
{ 18, 0x00, 0xaf, 0x00 }, { 19, 0x00, 0xaf, 0x5f },
{ 20, 0x00, 0xaf, 0x87 }, { 21, 0x00, 0xaf, 0xaf },
{ 22, 0x00, 0xaf, 0xd7 }, { 23, 0x00, 0xaf, 0xff },
{ 24, 0x00, 0xd7, 0x00 }, { 25, 0x00, 0xd7, 0x5f },
{ 26, 0x00, 0xd7, 0x87 }, { 27, 0x00, 0xd7, 0xaf },
{ 28, 0x00, 0xd7, 0xd7 }, { 29, 0x00, 0xd7, 0xff },
{ 30, 0x00, 0xff, 0x00 }, { 31, 0x00, 0xff, 0x5f },
{ 32, 0x00, 0xff, 0x87 }, { 33, 0x00, 0xff, 0xaf },
{ 34, 0x00, 0xff, 0xd7 }, { 35, 0x00, 0xff, 0xff },
{ 36, 0x5f, 0x00, 0x00 }, { 37, 0x5f, 0x00, 0x5f },
{ 38, 0x5f, 0x00, 0x87 }, { 39, 0x5f, 0x00, 0xaf },
{ 40, 0x5f, 0x00, 0xd7 }, { 41, 0x5f, 0x00, 0xff },
{ 42, 0x5f, 0x5f, 0x00 }, { 43, 0x5f, 0x5f, 0x5f },
{ 44, 0x5f, 0x5f, 0x87 }, { 45, 0x5f, 0x5f, 0xaf },
{ 46, 0x5f, 0x5f, 0xd7 }, { 47, 0x5f, 0x5f, 0xff },
{ 48, 0x5f, 0x87, 0x00 }, { 49, 0x5f, 0x87, 0x5f },
{ 50, 0x5f, 0x87, 0x87 }, { 51, 0x5f, 0x87, 0xaf },
{ 52, 0x5f, 0x87, 0xd7 }, { 53, 0x5f, 0x87, 0xff },
{ 54, 0x5f, 0xaf, 0x00 }, { 55, 0x5f, 0xaf, 0x5f },
{ 56, 0x5f, 0xaf, 0x87 }, { 57, 0x5f, 0xaf, 0xaf },
{ 58, 0x5f, 0xaf, 0xd7 }, { 59, 0x5f, 0xaf, 0xff },
{ 60, 0x5f, 0xd7, 0x00 }, { 61, 0x5f, 0xd7, 0x5f },
{ 62, 0x5f, 0xd7, 0x87 }, { 63, 0x5f, 0xd7, 0xaf },
{ 64, 0x5f, 0xd7, 0xd7 }, { 65, 0x5f, 0xd7, 0xff },
{ 66, 0x5f, 0xff, 0x00 }, { 67, 0x5f, 0xff, 0x5f },
{ 68, 0x5f, 0xff, 0x87 }, { 69, 0x5f, 0xff, 0xaf },
{ 70, 0x5f, 0xff, 0xd7 }, { 71, 0x5f, 0xff, 0xff },
{ 72, 0x87, 0x00, 0x00 }, { 73, 0x87, 0x00, 0x5f },
{ 74, 0x87, 0x00, 0x87 }, { 75, 0x87, 0x00, 0xaf },
{ 76, 0x87, 0x00, 0xd7 }, { 77, 0x87, 0x00, 0xff },
{ 78, 0x87, 0x5f, 0x00 }, { 79, 0x87, 0x5f, 0x5f },
{ 80, 0x87, 0x5f, 0x87 }, { 81, 0x87, 0x5f, 0xaf },
{ 82, 0x87, 0x5f, 0xd7 }, { 83, 0x87, 0x5f, 0xff },
{ 84, 0x87, 0x87, 0x00 }, { 85, 0x87, 0x87, 0x5f },
{ 86, 0x87, 0x87, 0x87 }, { 87, 0x87, 0x87, 0xaf },
{ 88, 0x87, 0x87, 0xd7 }, { 89, 0x87, 0x87, 0xff },
{ 90, 0x87, 0xaf, 0x00 }, { 91, 0x87, 0xaf, 0x5f },
{ 92, 0x87, 0xaf, 0x87 }, { 93, 0x87, 0xaf, 0xaf },
{ 94, 0x87, 0xaf, 0xd7 }, { 95, 0x87, 0xaf, 0xff },
{ 96, 0x87, 0xd7, 0x00 }, { 97, 0x87, 0xd7, 0x5f },
{ 98, 0x87, 0xd7, 0x87 }, { 99, 0x87, 0xd7, 0xaf },
{ 100, 0x87, 0xd7, 0xd7 }, { 101, 0x87, 0xd7, 0xff },
{ 102, 0x87, 0xff, 0x00 }, { 103, 0x87, 0xff, 0x5f },
{ 104, 0x87, 0xff, 0x87 }, { 105, 0x87, 0xff, 0xaf },
{ 106, 0x87, 0xff, 0xd7 }, { 107, 0x87, 0xff, 0xff },
{ 108, 0xaf, 0x00, 0x00 }, { 109, 0xaf, 0x00, 0x5f },
{ 110, 0xaf, 0x00, 0x87 }, { 111, 0xaf, 0x00, 0xaf },
{ 112, 0xaf, 0x00, 0xd7 }, { 113, 0xaf, 0x00, 0xff },
{ 114, 0xaf, 0x5f, 0x00 }, { 115, 0xaf, 0x5f, 0x5f },
{ 116, 0xaf, 0x5f, 0x87 }, { 117, 0xaf, 0x5f, 0xaf },
{ 118, 0xaf, 0x5f, 0xd7 }, { 119, 0xaf, 0x5f, 0xff },
{ 120, 0xaf, 0x87, 0x00 }, { 121, 0xaf, 0x87, 0x5f },
{ 122, 0xaf, 0x87, 0x87 }, { 123, 0xaf, 0x87, 0xaf },
{ 124, 0xaf, 0x87, 0xd7 }, { 125, 0xaf, 0x87, 0xff },
{ 126, 0xaf, 0xaf, 0x00 }, { 127, 0xaf, 0xaf, 0x5f },
{ 128, 0xaf, 0xaf, 0x87 }, { 129, 0xaf, 0xaf, 0xaf },
{ 130, 0xaf, 0xaf, 0xd7 }, { 131, 0xaf, 0xaf, 0xff },
{ 132, 0xaf, 0xd7, 0x00 }, { 133, 0xaf, 0xd7, 0x5f },
{ 134, 0xaf, 0xd7, 0x87 }, { 135, 0xaf, 0xd7, 0xaf },
{ 136, 0xaf, 0xd7, 0xd7 }, { 137, 0xaf, 0xd7, 0xff },
{ 138, 0xaf, 0xff, 0x00 }, { 139, 0xaf, 0xff, 0x5f },
{ 140, 0xaf, 0xff, 0x87 }, { 141, 0xaf, 0xff, 0xaf },
{ 142, 0xaf, 0xff, 0xd7 }, { 143, 0xaf, 0xff, 0xff },
{ 144, 0xd7, 0x00, 0x00 }, { 145, 0xd7, 0x00, 0x5f },
{ 146, 0xd7, 0x00, 0x87 }, { 147, 0xd7, 0x00, 0xaf },
{ 148, 0xd7, 0x00, 0xd7 }, { 149, 0xd7, 0x00, 0xff },
{ 150, 0xd7, 0x5f, 0x00 }, { 151, 0xd7, 0x5f, 0x5f },
{ 152, 0xd7, 0x5f, 0x87 }, { 153, 0xd7, 0x5f, 0xaf },
{ 154, 0xd7, 0x5f, 0xd7 }, { 155, 0xd7, 0x5f, 0xff },
{ 156, 0xd7, 0x87, 0x00 }, { 157, 0xd7, 0x87, 0x5f },
{ 158, 0xd7, 0x87, 0x87 }, { 159, 0xd7, 0x87, 0xaf },
{ 160, 0xd7, 0x87, 0xd7 }, { 161, 0xd7, 0x87, 0xff },
{ 162, 0xd7, 0xaf, 0x00 }, { 163, 0xd7, 0xaf, 0x5f },
{ 164, 0xd7, 0xaf, 0x87 }, { 165, 0xd7, 0xaf, 0xaf },
{ 166, 0xd7, 0xaf, 0xd7 }, { 167, 0xd7, 0xaf, 0xff },
{ 168, 0xd7, 0xd7, 0x00 }, { 169, 0xd7, 0xd7, 0x5f },
{ 170, 0xd7, 0xd7, 0x87 }, { 171, 0xd7, 0xd7, 0xaf },
{ 172, 0xd7, 0xd7, 0xd7 }, { 173, 0xd7, 0xd7, 0xff },
{ 174, 0xd7, 0xff, 0x00 }, { 175, 0xd7, 0xff, 0x5f },
{ 176, 0xd7, 0xff, 0x87 }, { 177, 0xd7, 0xff, 0xaf },
{ 178, 0xd7, 0xff, 0xd7 }, { 179, 0xd7, 0xff, 0xff },
{ 180, 0xff, 0x00, 0x00 }, { 181, 0xff, 0x00, 0x5f },
{ 182, 0xff, 0x00, 0x87 }, { 183, 0xff, 0x00, 0xaf },
{ 184, 0xff, 0x00, 0xd7 }, { 185, 0xff, 0x00, 0xff },
{ 186, 0xff, 0x5f, 0x00 }, { 187, 0xff, 0x5f, 0x5f },
{ 188, 0xff, 0x5f, 0x87 }, { 189, 0xff, 0x5f, 0xaf },
{ 190, 0xff, 0x5f, 0xd7 }, { 191, 0xff, 0x5f, 0xff },
{ 192, 0xff, 0x87, 0x00 }, { 193, 0xff, 0x87, 0x5f },
{ 194, 0xff, 0x87, 0x87 }, { 195, 0xff, 0x87, 0xaf },
{ 196, 0xff, 0x87, 0xd7 }, { 197, 0xff, 0x87, 0xff },
{ 198, 0xff, 0xaf, 0x00 }, { 199, 0xff, 0xaf, 0x5f },
{ 200, 0xff, 0xaf, 0x87 }, { 201, 0xff, 0xaf, 0xaf },
{ 202, 0xff, 0xaf, 0xd7 }, { 203, 0xff, 0xaf, 0xff },
{ 204, 0xff, 0xd7, 0x00 }, { 205, 0xff, 0xd7, 0x5f },
{ 206, 0xff, 0xd7, 0x87 }, { 207, 0xff, 0xd7, 0xaf },
{ 208, 0xff, 0xd7, 0xd7 }, { 209, 0xff, 0xd7, 0xff },
{ 210, 0xff, 0xff, 0x00 }, { 211, 0xff, 0xff, 0x5f },
{ 212, 0xff, 0xff, 0x87 }, { 213, 0xff, 0xff, 0xaf },
{ 214, 0xff, 0xff, 0xd7 }, { 215, 0xff, 0xff, 0xff },
{ 216, 0x08, 0x08, 0x08 }, { 217, 0x12, 0x12, 0x12 },
{ 218, 0x1c, 0x1c, 0x1c }, { 219, 0x26, 0x26, 0x26 },
{ 220, 0x30, 0x30, 0x30 }, { 221, 0x3a, 0x3a, 0x3a },
{ 222, 0x44, 0x44, 0x44 }, { 223, 0x4e, 0x4e, 0x4e },
{ 224, 0x58, 0x58, 0x58 }, { 225, 0x62, 0x62, 0x62 },
{ 226, 0x6c, 0x6c, 0x6c }, { 227, 0x76, 0x76, 0x76 },
{ 228, 0x80, 0x80, 0x80 }, { 229, 0x8a, 0x8a, 0x8a },
{ 230, 0x94, 0x94, 0x94 }, { 231, 0x9e, 0x9e, 0x9e },
{ 232, 0xa8, 0xa8, 0xa8 }, { 233, 0xb2, 0xb2, 0xb2 },
{ 234, 0xbc, 0xbc, 0xbc }, { 235, 0xc6, 0xc6, 0xc6 },
{ 236, 0xd0, 0xd0, 0xd0 }, { 237, 0xda, 0xda, 0xda },
{ 238, 0xe4, 0xe4, 0xe4 }, { 239, 0xee, 0xee, 0xee },
};
const struct colour_rgb colour_to_256[] = {
{ 0, 0x00, 0x00, 0x00 }, { 1, 0x00, 0x00, 0x5f },
{ 2, 0x00, 0x00, 0x87 }, { 3, 0x00, 0x00, 0xaf },
{ 4, 0x00, 0x00, 0xd7 }, { 5, 0x00, 0x00, 0xff },
{ 6, 0x00, 0x5f, 0x00 }, { 7, 0x00, 0x5f, 0x5f },
{ 8, 0x00, 0x5f, 0x87 }, { 9, 0x00, 0x5f, 0xaf },
{ 10, 0x00, 0x5f, 0xd7 }, { 11, 0x00, 0x5f, 0xff },
{ 12, 0x00, 0x87, 0x00 }, { 13, 0x00, 0x87, 0x5f },
{ 14, 0x00, 0x87, 0x87 }, { 15, 0x00, 0x87, 0xaf },
{ 16, 0x00, 0x87, 0xd7 }, { 17, 0x00, 0x87, 0xff },
{ 18, 0x00, 0xaf, 0x00 }, { 19, 0x00, 0xaf, 0x5f },
{ 20, 0x00, 0xaf, 0x87 }, { 21, 0x00, 0xaf, 0xaf },
{ 22, 0x00, 0xaf, 0xd7 }, { 23, 0x00, 0xaf, 0xff },
{ 24, 0x00, 0xd7, 0x00 }, { 25, 0x00, 0xd7, 0x5f },
{ 26, 0x00, 0xd7, 0x87 }, { 27, 0x00, 0xd7, 0xaf },
{ 28, 0x00, 0xd7, 0xd7 }, { 29, 0x00, 0xd7, 0xff },
{ 30, 0x00, 0xff, 0x00 }, { 31, 0x00, 0xff, 0x5f },
{ 32, 0x00, 0xff, 0x87 }, { 33, 0x00, 0xff, 0xaf },
{ 34, 0x00, 0xff, 0xd7 }, { 35, 0x00, 0xff, 0xff },
{ 216, 0x08, 0x08, 0x08 }, { 217, 0x12, 0x12, 0x12 },
{ 218, 0x1c, 0x1c, 0x1c }, { 219, 0x26, 0x26, 0x26 },
{ 220, 0x30, 0x30, 0x30 }, { 221, 0x3a, 0x3a, 0x3a },
{ 222, 0x44, 0x44, 0x44 }, { 223, 0x4e, 0x4e, 0x4e },
{ 224, 0x58, 0x58, 0x58 }, { 36, 0x5f, 0x00, 0x00 },
{ 37, 0x5f, 0x00, 0x5f }, { 38, 0x5f, 0x00, 0x87 },
{ 39, 0x5f, 0x00, 0xaf }, { 40, 0x5f, 0x00, 0xd7 },
{ 41, 0x5f, 0x00, 0xff }, { 42, 0x5f, 0x5f, 0x00 },
{ 43, 0x5f, 0x5f, 0x5f }, { 44, 0x5f, 0x5f, 0x87 },
{ 45, 0x5f, 0x5f, 0xaf }, { 46, 0x5f, 0x5f, 0xd7 },
{ 47, 0x5f, 0x5f, 0xff }, { 48, 0x5f, 0x87, 0x00 },
{ 49, 0x5f, 0x87, 0x5f }, { 50, 0x5f, 0x87, 0x87 },
{ 51, 0x5f, 0x87, 0xaf }, { 52, 0x5f, 0x87, 0xd7 },
{ 53, 0x5f, 0x87, 0xff }, { 54, 0x5f, 0xaf, 0x00 },
{ 55, 0x5f, 0xaf, 0x5f }, { 56, 0x5f, 0xaf, 0x87 },
{ 57, 0x5f, 0xaf, 0xaf }, { 58, 0x5f, 0xaf, 0xd7 },
{ 59, 0x5f, 0xaf, 0xff }, { 60, 0x5f, 0xd7, 0x00 },
{ 61, 0x5f, 0xd7, 0x5f }, { 62, 0x5f, 0xd7, 0x87 },
{ 63, 0x5f, 0xd7, 0xaf }, { 64, 0x5f, 0xd7, 0xd7 },
{ 65, 0x5f, 0xd7, 0xff }, { 66, 0x5f, 0xff, 0x00 },
{ 67, 0x5f, 0xff, 0x5f }, { 68, 0x5f, 0xff, 0x87 },
{ 69, 0x5f, 0xff, 0xaf }, { 70, 0x5f, 0xff, 0xd7 },
{ 71, 0x5f, 0xff, 0xff }, { 225, 0x62, 0x62, 0x62 },
{ 226, 0x6c, 0x6c, 0x6c }, { 227, 0x76, 0x76, 0x76 },
{ 228, 0x80, 0x80, 0x80 }, { 72, 0x87, 0x00, 0x00 },
{ 73, 0x87, 0x00, 0x5f }, { 74, 0x87, 0x00, 0x87 },
{ 75, 0x87, 0x00, 0xaf }, { 76, 0x87, 0x00, 0xd7 },
{ 77, 0x87, 0x00, 0xff }, { 78, 0x87, 0x5f, 0x00 },
{ 79, 0x87, 0x5f, 0x5f }, { 80, 0x87, 0x5f, 0x87 },
{ 81, 0x87, 0x5f, 0xaf }, { 82, 0x87, 0x5f, 0xd7 },
{ 83, 0x87, 0x5f, 0xff }, { 84, 0x87, 0x87, 0x00 },
{ 85, 0x87, 0x87, 0x5f }, { 86, 0x87, 0x87, 0x87 },
{ 87, 0x87, 0x87, 0xaf }, { 88, 0x87, 0x87, 0xd7 },
{ 89, 0x87, 0x87, 0xff }, { 90, 0x87, 0xaf, 0x00 },
{ 91, 0x87, 0xaf, 0x5f }, { 92, 0x87, 0xaf, 0x87 },
{ 93, 0x87, 0xaf, 0xaf }, { 94, 0x87, 0xaf, 0xd7 },
{ 95, 0x87, 0xaf, 0xff }, { 96, 0x87, 0xd7, 0x00 },
{ 97, 0x87, 0xd7, 0x5f }, { 98, 0x87, 0xd7, 0x87 },
{ 99, 0x87, 0xd7, 0xaf }, { 100, 0x87, 0xd7, 0xd7 },
{ 101, 0x87, 0xd7, 0xff }, { 102, 0x87, 0xff, 0x00 },
{ 103, 0x87, 0xff, 0x5f }, { 104, 0x87, 0xff, 0x87 },
{ 105, 0x87, 0xff, 0xaf }, { 106, 0x87, 0xff, 0xd7 },
{ 107, 0x87, 0xff, 0xff }, { 229, 0x8a, 0x8a, 0x8a },
{ 230, 0x94, 0x94, 0x94 }, { 231, 0x9e, 0x9e, 0x9e },
{ 232, 0xa8, 0xa8, 0xa8 }, { 108, 0xaf, 0x00, 0x00 },
{ 109, 0xaf, 0x00, 0x5f }, { 110, 0xaf, 0x00, 0x87 },
{ 111, 0xaf, 0x00, 0xaf }, { 112, 0xaf, 0x00, 0xd7 },
{ 113, 0xaf, 0x00, 0xff }, { 114, 0xaf, 0x5f, 0x00 },
{ 115, 0xaf, 0x5f, 0x5f }, { 116, 0xaf, 0x5f, 0x87 },
{ 117, 0xaf, 0x5f, 0xaf }, { 118, 0xaf, 0x5f, 0xd7 },
{ 119, 0xaf, 0x5f, 0xff }, { 120, 0xaf, 0x87, 0x00 },
{ 121, 0xaf, 0x87, 0x5f }, { 122, 0xaf, 0x87, 0x87 },
{ 123, 0xaf, 0x87, 0xaf }, { 124, 0xaf, 0x87, 0xd7 },
{ 125, 0xaf, 0x87, 0xff }, { 126, 0xaf, 0xaf, 0x00 },
{ 127, 0xaf, 0xaf, 0x5f }, { 128, 0xaf, 0xaf, 0x87 },
{ 129, 0xaf, 0xaf, 0xaf }, { 130, 0xaf, 0xaf, 0xd7 },
{ 131, 0xaf, 0xaf, 0xff }, { 132, 0xaf, 0xd7, 0x00 },
{ 133, 0xaf, 0xd7, 0x5f }, { 134, 0xaf, 0xd7, 0x87 },
{ 135, 0xaf, 0xd7, 0xaf }, { 136, 0xaf, 0xd7, 0xd7 },
{ 137, 0xaf, 0xd7, 0xff }, { 138, 0xaf, 0xff, 0x00 },
{ 139, 0xaf, 0xff, 0x5f }, { 140, 0xaf, 0xff, 0x87 },
{ 141, 0xaf, 0xff, 0xaf }, { 142, 0xaf, 0xff, 0xd7 },
{ 143, 0xaf, 0xff, 0xff }, { 233, 0xb2, 0xb2, 0xb2 },
{ 234, 0xbc, 0xbc, 0xbc }, { 235, 0xc6, 0xc6, 0xc6 },
{ 236, 0xd0, 0xd0, 0xd0 }, { 144, 0xd7, 0x00, 0x00 },
{ 145, 0xd7, 0x00, 0x5f }, { 146, 0xd7, 0x00, 0x87 },
{ 147, 0xd7, 0x00, 0xaf }, { 148, 0xd7, 0x00, 0xd7 },
{ 149, 0xd7, 0x00, 0xff }, { 150, 0xd7, 0x5f, 0x00 },
{ 151, 0xd7, 0x5f, 0x5f }, { 152, 0xd7, 0x5f, 0x87 },
{ 153, 0xd7, 0x5f, 0xaf }, { 154, 0xd7, 0x5f, 0xd7 },
{ 155, 0xd7, 0x5f, 0xff }, { 156, 0xd7, 0x87, 0x00 },
{ 157, 0xd7, 0x87, 0x5f }, { 158, 0xd7, 0x87, 0x87 },
{ 159, 0xd7, 0x87, 0xaf }, { 160, 0xd7, 0x87, 0xd7 },
{ 161, 0xd7, 0x87, 0xff }, { 162, 0xd7, 0xaf, 0x00 },
{ 163, 0xd7, 0xaf, 0x5f }, { 164, 0xd7, 0xaf, 0x87 },
{ 165, 0xd7, 0xaf, 0xaf }, { 166, 0xd7, 0xaf, 0xd7 },
{ 167, 0xd7, 0xaf, 0xff }, { 168, 0xd7, 0xd7, 0x00 },
{ 169, 0xd7, 0xd7, 0x5f }, { 170, 0xd7, 0xd7, 0x87 },
{ 171, 0xd7, 0xd7, 0xaf }, { 172, 0xd7, 0xd7, 0xd7 },
{ 173, 0xd7, 0xd7, 0xff }, { 174, 0xd7, 0xff, 0x00 },
{ 175, 0xd7, 0xff, 0x5f }, { 176, 0xd7, 0xff, 0x87 },
{ 177, 0xd7, 0xff, 0xaf }, { 178, 0xd7, 0xff, 0xd7 },
{ 179, 0xd7, 0xff, 0xff }, { 237, 0xda, 0xda, 0xda },
{ 238, 0xe4, 0xe4, 0xe4 }, { 239, 0xee, 0xee, 0xee },
{ 180, 0xff, 0x00, 0x00 }, { 181, 0xff, 0x00, 0x5f },
{ 182, 0xff, 0x00, 0x87 }, { 183, 0xff, 0x00, 0xaf },
{ 184, 0xff, 0x00, 0xd7 }, { 185, 0xff, 0x00, 0xff },
{ 186, 0xff, 0x5f, 0x00 }, { 187, 0xff, 0x5f, 0x5f },
{ 188, 0xff, 0x5f, 0x87 }, { 189, 0xff, 0x5f, 0xaf },
{ 190, 0xff, 0x5f, 0xd7 }, { 191, 0xff, 0x5f, 0xff },
{ 192, 0xff, 0x87, 0x00 }, { 193, 0xff, 0x87, 0x5f },
{ 194, 0xff, 0x87, 0x87 }, { 195, 0xff, 0x87, 0xaf },
{ 196, 0xff, 0x87, 0xd7 }, { 197, 0xff, 0x87, 0xff },
{ 198, 0xff, 0xaf, 0x00 }, { 199, 0xff, 0xaf, 0x5f },
{ 200, 0xff, 0xaf, 0x87 }, { 201, 0xff, 0xaf, 0xaf },
{ 202, 0xff, 0xaf, 0xd7 }, { 203, 0xff, 0xaf, 0xff },
{ 204, 0xff, 0xd7, 0x00 }, { 205, 0xff, 0xd7, 0x5f },
{ 206, 0xff, 0xd7, 0x87 }, { 207, 0xff, 0xd7, 0xaf },
{ 208, 0xff, 0xd7, 0xd7 }, { 209, 0xff, 0xd7, 0xff },
{ 210, 0xff, 0xff, 0x00 }, { 211, 0xff, 0xff, 0x5f },
{ 212, 0xff, 0xff, 0x87 }, { 213, 0xff, 0xff, 0xaf },
{ 214, 0xff, 0xff, 0xd7 }, { 215, 0xff, 0xff, 0xff },
};
void colour_rgb_generate256(void); int colour_cmp_rgb(const void *, const void *);
u_int colour_rgb_distance(struct colour_rgb *, struct colour_rgb *);
int colour_rgb_find(struct colour_rgb *);
/* Generate 256 colour RGB table. */ /* Compare function for bsearch(). */
void int
colour_rgb_generate256(void) colour_cmp_rgb(const void *lhs0, const void *rhs0)
{ {
struct colour_rgb *rgb; const struct colour_rgb *lhs = lhs0, *rhs = rhs0;
u_int i, r, g, b;
/* if (lhs->r < rhs->r)
* Allocate the table. The first 16 colours are often changed by users return (-1);
* and terminals so don't include them. if (lhs->r > rhs->r)
*/ return (1);
colour_rgb_256 = xcalloc(240, sizeof *colour_rgb_256);
/* Add the colours first. */ if (lhs->g < rhs->g)
r = g = b = 0; return (-1);
for (i = 240; i > 24; i--) { if (lhs->g > rhs->g)
rgb = &colour_rgb_256[240 - i]; return (1);
if (r != 0) if (lhs->b < rhs->b)
rgb->r = (r * 40) + 55; return (-1);
if (g != 0) if (lhs->b > rhs->b)
rgb->g = (g * 40) + 55; return (1);
if (b != 0)
rgb->b = (b * 40) + 55;
b++; return (0);
if (b > 5) {
b = 0;
g++;
}
if (g > 5) {
g = 0;
r++;
}
}
/* Then add the greys. */
for (i = 24; i > 0; i--) {
rgb = &colour_rgb_256[240 - i];
rgb->r = 8 + (24 - i) * 10;
rgb->g = 8 + (24 - i) * 10;
rgb->b = 8 + (24 - i) * 10;
}
}
/* Get colour RGB distance. */
u_int
colour_rgb_distance(struct colour_rgb *rgb1, struct colour_rgb *rgb2)
{
int r, g, b;
r = rgb1->r - rgb2->r;
g = rgb1->g - rgb2->g;
b = rgb1->b - rgb2->b;
return (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_find_rgb(u_char r, u_char g, u_char b)
{ {
struct colour_rgb rgb = { .r = r, .g = g, .b = b }, *found;
u_int distance, lowest, colour, i; u_int distance, lowest, colour, i;
int dr, dg, db;
if (colour_rgb_256 == NULL) found = bsearch(&rgb, colour_to_256, nitems(colour_to_256),
colour_rgb_generate256(); sizeof colour_to_256[0], colour_cmp_rgb);
if (found != NULL)
return (16 + found->i);
colour = 16; colour = 16;
lowest = UINT_MAX; lowest = UINT_MAX;
for (i = 0; i < 240; i++) { for (i = 0; i < 240; i++) {
distance = colour_rgb_distance(&colour_rgb_256[i], rgb); dr = (int)colour_from_256[i].r - r;
dg = (int)colour_from_256[i].g - g;
db = (int)colour_from_256[i].b - b;
distance = dr * dr + dg * dg + db * db;
if (distance < lowest) { if (distance < lowest) {
lowest = distance; lowest = distance;
colour = 16 + i; colour = 16 + i;
@ -147,7 +361,7 @@ colour_tostring(int c)
static char s[32]; static char s[32];
if (c & 0x100) { if (c & 0x100) {
xsnprintf(s, sizeof s, "colour%u", c & ~0x100); xsnprintf(s, sizeof s, "colour%d", c & ~0x100);
return (s); return (s);
} }
@ -196,18 +410,18 @@ colour_fromstring(const char *s)
{ {
const char *errstr; const char *errstr;
const char *cp; const char *cp;
struct colour_rgb rgb;
int n; int n;
u_char r, g, b;
if (*s == '#' && strlen(s) == 7) { if (*s == '#' && strlen(s) == 7) {
for (cp = s + 1; isxdigit((u_char) *cp); cp++) for (cp = s + 1; isxdigit((u_char) *cp); cp++)
; ;
if (*cp != '\0') if (*cp != '\0')
return (-1); return (-1);
n = sscanf(s + 1, "%2hhx%2hhx%2hhx", &rgb.r, &rgb.g, &rgb.b); n = sscanf(s + 1, "%2hhx%2hhx%2hhx", &r, &g, &b);
if (n != 3) if (n != 3)
return (-1); return (-1);
return (colour_rgb_find(&rgb) | 0x100); return (colour_find_rgb(r, g, b) | 0x100);
} }
if (strncasecmp(s, "colour", (sizeof "colour") - 1) == 0) { if (strncasecmp(s, "colour", (sizeof "colour") - 1) == 0) {
@ -217,47 +431,39 @@ colour_fromstring(const char *s)
return (n | 0x100); return (n | 0x100);
} }
if (strcasecmp(s, "black") == 0 || (s[0] == '0' && s[1] == '\0')) if (strcasecmp(s, "black") == 0 || strcmp(s, "0") == 0)
return (0); return (0);
if (strcasecmp(s, "red") == 0 || (s[0] == '1' && s[1] == '\0')) if (strcasecmp(s, "red") == 0 || strcmp(s, "1") == 0)
return (1); return (1);
if (strcasecmp(s, "green") == 0 || (s[0] == '2' && s[1] == '\0')) if (strcasecmp(s, "green") == 0 || strcmp(s, "2") == 0)
return (2); return (2);
if (strcasecmp(s, "yellow") == 0 || (s[0] == '3' && s[1] == '\0')) if (strcasecmp(s, "yellow") == 0 || strcmp(s, "3") == 0)
return (3); return (3);
if (strcasecmp(s, "blue") == 0 || (s[0] == '4' && s[1] == '\0')) if (strcasecmp(s, "blue") == 0 || strcmp(s, "4") == 0)
return (4); return (4);
if (strcasecmp(s, "magenta") == 0 || (s[0] == '5' && s[1] == '\0')) if (strcasecmp(s, "magenta") == 0 || strcmp(s, "5") == 0)
return (5); return (5);
if (strcasecmp(s, "cyan") == 0 || (s[0] == '6' && s[1] == '\0')) if (strcasecmp(s, "cyan") == 0 || strcmp(s, "6") == 0)
return (6); return (6);
if (strcasecmp(s, "white") == 0 || (s[0] == '7' && s[1] == '\0')) if (strcasecmp(s, "white") == 0 || strcmp(s, "7") == 0)
return (7); return (7);
if (strcasecmp(s, "default") == 0 || (s[0] == '8' && s[1] == '\0')) if (strcasecmp(s, "default") == 0 || strcmp(s, "8") == 0)
return (8); return (8);
if (strcasecmp(s, "brightblack") == 0 || if (strcasecmp(s, "brightblack") == 0 || strcmp(s, "90") == 0)
(s[0] == '9' && s[1] == '0' && s[1] == '\0'))
return (90); return (90);
if (strcasecmp(s, "brightred") == 0 || if (strcasecmp(s, "brightred") == 0 || strcmp(s, "91") == 0)
(s[0] == '9' && s[1] == '1' && s[1] == '\0'))
return (91); return (91);
if (strcasecmp(s, "brightgreen") == 0 || if (strcasecmp(s, "brightgreen") == 0 || strcmp(s, "92") == 0)
(s[0] == '9' && s[1] == '2' && s[1] == '\0'))
return (92); return (92);
if (strcasecmp(s, "brightyellow") == 0 || if (strcasecmp(s, "brightyellow") == 0 || strcmp(s, "93") == 0)
(s[0] == '9' && s[1] == '3' && s[1] == '\0'))
return (93); return (93);
if (strcasecmp(s, "brightblue") == 0 || if (strcasecmp(s, "brightblue") == 0 || strcmp(s, "94") == 0)
(s[0] == '9' && s[1] == '4' && s[1] == '\0'))
return (94); return (94);
if (strcasecmp(s, "brightmagenta") == 0 || if (strcasecmp(s, "brightmagenta") == 0 || strcmp(s, "95") == 0)
(s[0] == '9' && s[1] == '5' && s[1] == '\0'))
return (95); return (95);
if (strcasecmp(s, "brightcyan") == 0 || if (strcasecmp(s, "brightcyan") == 0 || strcmp(s, "96") == 0)
(s[0] == '9' && s[1] == '6' && s[1] == '\0'))
return (96); return (96);
if (strcasecmp(s, "brightwhite") == 0 || if (strcasecmp(s, "brightwhite") == 0 || strcmp(s, "97") == 0)
(s[0] == '9' && s[1] == '7' && s[1] == '\0'))
return (97); return (97);
return (-1); return (-1);
} }
@ -287,29 +493,3 @@ 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

@ -1,5 +1,3 @@
/* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
* *
@ -23,6 +21,9 @@
#define __attribute__(a) #define __attribute__(a)
#endif #endif
#ifndef __unused
#define __unused __attribute__ ((__unused__))
#endif
#ifndef __dead #ifndef __dead
#define __dead __attribute__ ((__noreturn__)) #define __dead __attribute__ ((__noreturn__))
#endif #endif
@ -30,6 +31,10 @@
#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;
@ -121,6 +126,10 @@ 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
@ -152,13 +161,31 @@ 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 HAVE_BZERO #ifndef HOST_NAME_MAX
#undef bzero #define HOST_NAME_MAX 255
#define bzero(buf, len) memset(buf, 0, len); #endif
#ifndef HAVE_FLOCK
#define LOCK_SH 0
#define LOCK_EX 0
#define LOCK_NB 0
#define flock(fd, op) (0)
#endif #endif
#ifndef HAVE_CLOSEFROM #ifndef HAVE_CLOSEFROM
@ -198,6 +225,7 @@ int daemon(int, int);
#ifndef HAVE_B64_NTOP #ifndef HAVE_B64_NTOP
/* b64_ntop.c */ /* b64_ntop.c */
#undef b64_ntop /* for Cygwin */
int b64_ntop(const char *, size_t, char *, size_t); int b64_ntop(const char *, size_t, char *, size_t);
#endif #endif
@ -218,12 +246,32 @@ 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
#ifndef HAVE_REALLOCARRAY
/* reallocarray.c */
void *reallocarray(void *, size_t, size_t size);
#endif
#ifdef HAVE_GETOPT #ifdef HAVE_GETOPT
#include <getopt.h> #include <getopt.h>
#else #else

View File

@ -1,5 +1,3 @@
/* $Id$ */
/* /*
* Copyright (c) 2006 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2006 Nicholas Marriott <nicm@users.sourceforge.net>
* *
@ -56,10 +54,12 @@ vasprintf(char **ret, const char *fmt, va_list ap)
free(*ret); free(*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,4 +1,3 @@
/* $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,7 +1,6 @@
/* $Id$ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2013 Dagobert Michelsen
* 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
@ -16,28 +15,16 @@
* 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 <string.h>
#include "tmux.h" #include "tmux.h"
/* void
* Start the server and do nothing else. cfmakeraw(struct termios *tio)
*/
enum cmd_retval cmd_start_server_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_start_server_entry = {
"start-server", "start",
"", 0, 0,
"",
CMD_STARTSERVER,
NULL,
NULL,
cmd_start_server_exec
};
enum cmd_retval
cmd_start_server_exec(unused struct cmd *self, unused struct cmd_q *cmdq)
{ {
return (CMD_RETURN_NORMAL); tio->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
tio->c_oflag &= ~OPOST;
tio->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
tio->c_cflag &= ~(CSIZE|PARENB);
tio->c_cflag |= CS8;
} }

View File

@ -1,5 +1,3 @@
/* $Id$ */
/* /*
* Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
* *
@ -16,8 +14,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "tmux.h"
#ifndef HAVE_CLOSEFROM #ifndef HAVE_CLOSEFROM
#include <sys/types.h> #include <sys/types.h>
@ -49,6 +45,8 @@
# endif # endif
#endif #endif
#include "tmux.h"
#ifndef OPEN_MAX #ifndef OPEN_MAX
# define OPEN_MAX 256 # define OPEN_MAX 256
#endif #endif

View File

@ -1,4 +1,3 @@
/* $Id$ */
/* $OpenBSD: daemon.c,v 1.6 2005/08/08 08:05:33 espie Exp $ */ /* $OpenBSD: daemon.c,v 1.6 2005/08/08 08:05:33 espie Exp $ */
/*- /*-
* Copyright (c) 1990, 1993 * Copyright (c) 1990, 1993

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