1 Commits
2.3 ... 0.8

Author SHA1 Message Date
no_author
c23359e5d7 This commit was manufactured by cvs2svn to create tag 'TMUX_0_8'. 2009-04-21 20:10:23 +00:00
254 changed files with 21068 additions and 49052 deletions

20
.gitignore vendored
View File

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

View File

@@ -1,37 +0,0 @@
Bob Beck <beck@openbsd.org> beck <beck>
Claudio Jeker <claudio@openbsd.org> claudio <claudio>
Igor Sobrado <sobrado@openbsd.org> sobrado <sobrado>
Ingo Schwarze <schwarze@openbsd.org> schwarze <schwarze>
Jacek Masiulaniec <jacekm@openbsd.org> jacekm <jacekm>
Jason McIntyre <jmc@openbsd.org> jmc <jmc>
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>
Matthew Dempsky <matthew@openbsd.org> matthew <matthew>
Matthias Kilian <kili@openbsd.org> kili <kili>
Matthieu Herrb <matthieu@openbsd.org> matthieu <matthieu>
Michael McConville <mmcc@openbsd.org> mmcc <mmcc>
Miod Vallat <miod@openbsd.org> miod <miod>
Nicholas Marriott <nicholas.marriott@gmail.com> Nicholas Marriott <nicm@openbsd.org>
Nicholas Marriott <nicholas.marriott@gmail.com> nicm <nicm>
Nicholas Marriott <nicholas.marriott@gmail.com> no_author <no_author@example.org>
Okan Demirmen <okan@openbsd.org> okan <okan>
Philip Guenther <guenther@openbsd.org> guenther <guenther>
Pierre-Yves Ritschard <pyr@openbsd.org> pyr <pyr>
Ray Lai <ray@openbsd.org> ray <ray>
Ryan McBride <mcbride@openbsd.org> mcbride <mcbride>
Sebastian Benoit <benno@openbsd.org> benno <benno>
Sebastien Marie <semarie@openbsd.org> semarie <semarie>
Stefan Sperling <stsp@openbsd.org> stsp <stsp>
Stuart Henderson <sthen@openbsd.org> sthen <sthen>
Ted Unangst <tedu@openbsd.org> tedu <tedu>
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 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>

View File

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

874
CHANGES
View File

@@ -1,862 +1,3 @@
CHANGES FROM 2.2 to 2.3 29 September 2016
Incompatible Changes
====================
None.
Normal Changes
==============
* New option 'pane-border-status' to add text in the oane borders.
* Support for hooks on commands: 'after' and 'before' hooks.
* 'source-file' understands '-q' to supress errors for nonexistent files.
* Lots of UTF8 improvements, especially on MacOS.
* 'window-status-separator' understands #[] expansions.
* 'split-window' understands '-f' for performing a full-width split.
* Allow report count to be specified when using 'bind-key -R'.
* 'set -a' for appending to user options (@foo) is now supported.
* 'display-panes' can now accept a command to run, rather than always
selecting the pane.
CHANGES FROM 2.1 to 2.2 10 April 2016
Incompatible Changes
====================
* The format strings which referenced time have been removed. Instead:
#{t:window_activity}
can be used.
* Support for TMPDIR has been removed. Use TMUX_TMPDIR instead.
* UTF8 detection how happens automatically if the client supports it, hence
the:
mouse-utf8
utf8
options has been removed.
* The:
mouse_utf8_flag
format string has been removed.
* The -I option to show-messages has been removed. See:
#{t:start_time}
format option instead.
Normal Changes
==============
* Panes are unzoomed with selectp -LRUD
* New formats added:
#{scroll_position}
#{socket_path}
#{=10:...} -- limit to N characters (from the start)
#{=-10:...} -- limit to N characters (from the end)
#{t:...} -- used to format time-based formats
#{b:...} -- used to ascertain basename from string
#{d:...} -- used to ascertain dirname from string
#{s:...} -- used to perform substitutions on a string
* Job output is run via the format system, so formats work again
* If display-time is set to 0, then the indicators wait for a key to be
pressed.
* list-keys and list-commands can be run without starting the tmux server.
* kill-session learns -C to clear all alerts in all windows of the session.
* Support for hooks (internal for now), but hooks for the following have been
implemented:
alert-bell
alert-silence
alert-activity
client-attached
client-detached
client-resized
pane-died
pane-exited
* RGB (24bit) colour support. The 'Tc' flag must be set in the external TERM
entry (using terminal-overrides or a custom terminfo entry).
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_synchronized} format specifier has been added to be a conditional
format if a pane is in a synchronised mode (c.f. synchronize-panes)
* Tmux now runs under Cygwin natively.
* Formats can now be nested within each other and expanded accordingly.
* Added 'automatic-rename-format' option to allow the automatic rename
mechanism to use something other than the default of
#{pane_current_command}.
* new-session learnt '-c' to specify the starting directory for that session
and all subsequent windows therein.
* The session name is now shown in the message printed to the terminal when
a session is detached.
* Lots more format specifiers have been added.
* Server race conditions have been fixed; in particular commands are not run
until after the configuration file is read completely.
* Case insensitive searching in tmux's copy-mode is now possible.
* attach-session and switch-client learnt the '-t' option to accept a window
and/or a pane to use.
* Copy-mode is only exited if no selection is in progress.
* Paste key in copy-mode is now possible to enter text from the clipboard.
* status-interval set to '0' now works as intended.
* tmux now supports 256 colours running under fbterm.
* Many bug fixes!
CHANGES FROM 1.7 to 1.8, 26 March 2013
Incompatible Changes
====================
* layout redo/undo has been removed.
Normal Changes
==============
* Add halfpage up/down bindings to copy mode.
* Session choosing fixed to work with unattached sessions.
* New window options window-status-last-{attr,bg,fg} to denote the last
window which was active.
* Scrolling in copy-mode now scrolls the region without moving the mouse
cursor.
* run-shell learnt '-t' to specify the pane to use when displaying output.
* Support for middle-click pasting.
* choose-tree learns '-u' to start uncollapsed.
* select-window learnt '-T' to toggle to the last window if it's already
current.
* New session option 'assume-paste-time' for pasting text versus key-binding
actions.
* choose-* commands now work outside of an attached client.
* Aliases are now shown for list-commands command.
* Status learns about formats.
* Free-form options can be set with set-option if prepended with an '@'
sign.
* capture-pane learnt '-p' to send to stdout, and '-e' for capturing escape
sequences, and '-a' to capture the alternate screen, and '-P' to dump
pending output.
* Many new formats added (client_session, client_last_session, etc.)
* Control mode, which is a way for a client to send tmux commands.
Currently more useful to users of iterm2.
* resize-pane learnt '-x' and '-y' for absolute pane sizing.
* Config file loading now reports errors from all files which are loaded via
the 'source-file' command.
* 'copy-pipe' mode command to copy selection and pipe the selection to a
command.
* Panes can now emit focus notifications for certain applications
which use those.
* run-shell and if-shell now accept formats.
* resize-pane learnt '-Z' for zooming a pane temporarily.
* new-session learnt '-A' to make it behave like attach-session.
* set-option learnt '-o' to prevent setting an option which is already set.
* capture-pane and show-options learns '-q' to silence errors.
* New command 'wait-for' which blocks a client until woken up again.
* Resizing panes will now reflow the text inside them.
* Lots and lots of bug fixes, fixing memory-leaks, etc.
* Various manpage improvements.
CHANGES FROM 1.6 to 1.7, 13 October 2012
* tmux configuration files now support line-continuation with a "\" at the
end of a line.
* New option status-position to move the status line to the top or bottom of
the screen.
* Enforce history-limit option when clearing the screen.
* Give each window a unique id, like panes but prefixed with @.
* Add pane id to each pane in layout description (while still accepting
the old form).
* Provide defined ways to set the various default-path possibilities: ~
for home directory, . for server start directory, - for session start
directory and empty for the pane's working directory (the default). All
can also be used as part of a relative path (eg -/foo). Also provide -c
flags to neww and splitw to override default-path setting.
* Add -l flag to send-keys to send input literally (without translating
key names).
* Allow a single option to be specified to show-options to show just that
option.
* New command "move-pane" (like join-pane but allows the same window).
* join-pane and move-pane commands learn "-b" option to place the pane to
the left or above.
* Support for bracketed-paste mode.
* Allow send-keys command to accept hex values.
* Add locking around "start-server" to avoid race-conditions.
* break-pane learns -P/-F arguments for display formatting.
* set-option learns "-q" to make it quiet, and not print out anything.
* copy mode learns "wrap-search" option.
* Add a simple form of output rate limiting by counting the number of
certain C0 sequences (linefeeds, backspaces, carriage returns) and if it
exceeds a threshold (current default 250/millisecond), start to redraw
the pane every 100 milliseconds instead of making each change as it
comes. Two configuration options - c0-change-trigger and
c0-change-interval.
* find-window learns new flags: "-C", "-N", "-T" to match against either or
all of a window's content, name, or title. Defaults to all three options
if none specified.
* find-window automatically selects the appropriate pane for the found
matches.
* show-environment can now accept one option to show that environment value.
* Exit mouse mode when end-of-screen reached when scrolling with the mouse
wheel.
* select-layout learns -u and -U for layout history stacks.
* kill-window, detach-client, kill-session all learn "-a" option for
killing all but the current thing specified.
* move-window learns "-r" option to renumber window sequentially in a
session.
* New session option "renumber-windows" to automatically renumber windows in
a session when a window is closed. (see "move-window -r").
* Only enter copy-mode on scroll up.
* choose-* and list-* commands all use "-F" for format specifiers.
* When spawning external commands, the value from the "default-shell" option
is now used, rather than assuming /bin/sh.
* New choose-tree command to render window/sessions as a tree for selection.
* display-message learns new format options.
* For linked-windows across sessions, all flags for that window are now
cleared across sessions.
* Lots and lots of bug fixes, fixing memory-leaks, etc.
* Various manpage improvements.
CHANGES FROM 1.5 TO 1.6, 23 January 2012
* Extend the mode-mouse option to add a third choice which means the mouse
does not enter copy mode.
* Add a -r flag to switch-client to toggle the client read-only flag.
* Add pane-base-index option.
* Support \ for line continuation in the configuration file.
* Framework for more powerful formatting of command output and use it for
list-{panes,windows,sessions}. This allows more descriptive replacements
(such as #{session_name}) and conditionals.
* Mark dead panes with some text saying they are dead.
* Reject $SHELL if it is not a full path.
* Add -S option to refresh-client to redraw status line.
* Add an else clause for if-shell.
* Try to resolve relative paths for loadb and saveb (first, using client
working directory, if any, then default-path or session working directory).
* Support for \e[3J to clear the history and send the corresponding
terminfo code (E3) before locking.
* When in copy mode, make repeat count indicate buffer to replace, if used.
* Add screen*:XT to terminal-overrides for tmux-in-tmux.
* Status-line message attributes added.
* Move word-separators to be a session rather than window option.
* Change the way the working directory for new processes is discovered. If
default-path isn't empty, it is used. Otherwise, if a new window is created
from the command-line, the working directory of the client is used. If not,
platform specific code is used to retrieve the current working directory
of the process in the active pane. If that fails, the directory where the
session was created is used, instead.
* Do not change the current pane if both mouse-select-{pane,window} are
enabled.
* Add \033[s and \033[u to save and restore cursor position.
* Allow $HOME to be used as default-path.
* Add CNL and CPL escape sequences.
* Calculate last position correctly for UTF-8 wide characters.
* Add an option allow-rename to disable the window rename escape sequence.
* Attributes for each type of status-line alert (ie bell, content and
activity) added. Therefore, remove the superfluous options
window-status-alert-{attr,bg,fg}.
* Add a -R flag to send-keys to reset the terminal.
* Add strings to allow the aixterm bright colours to be used when
configuring colours.
* Drop the ability to have a list of keys in the prefix in favour of two
separate options, prefix and prefix2.
* Flag -2 added to send-prefix to send the secondary prefix key.
* Show pane size in top right of display panes mode.
* Some memory leaks plugged.
* More command-prompt editing improvements.
* Various manpage improvements.
* More Vi mode improvements.
CHANGES FROM 1.4 TO 1.5, 09 July 2011
* Support xterm mouse modes 1002 and 1003.
* Change from a per-session stack of buffers to one global stack. This renders
copy-buffer useless and makes buffer-limit now a server option.
* Fix most-recently-used choice by avoiding reset the activity timer for
unattached sessions every second.
* Add a -P option to new-window and split-window to print the new window or
pane index in target form (useful to pass it into other commands).
* Handle a # at the end of a replacement string (such as status-left)
correctly.
* Support for UTF-8 mouse input (\033[1005h) which was added in xterm 262.
If the new mouse-utf8 option is on, UTF-8 mouse input is enabled for all
UTF-8 terminals. The option defaults to on if LANG etc are set in the same
manner as the utf8 option.
* Support for HP-UX.
* Accept colours of the hex form #ffffff and translate to the nearest from the
xterm(1) 256-colour set.
* Clear the non-blocking IO flag (O_NONBLOCK) on the stdio file descriptors
before closing them (fixes things like "tmux ls && cat").
* Use TMPDIR if set.
* Fix next and previous session functions to actually work.
* Support -x and -y for new-session to specify the initial size of the window
if created detached with -d.
* Make bind-key accept characters with the top-bit-set and print them as octal.
* Set $TMUX without the session when background jobs are run.
* Simplify the way jobs work and drop the persist type, so all jobs are
fire-and-forget.
* Accept tcgetattr/tcsetattr(3) failure, fixes problems with fatal() if the
terminal disappears while locked.
* Add a -P option to detach to HUP the client's parent process (usually causing
it to exit as well).
* Support passing through escape sequences to the underlying terminal by using
DCS with a "tmux;" prefix.
* Prevent tiled producing a corrupt layout when only one column is needed.
* Give each pane created in a tmux server a unique id (starting from 0), put it
in the TMUX_PANE environment variable and accept it as a target.
* Allow a start and end line to be specified for capture-pane which may be
negative to capture part of the history.
* Add -a and -s options to lsp to list all panes in the server or session
respectively. Likewise add -s to lsw.
* Change -t on display-message to be target-pane for the #[A-Z] replacements
and add -c as target-client.
* The attach-session command now prefers the most recently used unattached
session.
* Add -s option to detach-client to detach all clients attached to a session.
* Add -t to list-clients.
* Change window with mouse wheel over status line if mouse-select-window is on.
* When mode-mouse is on, automatically enter copy mode when the mouse is
dragged or the mouse wheel is used. Also exit copy mode when the mouse wheel
is scrolled off the bottom.
* Provide #h character pair for short hostname (no domain).
* Don't use strnvis(3) for the title as it breaks UTF-8.
* Use the tsl and fsl terminfo(5) capabilities to update terminal title and
automatically fill them in on terminals with the XT capability (which means
their title setting is xterm-compatible).
* Add a new option, mouse-resize-pane. When on, panes may be resized by
dragging their borders.
* Fix crash by resetting last pane on {break,swap}-pane across windows.
* Add three new copy-mode commands - select-line, copy-line, copy-end-of-line.
* Support setting the xterm clipboard when copying from copy mode using the
xterm escape sequence for the purpose (if xterm is configured to allow it).
* Support xterm(1) cursor colour change sequences through terminfo(5) Cc
(set) and Cr (reset) extensions.
* Support DECSCUSR sequence to set the cursor style with two new terminfo(5)
extensions, Cs and Csr.
* Make the command-prompt custom prompts recognize the status-left option
character pairs.
* Add a respawn-pane command.
* Add a couple of extra xterm-style keys that gnome terminal provides.
* Allow the initial context on prompts to be set with the new -I option to
command-prompt. Include the current window and session name in the prompt
when renaming and add a new key binding ($) for rename session.
* Option bell-on-alert added to trigger the terminal bell when there is an
alert.
* Change the list-keys format so that it shows the keys using actual tmux
commands which should be able to be directly copied into the config file.
* Show full targets for lsp/lsw -a.
* Make confirm-before prompt customizable with -p option like command-prompt
and add the character pairs #W and #P to the default kill-{pane,window}
prompts.
* Avoid sending data to suspended/locked clients.
* Small memory leaks in error paths plugged.
* Vi mode improvements.
CHANGES FROM 1.3 TO 1.4, 27 December 2010
* Window bell reporting fixed.
* Show which pane is active in the list-panes output.
* Backoff reworked.
* Prevent the server from dying when switching into copy mode when already
in a different mode.
* Reset running jobs when the status line is enabled or disabled.
* Simplify xterm modifier detection.
* Avoid crashing in copy mode if the screen size is too small for the
indicator.
* Flags -n and -p added to switch-client.
* Use UTF-8 line drawing characters on UTF-8 terminals, thus fixing some
terminals (eg putty) which disable the vt100 ACS mode switching sequences
in UTF-8 mode. On terminals without ACS, use ASCII equivalents.
* New server option exit-unattached added.
* New session option destroy-unattached added.
* Fall back on normal session choice method if $TMUX exists but is invalid
rather than rejecting.
* Mark repeating keys with "(repeat)" in the key list.
* When removing a pane, don't change the active pane unless the active pane
is actually the one being removed.
* New command last-pane added.
* AIX fixes.
* Flag -a added to unbind-key.
* Add XAUTHORITY to update-environment.
* More info regarding window and pane flags is now shown in list-*.
* If VISUAL or EDITOR contains "vi" configure mode-keys and status-key to vi.
* New window option monitor-silence and session option visual-silence added.
* In the built-in layouts distribute the panes more evenly.
* Set the default value of main-pane-width to 80 instead of 81.
* Command-line flag -V added.
* Instead of keeping a per-client prompt history make it global.
* Fix rectangle copy to behave like emacs (the cursor is not part of the
selection on the right edge but on the left it is).
* Flag -l added to switch-client.
* Retrieve environment variables from the global environment rather than
getenv(3), thus allowing them to be updated during the configuration file.
* New window options other-pane-{height,width} added.
* More minor bugs fixed and manpage improvements.
CHANGES FROM 1.2 TO 1.3, 18 July 2010
* New input parser.
* Flags to move through panes -UDLR added to select-pane.
* Commands up-pane, and down-pane removed, since equivalent behaviour is now
available through the target flag (-t:+ and -t:-).
* Jump-forward/backward in copy move (based on vi's F, and f commands).
* Make paste-buffer accept a pane as a target.
* Flag -a added to new-window to insert a window after an existing one, moving
windows up if necessary.
* Merge more mode into copy mode.
* Run job commands explicitly in the global environment (which can be modified
with setenv -g), rather than with the environment tmux started with.
* Use the machine's hostname as the default title, instead of an empty string.
* Prevent double free if the window option remain-on-exit is set.
* Key string conversions rewritten.
* Mark zombie windows as dead in the choose-window list.
* Tiled layout added.
* Signal handling reworked.
* Reset SIGCHLD after fork to fix problems with some shells.
* Select-prompt command removed. Therefore, bound ' to command-prompt -p index
"select-window -t:%%" by default.
* Catch SIGHUP and terminate if running as a client, thus avoiding clients from
being left hanging around when, for instance, a SSH session is disconnected.
* Solaris 9 fixes (such as adding compat {get,set}env(3) code).
* Accept none instead of default for attributes.
* Window options window-status-alert-{alert,bg,fg} added.
* Flag -s added to the paste-buffer command to specify a custom separator.
* Allow dragging to make a selection in copy mode if the mode-mouse option is
set.
* Support the mouse scroll wheel.
* Make pipe-pane accept special character sequences (eg #I).
* Fix problems with window sizing when starting tmux from .xinitrc.
* Give tmux sockets (but not the containing folder) group permissions.
* Extend the target flags (ie -t) to accept an offset (for example -t:+2), and
make it wrap windows, and panes.
* New command choose-buffer added.
* New server option detach-on-destroy to set what happens to a client when the
session it is attached to is destroyed. If on (default), the client is
detached. Otherwise, the client is switched to the most recently active of
the remaining sessions.
* The commands load-buffer, and save-buffer now accept a dash (-) as the file
to read from stdin, or write to stdout.
* Custom layouts added.
* Additional code reduction, bug fixes, and manpage enhancements.
CHANGES FROM 1.1 TO 1.2, 10 March 2010
* Switch to libevent.
* Emulate the ri (reverse index) capability, ergo allowing tmux to at least
start on Sun consoles (TERM=sun, or sun-color).
* Assign each entry a number, or lowercase letter in choose mode, and accept
that as a shortcut key.
* Permit top-bit-set characters to be entered in the status line.
* Mark no-prefix keys with (no prefix), rather than [] in list-keys.
* New command show-messages (alias showmsgs), and new session option
message-limit, to show a per-client log of status lines messages up to the
number defined by message-limit.
* Do not interpret #() for display-message to avoid leaking commands.
* New window options window-status-format, and window-status-current-format to
control the format of each window in the status line.
* Add a -p flag to display-message to print the output, instead of displaying
it in the status line.
* Emulate il1, dl1, ich1 to run with vt100 feature set.
* New command capture-pane (alias capturep) to copy the entire pane contents
to a paste buffer.
* Avoid duplicating code by adding a -w flag to set-option, and show-options to
set, and show window options. The commands set-window-option, and
show-window-options are now aliases.
* Panes can now be referred to as top, bottom, top-left, etc.
* Add server-wide options, which can be set with set-option -s, and shown with
show-options -s.
* New server option quiet (like -q from the command line).
* New server option escape-time to set the timeout used to detect if escapes
are alone, part of a function key, or meta sequence.
* New session options pane-active-border-bg, pane-active-border-fg,
pane-border-bg, and pane-border-fg to set pane colours.
* Make split-window accept a pane target, instead of a window.
* New command join-pane (alias joinp) to split, and move an existing pane into
the space (the opposite of break-pane), thus simplifying calls to
split-window, followed by move-window.
* Permit S- prefix on keys for shift when the terminal/terminfo supports them.
* Window targets (-t flag) can now refer to the last window (!), next (+), and
previous (-) window by number.
* Mode keys to jump to the bottom/top of history, end of the next word, scroll
up/down, and reverse search in copy mode.
* New session option display-panes-active-colour to display the active pane in
a different colour with the display-panes command.
* Read the socket path from $TMUX if it's present, and -L, and -S are not
given.
* Vi-style mode keys B, W, and E to navigate between words in copy mode.
* Start in more mode when configuration file errors are detected.
* Rectangle copy support added.
* If attach-session was specified with the -r flag, make the client read-only.
* Per-window alternate-screen option.
* Make load-buffer work with FIFOs.
* New window option word-separators to set the characters considered as word
separators in copy mode.
* Permit keys in copy mode to be prefixed by a repeat count, entered with [1-9]
in vi mode, or M-[1-9] in emacs mode.
* utf8 improvements.
* As usual, additional code reduction, bug fixes, and manpage enhancements.
CHANGES FROM 1.0 TO 1.1, 05 November 2009
* New run-shell (alias run) command to run an external command without a
window, capture it's stdout, and send it to output mode.
* Ability to define multiple prefix keys.
* Internal locking mechanism removed. Instead, detach each client and run the
external command specified in the new session option lock-command (by default
lock -np), thus allowing the system password to be used.
* set-password command, and -U command line flag removed per the above change.
* Add support for -c command line flag to execute a shell command.
* New lock-client (alias lockc), and lock-session (alias locks) commands to
lock a particular client, or all clients attached to a session.
* Support C-n/C-p/C-v/M-v with emacs keys in choice mode.
* Use : for goto line rather than g in vi mode.
* Try to guess which client to use when no target client was specified. Finds
the current session, and if only one client is present, use it. Otherwise,
return the most recently used client.
* Make C-Down/C-Up in copy mode scroll the screen down/up one line without
moving the cursor.
* Scroll mode superseded by copy mode.
* New synchronize-panes window option to send all input to all other panes in
the same window.
* New lock-server session option to lock, when off (on by default), each
session when it has been idle for the lock-after-time setting. When on, the
entire server locks when all sessions have been idle for their individual
lock-after-time setting.
* Add support for grouped sessions which have independent name, options,
current window, but where the linked windows are synchronized (ie creating,
killing windows are mirrored between the sessions). A grouped session may be
created by passing -t to new-session.
* New mouse-select-pane session option to select the current pane with the
mouse.
* Queue, and run commands in the background for if-shell, status-left,
status-right, and #() by starting each once every status-interval. Adds the
capability to call some programs which would previously cause the server to
hang (eg sleep/tmux). It also avoids running commands excessively (ie if used
multiple times, it will be run only once).
* When a window is zombified and automatic-rename is on, append [dead] to the
name.
* Split list-panes (alias lsp) off from list-windows.
* New pipe-pane (alias pipep) to redirect a pane output to an external command.
* Support for automatic-renames for Solaris.
* Permit attributes to be turned off in #[] by prefixing with no (eg nobright).
* Add H/M/L in vi mode, and M-R/M-r in emacs to move the cursor to the top,
middle, and bottom of the screen.
* -a option added to kill-pane to kill all except current pane.
* The -d command line flag is now gone (can be replaced by terminal-overrides).
Just use op/AX to detect default colours.
* input/tty/utf8 improvements.
* xterm-keys rewrite.
* Additional code reduction, and bug fixes.
CHANGES FROM 0.9 TO 1.0, 20 Sept 2009
* Option to alter the format of the window title set by tmux.
* Backoff for a while after multiple incorrect password attempts.
* Quick display of pane numbers (C-b q).
* Better choose-window, choose-session commands and a new choose-client command.
* Option to request multiple responses when using command-prompt.
* Improved environment handling.
* Combine wrapped lines when pasting.
* Option to override terminal settings (terminal-overrides).
* Use the full range of ACS characters for drawing pane separator lines.
* Customisable mode keys.
* Status line colour options, with embedded colours in status-left/right, and
an option to centre the window list.
* Much improved layouts, including both horizontal and vertical splitting.
* Optional visual bell, activity and content indications.
* Set the utf8 and status-utf8 options when the server is started with -u.
* display-message command to show a message in the status line, by default some
information about the current window.
* Improved current process detection on NetBSD.
* unlink-window -k is now the same as kill-window.
* attach-session now works from inside tmux.
* A system-wide configuration file, /etc/tmux.conf.
* A number of new commands in copy mode, including searching.
* Panes are now specified using the target (-t) notation.
* -t now accepts fnmatch(3) patterns and looks for prefixes.
* Translate \r into \n when pasting.
* Support for binding commands to keys without the prefix key
* Support for alternate screen (terminfo smcup/rmcup).
* Maintain data that goes off screen after reducing the window size, so it can
be restored when the size is increased again.
* New if-shell command to test a shell command before running a tmux command.
* tmux now works as the shell.
* Man page reorganisation.
* Many minor additions, much code tidying and several bug fixes.
CHANGES FROM 0.8 TO 0.9, 01 July 2009
* Major changes to build infrastructure: cleanup of makefiles and addition
of a configure script.
* monitor-content window option to monitor a window for a specific fnmatch(3)
pattern. The find-window command also now accepts fnmatch(3) patterns.
* previous-layout and select-layout commands, and a main-horizontal layout.
* Recreate the server socket on SIGUSR1.
* clear-history command.
* Use ACS line drawing characters for pane separator lines.
* UTF-8 improvements, and code to detect UTF-8 support by looking at
environment variables.
* The resize-pane-up and resize-pane-down commands are now merged together
into a new resize-pane command with -U and -D flags.
* confirm-before command to request a yes/no answer before executing dangerous
commands.
* Status line bug fixes, support for UTF-8 (status-utf8 option), and a key to
paste from the paste buffer.
* Support for some additional escape sequences and terminal features, including
better support for insert mode and tab stops.
* Improved window resizing behaviour, modelled after xterm.
* Some code reduction and a number of miscellaneous bug fixes.
================================================================================
On 01 June 2009, tmux was imported into the OpenBSD base system. From this date
onward changes are logged as part of the normal CVS commit message to either
OpenBSD or SourceForge CVS. This file will be updated to contain a summary of
major changes with each release, and to mention important configuration or
command syntax changes during development.
The list of older changes is below.
================================================================================
21 May 2009
* stat(2) files before trying to load them to avoid problems, for example
with "source-file /dev/zero".
19 May 2009
* Try to guess if the window is UTF-8 by outputting a three-byte UTF-8 wide
character and seeing how much the cursor moves. Currently tries to figure out
if this works by some stupid checks on the terminal, these need to be
rethought. Also might be better using a width 1 character rather than width 2.
* If LANG contains "UTF-8", assume the terminal supports UTF-8, on the grounds
that anyone who configures it probably wants UTF-8. Not certain if this is
a perfect idea but let's see if it causes any problems.
* New window option: monitor-content. Searches for a string in a window and if
it matches, highlight the status line.
18 May 2009
* main-horizontal layout and main-pane-height option to match vertical.
* New window option main-pane-width to set the width of the large left pane with
main-vertical (was left-vertical) layout.
* Lots of layout cleanup. manual layout is now manual-vertical.
16 May 2009
* select-layout command and a few default key bindings (M-0, M-1, M-2, M-9) to
select layouts.
* Recreate server socket on SIGUSR1, per SF feature request 2792533.
14 May 2009
* Keys in status line (p in vi mode, M-y in emacs) to paste the first line
of the upper paste buffer. Suggested by Dan Colish.
* clear-history command to clear a pane's history.
* Don't force wrapping with \n when asked, let the cursor code figure it out.
Should fix terminals which use this to detect line breaks.
* Major cleanup and restructuring of build infrastructure. Still separate files
for GNU and BSD make, but they are now hugely simplified at the expense of
adding a configure script which must be run before make. Now build and
install with:
$ ./configure && make && sudo make install
04 May 2009
* Use ACS line drawing characters for pane separator lines.
30 April 2009
* Support command sequences without a space before the semicolon, for example
"neww; neww" now works as well as "neww ; neww". "neww;neww" is still an
error.
* previous-layout command.
* Display the layout name in window lists.
* Merge resize-pane-up and resize-pane-down into resize-pane with -U and -D
flags.
29 April 2009
* Get rid of compat/vis.* - only one function was used which is easily
replaced,and less compat code == good.
27 April 2009
* Avoid using the prompt history when the server is locked, and prevent any
input entered from being added to the client's prompt history.
* New command, confirm-before (alias confirm), which asks for confirmation
before executing a command. Bound "&" and "x" by default to confirm-before
"kill-window" and confirm-before "kill-pane", respectively.
23 April 2009
* Support NEL, yet another way of making newline. Fixes the output from some
Gentoo packaging thing. Reported by someone on SF then logs that allowed a
fix sent by tcunha.
* Use the xenl terminfo flag to detect early-wrap terminals like the FreeBSD
console. Many thanks for a very informative email from Christian Weisgerber.
21 April 2009
* tmux 0.8 released.
17 April 2009
* Remove the right number of characters from the buffer when escape then
@@ -1039,7 +180,7 @@ The list of older changes is below.
* -u flag to scroll-mode and copy-mode to start scrolled one page
up. scroll-mode -u is bound to prefix,page-up (ppage) by default.
* Allow status, mode and message attributes to be changed by three new options:
status-attr, mode-attr, message-attr. A comma-separated list is accepted
status-attr, mode-attr, message-attr. A comma-separataed list is accepted
containing: bright, dim, underscore, blink, reverse, hidden, italics, for
example:
@@ -1106,7 +247,7 @@ The list of older changes is below.
18 January 2009
* Unbreak UTF-8.
* -a flag to next-window and previous-window to select the next or previous
* -a flag to next-window and previous-window to select the next or previous
window with activity or bell. Bound to M-n and M-p.
* find-window command to search window names, titles and visible content (but
not history) for a string. If only one is found, the window is selected
@@ -1191,7 +332,7 @@ The list of older changes is below.
* Vertical window splitting. Currently can only split a window into two panes.
New split-window command splits (bound to ") and switch-pane command (bound to
o) switches between panes.
o) switches between panes.
close-pane, swap-pane commands are to follow. Also to come are pane resizing,
>2 panes, the ability to break a pane out to a full window and vice versa and
@@ -1210,7 +351,7 @@ The list of older changes is below.
* New option, lock-after-time. If there is no activity in the period specified
by this option (in seconds), tmux will lock the server. Default is 1800 (30
minutes), set to 0 to disable.
minutes), set to 0 to disable.
* Server locking. Two new commands: set-password to set a password (a
preencrypted password may be specified with -c); and lock-server to lock the
server until the password is entered. Also an additional command line flag,
@@ -2062,3 +1203,10 @@ The list of older changes is below.
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
customisation.
$Id: CHANGES,v 1.272 2009-04-17 12:36:21 nicm Exp $
LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr
LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms
LocalWords: dstidx srcname srcidx winlink lsw nabc sabc Exp Tiago Cunha dch
LocalWords: setw Chisnall renamew merdely eg Maier newname selectw neww Gass

21
COPYING
View File

@@ -1,21 +0,0 @@
THIS IS FOR INFORMATION ONLY, CODE IS UNDER THE LICENCE AT THE TOP OF ITS FILE.
The README, CHANGES, FAQ and TODO files are licensed under the ISC
license. Files under examples/ remain copyright their authors unless otherwise
stated in the file but permission has been received to distribute them with
tmux. All other files have a license and copyright notice at their start,
typically:
Copyright (c) <author>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

369
FAQ
View File

@@ -1,116 +1,33 @@
tmux frequently asked questions
******************************************************************************
* PLEASE NOTE: most display problems are due to incorrect TERM! Before *
* reporting problems make SURE that TERM settings are correct inside and *
* outside tmux. *
* *
* Inside tmux TERM must be "screen" or similar (such as "screen-256color"). *
* Don't bother reporting problems where it isn't! *
* *
* Outside, it must match your terminal: particularly, use "rxvt" for rxvt *
* and derivatives. *
******************************************************************************
* How is tmux different from GNU screen? What else does it offer?
* How is tmux different from GNU screen?
tmux offers several advantages over screen:
tmux and GNU screen have many similarities. Some of the main differences I am
aware of are (bearing in mind I haven't used screen for a few years now):
- a clearly-defined client-server model: windows are independent entities which
may be attached simultaneously to multiple sessions and viewed from multiple
clients (terminals), as well as moved freely between sessions within the same
tmux server;
- a consistent, well-documented command interface, with the same syntax
whether used interactively, as a key binding, or from the shell;
- easily scriptable from the shell;
- multiple paste buffers;
- choice of vi or emacs key layouts;
- an option to limit the window size;
- a more usable status line syntax, with the ability to display the first line
of output of a specific command;
- a cleaner, modern, easily extended, BSD-licensed codebase.
- tmux uses a client-server model. Each server has single Unix domain socket in
/tmp and within one server there are multiple sessions which may be attached
to multiple clients (terminals).
There are still a few features screen includes that tmux omits:
This has advantages, notably: windows may be linked simultaneously to
multiple sessions; windows may be moved freely between sessions; and a client
may be switched between sessions easily (C-b D). There is one major
disadvantage: if the server crashes, game over, all sessions die. In
practice, however, tmux is quite stable and gets more so as people report any
bugs they hit :-).
This model is different from screen, where typically each new screen instance
is independent. tmux supports the same behaviour by using multiple servers
with the -L option but it is not typically recommended.
- Different command interfaces. One of the goals of tmux is that the shell
should be easily usable as a scripting language - almost all tmux commands
can be used from the shell and behave identically whether used from the
shell, from a key binding or from the command prompt. Personally I also find
tmux's command interface much more consistent and clearer, but this is
subjective.
- tmux calls window names (what you see in the status line) "names", screen
calls them "titles".
- tmux has a multiple paste buffers. Not a major one but comes in handy quite a
lot.
- tmux supports automatically renaming windows to the running application
without gross hacks using escape sequences. Its even on by default.
- tmux has a choice of vi or emacs key layouts. Again, not major, but I use
emacs so if tmux did support only one key set it would be emacs and then all
the vi users would get humpy. Key bindings may be completely reconfigured in
any case.
- tmux has an option to limit the window size.
- tmux has search in windows (C-b f).
- The window split (pane) model is different. tmux has two objects, windows and
panes; screen has just windows. This difference has several implications:
* In screen you can have a window appear in several layouts, in tmux a pane
can only be in one window (fixing this is a big todo item but quite
invasive).
* tmux layouts are immutable and do not get changed unless you modify them.
* In tmux, all panes are closed when you kill a window.
* tmux panes do not have individual names, titles and so on.
I think tmux's model is much easier to manage and navigate within a window,
but breaking panes off from and joining them to windows is more clumsy.
tmux also has support for preset pane layouts.
- tmux's status line syntax is more readable and easier to use. I think it'd be
hard for anyone to argue with this. tmux doesn't support running a command
constantly and always using the last line of its output, commands must be run
again each time.
- tmux has modern, easily extended code. Again hard to argue screen is better
if you have looked at the code.
- tmux depends on libevent. I don't see this as a disadvantage: libevent is
small and portable, and on modern systems with current package management
systems dependencies are not an issue. libevent brings advantages in code
simplicity and performance.
- screen allows the window to be bigger than the terminal and can pan around
it. tmux limits the size to the largest attached client. This is a big todo
item for tmux but it is not trivial.
- screen has builtin serial and telnet support; this is bloat and is unlikely
to be added to tmux.
- Environment handling is different.
- tmux tends to be more demanding on the terminal so tends to show up terminal
and application bugs which screen does not.
- screen has wider platform support, for example IRIX, and for odd terminals.
- builtin serial and telnet support; this is bloat and is unlikely to be added
to tmux;
- wider platform support, for example IRIX and HP-UX, and for odd terminals.
* I found a bug! What do I do?
Check the latest version of tmux from Git to see if the problem is still
reproducible. Sometimes the length of time between releases means a lot of
fixes can be sitting in Git and the problem might already be fixed.
Please send bug reports by email to nicholas.marriott@gmail.com or
tmux-users@googlegroups.com. Please include as much of the following
information as possible:
Please send bug reports by email to nicm@users.sourceforge.net. Please
include as much of the following information as possible:
- the version of tmux you are running;
- the operating system you are using and its version;
@@ -123,19 +40,18 @@ information as possible:
* Why doesn't tmux do $x?
Please send feature requests by email to tmux-users@googlegroups.com.
Please send feature requests by email to nicm@users.sourceforge.net.
* Why do you use the screen terminal description inside tmux? It sucks.
* Why do you use the screen termcap inside tmux? It sucks.
It is already widely available. It is planned to change to something else such
as xterm-xfree86 at some point, if possible.
It is already widely available. It is planned to change to something else
such as xterm-color at some point, if possible.
* I don't see any colour in my terminal! Help!
On some platforms, common terminal descriptions such as xterm do not include
colour. screen ignores this, tmux does not. If the terminal emulator in use
supports colour, use a value for TERM which correctly lists this, such as
xterm-color.
On some platforms, common termcaps such as xterm do not include colour. screen
ignores this, tmux does not. If the terminal emulator in use supports colour,
use a termcap which correctly lists this, such as xterm-color.
* tmux freezes my terminal when I attach to a session. I even have to kill -9
the shell it was started from to recover!
@@ -165,31 +81,23 @@ default) to the new key. For example:
* How do I use UTF-8?
When running tmux in a UTF-8 capable terminal, UTF-8 must be turned on in tmux;
as of release 0.9, tmux attempts to autodetect a UTF-8-capable terminal by
checking the LC_ALL, LC_CTYPE and LANG environment variables. list-clients may
be used to check if this is detected correctly; if not, the -u command-line
flag may be specified when creating or attaching a client to a tmux session:
When running tmux in a UTF-8 capable terminal, two things must be done to
enable support. UTF-8 must be turned on in tmux; this may be done separately
for each tmux window or globally by setting the "utf8" flag:
$ tmux -u new
setw -g utf8 on
Since the 1.0 release, tmux will turn on UTF-8 related options automatically
(ie status-utf8, and utf8) if the above conditions are met.
And, as it is not possible to automatically detect that a terminal is UTF-8
capable, tmux must be told by passing the -u flag when creating or
attaching a client to a tmux session:
$ tmux -u new
* How do I use a 256 colour terminal?
Provided the underlying terminal supports 256 colours, it is usually sufficient
to add the following to ~/.tmux.conf:
set -g default-terminal "screen-256color"
Note that some platforms do not support "screen-256color" ("infocmp
screen-256color" will return an error) - in this case see the next entry in
this FAQ.
tmux attempts to detect a 256 colour terminal both by looking at the colors
terminfo entry and by looking for the string "256col" in the TERM environment
variable.
tmux will attempt to detect a 256 colour terminal both by looking at the Co
termcap entry and, as this is broken for some terminals such as xterm-256color,
by looking for the string "256col" in the termcap name.
If both these methods fail, the -2 flag may be passed to tmux when attaching
to a session to indicate the terminal supports 256 colours.
@@ -197,18 +105,22 @@ to a session to indicate the terminal supports 256 colours.
* vim or $otherprogram doesn't display 256 colours. What's up?
Some programs attempt to detect the number of colours a terminal is capable of
by checking the colors terminfo or Co termcap entry. However, this is not
reliable, and in any case is missing from the "screen" terminal description
used inside tmux.
by checking the Co termcap entry. However, this is not reliable, and in any
case is missing from the "screen" termcap used inside tmux.
There are two options (aside from using "screen-256color") to allow programs to
recognise they are running on a 256-colour terminal inside tmux:
There are three options to allow programs to recognise they are running on
a 256-colour terminal inside tmux:
- Manually force the application to use 256 colours always or if TERM is set to
screen. For vim, you can do this by overriding the t_Co option, see
http://vim.wikia.com/wiki/256_colors_in_vim.
- Creating a custom terminfo file that includes colors#256 in ~/.terminfo and
using it instead. These may be compiled with tic(1).
- If the platform includes it, using the "screen-256color" termcap (set
TERM=screen-256color). "infocmp screen-256color" can be used to check if this
is supported. It is not currently possible to set this globally inside tmux
but it may be done in a shell startup script by checking if TERM is screen
and exporting TERM=screen-256color instead.
- Creating a custom terminfo file that includes Co#256 in ~/.terminfo and using
it instead. These may be compiled with tic(1).
* How do I make Ctrl-PgUp and Ctrl-PgDn work in vim?
@@ -237,33 +149,6 @@ the ctrl (bit 5 set, for example ^[[5~ to ^[[5^) modifier in non-xterm(1) mode;
it may be possible to configure vim to accept these, an example of how to do so
would be welcome.
vim users may also want to set the "ttyfast" option inside tmux.
* 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?
There isn't a way to detect if a terminal supports setting the window title, so
@@ -301,154 +186,4 @@ Automatic window renaming may use a lot of CPU, particularly on slow computers:
if this is a problem, turn it off with "setw -g automatic-rename off". If this
doesn't fix it, please report the problem.
* I use PuTTY and my tmux window pane separators are all qqqqqqqqq's!
PuTTY is using a character set translation that doesn't support ACS line
drawing. With a Unicode font, try setting PuTTY to use a different translation
on the Window -> Translation configuration page. For example, change UTF-8 to
ISO-8859-1 or CP437. It may also be necessary to adjust the way PuTTY treats
line drawing characters in the lower part of the same configuration page.
* What is the best way to display the load average? Why no #L?
It isn't possible to get the load average portably in code and it is preferable
not to add portability goop. The following works on at least Linux, *BSD and OS
X:
uptime|awk '{split(substr($0, index($0, "load")), a, ":"); print a[2]}'
* How do I attach the same session to multiple clients but with a different
current window, like screen -x?
One or more of the windows can be linked into multiple sessions manually with
link-window, or a grouped session with all the windows can be created with
new-session -t.
* Ctrl and arrow keys doesn't work in putty! What do I do?
putty inverts the sense of the cursor key mode on ctrl, which is a bit hard for
tmux to detect properly. To get ctrl keys right, change the terminfo settings
so kUP5 (Ctrl-Up etc) are the adjusted versions, and disable smkx/rmkx so tmux
doesn't change the mode. For example with this line in .tmux.conf (assuming you
have TERM set to xterm):
set -g terminal-overrides "xterm*:kLFT5=\eOD:kRIT5=\eOC:kUP5=\eOA:kDN5=\eOB:smkx@:rmkx@"
Note that this will only work in tmux 1.2 and above.
* How can I blank the tmux window?
GNU screen has a feature whereby it will blank the screen after a period of
inactivity. To do the same thing in tmux, use the lock-command setting, for
example (with GNU bash):
set -g lock-command 'tput civis && read -s -n1'
This will remove the cursor and tell the shell to quit once a key has been
pressed. For zsh, use "read -s -k1".
In addition, it's possible to have both blanking and locking (for instance via
lock(1) or vlock(1)) by using the following:
bind x set lock-command '/usr/bin/vlock' \; lock-client \; set lock-command 'tput civis && read -s -n1'
* I don't see italics! Or less and vim show italics and reverse the wrong way round!
GNU screen does not support italics and the "screen" terminfo description uses
the italics escape sequence incorrectly.
As of tmux 2.1, if default-terminal is set to "screen" or matches "screen-*",
tmux will behave like screen and italics will be disabled.
To enable italics, create a new terminfo entry called "tmux" (some platforms
may already have this, you can check with "infocmp tmux"):
$ cat <<EOF|tic -x -
tmux|tmux terminal multiplexer,
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:
set -g default-terminal "tmux"
If using urxvt, make sure you have an italics capable font enabled. for
example, add to ~/.Xdefaults:
urxvt.italicFont: xft:Bitstream Vera Sans Mono:italic:autohint=true
* How can I make tmux use my terminal's scrollback buffer?
Normally, tmux enables the terminal's "alternate screen". Most terminals (such
as xterm) do not save scrollback for the alternate screen. You might prefer
tmux to use the normal screen, so it uses your terminal's scrollback
buffer. This way, you can access the scrollback buffer as usual, for example
using the mouse wheel - although there is no guarantee output inside tmux will
always (or ever) be added to the scrollback.
You can make tmux use the normal screen by telling it that your terminal does
not have an alternate screen. Put the following in ~/.tmux.conf:
set -ga terminal-overrides ',xterm*:smcup@:rmcup@'
Adjust if your $TERM does not start with xterm.
tmux will still emulate the alternate screen for applications run under tmux,
so you don't really lose anything with this setting. The only disadvantage is
that when you exit tmux, it will not restore whatever was there before you
started.
* How do I see the default configuration?
Show the default session options by starting a new tmux server with no
configuration file:
$ tmux -Lfoo -f/dev/null start\; show -g
Or the default window options:
$ tmux -Lfoo -f/dev/null start\; show -gw
* How do I copy a selection from tmux to the system's clipboard?
When running in xterm(1), tmux can automatically send copied text to the
clipboard. This is controlled by the set-clipboard option and also needs this
X resource to be set:
XTerm*disallowedWindowOps: 20,21,SetXprop
For rxvt-unicode (urxvt), there is an unofficial Perl extension here:
http://anti.teamidiot.de/static/nei/*/Code/urxvt/
Otherwise a key binding for copy mode using xclip (or xsel) works:
bind -temacs-copy C-y copy-pipe "xclip -i >/dev/null"
Or for inside and outside copy mode with the prefix key:
bind C-y run -b "tmux save-buffer - | xclip -i"
On OS X, reattach-to-usernamespace lets pbcopy/pbpaste work:
https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard
* Why do I see dots around a session when I attach to it?
tmux limits the size of the window to the smallest attached session. If
it didn't do this then it would be impossible to see the entire window.
The dots mark the size of the window tmux can display.
To avoid this, detach all other clients when attaching:
$ tmux attach -d
Or from inside tmux by detaching individual clients with C-b D or all
using:
C-b : attach -d
$Id: FAQ,v 1.21 2009-03-31 23:17:28 nicm Exp $

144
GNUmakefile Normal file
View File

@@ -0,0 +1,144 @@
# $Id: GNUmakefile,v 1.82 2009-04-21 20:10:22 nicm Exp $
.PHONY: clean
PROG= tmux
VERSION= 0.8
DATE= $(shell date +%Y%m%d-%H%M)
#FDEBUG= 1
META?= \002
SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \
xmalloc.c xmalloc-debug.c input.c input-keys.c \
screen.c screen-write.c screen-redraw.c \
grid.c grid-view.c \
window.c session.c log.c client.c client-msg.c client-fn.c cfg.c \
key-string.c key-bindings.c resize.c arg.c mode-key.c \
layout.c cmd.c cmd-generic.c cmd-string.c cmd-list.c \
cmd-detach-client.c cmd-list-sessions.c cmd-new-window.c cmd-bind-key.c \
cmd-unbind-key.c cmd-previous-window.c cmd-last-window.c cmd-list-keys.c \
cmd-set-option.c cmd-rename-window.c cmd-select-window.c \
cmd-list-windows.c cmd-attach-session.c cmd-send-prefix.c \
cmd-refresh-client.c cmd-kill-window.c cmd-list-clients.c \
cmd-link-window.c cmd-unlink-window.c cmd-next-window.c cmd-send-keys.c \
cmd-swap-window.c cmd-rename-session.c cmd-kill-session.c \
cmd-switch-client.c cmd-has-session.c cmd-scroll-mode.c cmd-copy-mode.c \
cmd-paste-buffer.c cmd-new-session.c cmd-start-server.c \
cmd-kill-server.c cmd-set-window-option.c cmd-show-options.c \
cmd-show-window-options.c cmd-command-prompt.c cmd-set-buffer.c \
cmd-show-buffer.c cmd-list-buffers.c cmd-delete-buffer.c \
cmd-list-commands.c cmd-move-window.c cmd-select-prompt.c \
cmd-respawn-window.c cmd-source-file.c cmd-server-info.c \
cmd-clock-mode.c cmd-lock-server.c cmd-set-password.c \
cmd-save-buffer.c cmd-select-pane.c cmd-split-window.c \
cmd-resize-pane-up.c cmd-resize-pane-down.c cmd-kill-pane.c \
cmd-up-pane.c cmd-down-pane.c cmd-choose-window.c cmd-choose-session.c \
cmd-suspend-client.c cmd-find-window.c cmd-load-buffer.c \
cmd-copy-buffer.c cmd-break-pane.c cmd-swap-pane.c cmd-next-layout.c \
cmd-rotate-window.c \
window-clock.c window-scroll.c window-more.c window-copy.c \
window-choose.c \
options.c options-cmd.c paste.c colour.c utf8.c clock.c \
tty.c tty-term.c tty-keys.c tty-write.c util.c names.c \
osdep-unknown.c osdep-openbsd.c osdep-freebsd.c osdep-linux.c \
osdep-darwin.c attributes.c
CC?= gcc
INCDIRS+= -I. -I-
CFLAGS+= -DBUILD="\"$(VERSION) ($(DATE))\"" -DMETA="'${META}'"
ifdef FDEBUG
CFLAGS+= -g -ggdb -DDEBUG
LDFLAGS+= -rdynamic
LIBS+= -ldl
endif
ifeq (${CC},gcc)
CFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
CFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
CFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wcast-qual -Wsign-compare
CFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align
endif
LDFLAGS+=
LIBS+= -lncurses
PREFIX?= /usr/local
INSTALLDIR= install -d
INSTALLBIN= install -g bin -o root -m 555
INSTALLMAN= install -g bin -o root -m 444
ifeq ($(shell uname),AIX)
INCDIRS+= -I/usr/local/include/ncurses -Icompat
SRCS+= compat/vis.c compat/strlcpy.c compat/strlcat.c compat/strtonum.c \
compat/fgetln.c compat/asprintf.c compat/daemon.c compat/forkpty-aix.c \
compat/getopt_long.c compat/bsd-poll.c
CFLAGS+= -DNO_TREE_H -DNO_ASPRINTF -DNO_QUEUE_H -DNO_VSYSLOG \
-DNO_PROGNAME -DNO_STRLCPY -DNO_STRLCAT -DNO_STRTONUM \
-DNO_SETPROCTITLE -DNO_QUEUE_H -DNO_TREE_H -DNO_FORKPTY -DNO_FGETLN \
-DBROKEN_GETOPT -DBROKEN_POLL -DNO_PATHS_H
LDFLAGS+= -L/usr/local/lib
endif
ifeq ($(shell uname),IRIX64)
INCDIRS+= -Icompat -I/usr/local/include/ncurses
SRCS+= compat/strlcpy.c compat/strtonum.c compat/daemon.c \
compat/asprintf.c compat/fgetln.c compat/forkpty-irix.c
CFLAGS+= -DNO_STRLCPY -DNO_STRTONUM -DNO_TREE_H -DNO_SETPROCTITLE \
-DNO_DAEMON -DNO_FORKPTY -DNO_PROGNAME -DNO_ASPRINTF -DNO_FGETLN \
-DBROKEN_VSNPRINTF -D_SGI_SOURCE -std=c99
LDFLAGS+= -L/usr/local/lib
LIBS+= -lgen
endif
ifeq ($(shell uname),SunOS)
INCDIRS+= -Icompat -I/usr/local/include/ncurses
SRCS+= compat/strtonum.c compat/daemon.c compat/forkpty-sunos.c \
compat/asprintf.c compat/fgetln.c compat/vis.c
CFLAGS+= -DNO_STRTONUM -DNO_TREE_H -DNO_PATHS_H -DNO_SETPROCTITLE \
-DNO_DAEMON -DNO_FORKPTY -DNO_PROGNAME -DNO_ASPRINTF -DNO_FGETLN
LDFLAGS+= -L/usr/local/lib
LIBS+= -lsocket -lnsl
endif
ifeq ($(shell uname),Darwin)
INCDIRS+= -Icompat
SRCS+= compat/strtonum.c compat/bsd-poll.c compat/vis.c
CFLAGS+= -DNO_STRTONUM -DNO_SETRESUID -DNO_SETRESGID -DNO_SETPROCTITLE \
-DNO_QUEUE_H -DNO_TREE_H -DBROKEN_POLL
endif
ifeq ($(shell uname),Linux)
INCDIRS+= -Icompat
SRCS+= compat/strlcpy.c compat/strlcat.c compat/strtonum.c \
compat/fgetln.c compat/getopt_long.c compat/vis.c
CFLAGS+= $(shell getconf LFS_CFLAGS) -D_GNU_SOURCE \
-DNO_STRLCPY -DNO_STRLCAT -DNO_STRTONUM -DNO_SETPROCTITLE \
-DNO_QUEUE_H -DNO_TREE_H -DUSE_PTY_H -DNO_FGETLN \
-DBROKEN_GETOPT -std=c99
LIBS+= -lcrypt -lutil
endif
OBJS= $(patsubst %.c,%.o,$(SRCS))
CLEANFILES= ${PROG} *.o .depend *~ ${PROG}.core *.log compat/*.o index.html
CPPFLAGS:= ${INCDIRS} ${CPPFLAGS}
all: $(PROG)
$(PROG): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $+ $(LIBS)
depend: $(SRCS)
$(CC) $(CPPFLAGS) $(CFLAGS) -MM $(SRCS) > .depend
install:
$(INSTALLDIR) $(DESTDIR)$(PREFIX)/bin
$(INSTALLBIN) $(PROG) $(DESTDIR)$(PREFIX)/bin/$(PROG)
$(INSTALLDIR) $(DESTDIR)$(PREFIX)/man/man1
$(INSTALLMAN) $(PROG).1 $(DESTDIR)$(PREFIX)/man/man1/$(PROG).1
clean:
rm -f $(CLEANFILES)

158
Makefile Normal file
View File

@@ -0,0 +1,158 @@
# $Id: Makefile,v 1.121 2009-04-21 20:10:22 nicm Exp $
.SUFFIXES: .c .o .y .h
.PHONY: clean update-index.html upload-index.html
PROG= tmux
VERSION= 0.8
OS!= uname
REL!= uname -r
DATE!= date +%Y%m%d-%H%M
#FDEBUG= 1
META?= \002 # C-b
SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \
xmalloc.c xmalloc-debug.c input.c input-keys.c \
screen.c screen-write.c screen-redraw.c \
grid.c grid-view.c \
window.c session.c log.c client.c client-msg.c client-fn.c cfg.c \
layout.c key-string.c key-bindings.c resize.c arg.c mode-key.c \
cmd.c cmd-generic.c cmd-string.c cmd-list.c \
cmd-detach-client.c cmd-list-sessions.c cmd-new-window.c cmd-bind-key.c \
cmd-unbind-key.c cmd-previous-window.c cmd-last-window.c cmd-list-keys.c \
cmd-set-option.c cmd-rename-window.c cmd-select-window.c \
cmd-list-windows.c cmd-attach-session.c cmd-send-prefix.c \
cmd-refresh-client.c cmd-kill-window.c cmd-list-clients.c \
cmd-link-window.c cmd-unlink-window.c cmd-next-window.c cmd-send-keys.c \
cmd-swap-window.c cmd-rename-session.c cmd-kill-session.c \
cmd-switch-client.c cmd-has-session.c cmd-scroll-mode.c cmd-copy-mode.c \
cmd-paste-buffer.c cmd-new-session.c cmd-start-server.c \
cmd-kill-server.c cmd-set-window-option.c cmd-show-options.c \
cmd-show-window-options.c cmd-command-prompt.c cmd-set-buffer.c \
cmd-show-buffer.c cmd-list-buffers.c cmd-delete-buffer.c \
cmd-list-commands.c cmd-move-window.c cmd-select-prompt.c \
cmd-respawn-window.c cmd-source-file.c cmd-server-info.c \
cmd-clock-mode.c cmd-lock-server.c cmd-set-password.c \
cmd-save-buffer.c cmd-select-pane.c cmd-split-window.c \
cmd-resize-pane-up.c cmd-resize-pane-down.c cmd-kill-pane.c \
cmd-up-pane.c cmd-down-pane.c cmd-choose-window.c cmd-choose-session.c \
cmd-suspend-client.c cmd-find-window.c cmd-load-buffer.c \
cmd-copy-buffer.c cmd-break-pane.c cmd-swap-pane.c cmd-next-layout.c \
cmd-rotate-window.c \
window-clock.c window-scroll.c window-more.c window-copy.c \
window-choose.c \
options.c options-cmd.c paste.c colour.c utf8.c clock.c \
tty.c tty-term.c tty-keys.c tty-write.c util.c names.c attributes.c \
osdep-unknown.c osdep-openbsd.c osdep-freebsd.c osdep-linux.c \
osdep-darwin.c osdep-netbsd.c
CC?= c
INCDIRS+= -I. -I- -I/usr/local/include
CFLAGS+= -DMETA="'${META}'"
.ifdef PROFILE
# Don't use ccache
CC= /usr/bin/gcc
CFLAGS+= -pg -DPROFILE -O0
.endif
.ifdef FDEBUG
CFLAGS+= -g -ggdb -DDEBUG
LDFLAGS+= -Wl,-E
CFLAGS+= -DBUILD="\"$(VERSION) ($(DATE))\""
.else
CFLAGS+= -DBUILD="\"$(VERSION)\""
.endif
#CFLAGS+= -pedantic -std=c99
CFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
CFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
CFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wcast-qual -Wsign-compare
CFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align
PREFIX?= /usr/local
INSTALLDIR= install -d
INSTALLBIN= install -g bin -o root -m 555
INSTALLMAN= install -g bin -o root -m 444
LDFLAGS+= -L/usr/local/lib
.ifdef PROFILE
LDFLAGS+= -pg
.endif
LIBS+= -lutil -lncurses
# FreeBSD and DragonFly
.if ${OS} == "FreeBSD" || ${OS} == "DragonFly"
INCDIRS+= -Icompat
SRCS+= compat/vis.c
CFLAGS+= -DUSE_LIBUTIL_H -DNO_QUEUE_H -DNO_TREE_H
LIBS+= -lcrypt
.endif
# NetBSD
.if ${OS} == "NetBSD"
INCDIRS= -Icompat
SRCS+= compat/strtonum.c compat/vis.c
LIBS+= -lcrypt
CFLAGS+=-DNO_STRTONUM
.endif
OBJS= ${SRCS:S/.c/.o/:S/.y/.o/}
DISTDIR= ${PROG}-${VERSION}
DISTFILES= *.[chyl] Makefile GNUmakefile *.[1-9] NOTES TODO CHANGES FAQ \
`find examples compat -type f -and ! -path '*CVS*'`
CLEANFILES= ${PROG} *.o .depend *~ ${PROG}.core *.log compat/*.o index.html
CPPFLAGS:= ${INCDIRS} ${CPPFLAGS}
.c.o:
${CC} ${CPPFLAGS} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
.y.o:
${YACC} ${.IMPSRC}
${CC} ${CPPFLAGS} ${CFLAGS} -c y.tab.c -o ${.TARGET}
all: ${PROG}
${PROG}: ${OBJS}
${CC} ${LDFLAGS} -o ${PROG} ${OBJS} ${LIBS}
depend:
mkdep ${CPPFLAGS} ${CFLAGS} ${SRCS:M*.c}
dist: clean
grep '^#FDEBUG=' Makefile
grep '^#FDEBUG=' GNUmakefile
[ "`(grep '^VERSION' Makefile; grep '^VERSION' GNUmakefile)| \
uniq -u`" = "" ]
tar -zc \
-s '/.*/${DISTDIR}\/\0/' \
-f ${DISTDIR}.tar.gz ${DISTFILES}
lint:
lint -chvx ${CFLAGS:M-D*} ${SRCS:M*.c}
clean:
rm -f ${CLEANFILES}
upload-index.html: update-index.html
scp index.html images/*.png \
nicm,tmux@web.sf.net:/home/groups/t/tm/tmux/htdocs
rm -f images/small-*
update-index.html:
(cd images && \
rm -f small-* && \
for i in *.png; do \
convert "$$i" -resize 200x150 "small-$$i"; \
done \
)
sed "s/%%VERSION%%/${VERSION}/g" index.html.in >index.html
install: all
${INSTALLDIR} ${DESTDIR}${PREFIX}/bin
${INSTALLBIN} ${PROG} ${DESTDIR}${PREFIX}/bin/
${INSTALLDIR} ${DESTDIR}${PREFIX}/man/man1
${INSTALLMAN} ${PROG}.1 ${DESTDIR}${PREFIX}/man/man1/

View File

@@ -1,269 +0,0 @@
# Makefile.am
# Obvious program stuff.
bin_PROGRAMS = tmux
CLEANFILES = tmux.1.mdoc tmux.1.man
# Distribution tarball options.
EXTRA_DIST = \
CHANGES FAQ README TODO COPYING example_tmux.conf compat/*.[ch] \
compat.h tmux.h osdep-*.c xmalloc.h mdoc2man.awk tmux.1
dist-hook:
make clean
grep "^#found_debug=" configure
# Preprocessor flags.
CPPFLAGS += @XOPEN_DEFINES@ -DTMUX_CONF="\"$(sysconfdir)/tmux.conf\""
# glibc as usual does things ass-backwards and hides useful things by default,
# so everyone has to add this.
if IS_GLIBC
CFLAGS += -D_GNU_SOURCE
endif
# Set flags for gcc.
if IS_GCC
CFLAGS += -std=gnu99 -O2
if IS_DEBUG
CFLAGS += -g
CFLAGS += -Wno-long-long -Wall -W -Wformat=2
CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
CPPFLAGS += -DDEBUG
endif
if IS_COVERAGE
CFLAGS += -g -O0 --coverage
LDFLAGS += --coverage
endif
if IS_PROFILE
CFLAGS += -g -O0 -pg
LDFLAGS += -pg
endif
CPPFLAGS += -iquote.
endif
# Set flags for Solaris.
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
endif
endif
# Set flags for Sun CC.
if IS_SUNCC
CFLAGS += -erroff=E_EMPTY_DECLARATION
endif
# Set _LINUX_SOURCE_COMPAT for AIX for malloc(0).
if IS_AIX
DEFS += -D_LINUX_SOURCE_COMPAT=1
endif
# List of sources.
dist_tmux_SOURCES = \
alerts.c \
arguments.c \
attributes.c \
cfg.c \
client.c \
cmd-attach-session.c \
cmd-bind-key.c \
cmd-break-pane.c \
cmd-capture-pane.c \
cmd-choose-buffer.c \
cmd-choose-client.c \
cmd-choose-tree.c \
cmd-clear-history.c \
cmd-command-prompt.c \
cmd-confirm-before.c \
cmd-copy-mode.c \
cmd-detach-client.c \
cmd-display-message.c \
cmd-display-panes.c \
cmd-find.c \
cmd-find-window.c \
cmd-if-shell.c \
cmd-join-pane.c \
cmd-kill-pane.c \
cmd-kill-server.c \
cmd-kill-session.c \
cmd-kill-window.c \
cmd-list-buffers.c \
cmd-list-clients.c \
cmd-list-keys.c \
cmd-list-panes.c \
cmd-list-sessions.c \
cmd-list-windows.c \
cmd-list.c \
cmd-load-buffer.c \
cmd-lock-server.c \
cmd-move-window.c \
cmd-new-session.c \
cmd-new-window.c \
cmd-paste-buffer.c \
cmd-pipe-pane.c \
cmd-queue.c \
cmd-refresh-client.c \
cmd-rename-session.c \
cmd-rename-window.c \
cmd-resize-pane.c \
cmd-respawn-pane.c \
cmd-respawn-window.c \
cmd-rotate-window.c \
cmd-run-shell.c \
cmd-save-buffer.c \
cmd-select-layout.c \
cmd-select-pane.c \
cmd-select-window.c \
cmd-send-keys.c \
cmd-set-buffer.c \
cmd-set-environment.c \
cmd-set-hook.c \
cmd-set-option.c \
cmd-show-environment.c \
cmd-show-messages.c \
cmd-show-options.c \
cmd-source-file.c \
cmd-split-window.c \
cmd-string.c \
cmd-swap-pane.c \
cmd-swap-window.c \
cmd-switch-client.c \
cmd-unbind-key.c \
cmd-wait-for.c \
cmd.c \
colour.c \
control.c \
control-notify.c \
environ.c \
format.c \
grid-view.c \
grid.c \
hooks.c \
input-keys.c \
input.c \
job.c \
key-bindings.c \
key-string.c \
layout-custom.c \
layout-set.c \
layout.c \
log.c \
mode-key.c \
names.c \
notify.c \
options-table.c \
options.c \
paste.c \
proc.c \
resize.c \
screen-redraw.c \
screen-write.c \
screen.c \
server-client.c \
server-fn.c \
server.c \
session.c \
signal.c \
status.c \
style.c \
tmux.c \
tty-acs.c \
tty-keys.c \
tty-term.c \
tty.c \
utf8.c \
window-choose.c \
window-clock.c \
window-copy.c \
window.c \
xmalloc.c \
xterm-keys.c
nodist_tmux_SOURCES = osdep-@PLATFORM@.c
# Add compat file for utf8proc.
if HAVE_UTF8PROC
nodist_tmux_SOURCES += compat/utf8proc.c
endif
# Add compat for missing or broken functions.
if NO_FORKPTY
nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c
endif
if NO_IMSG
nodist_tmux_SOURCES += compat/imsg.c compat/imsg-buffer.c
endif
if NO_CLOSEFROM
nodist_tmux_SOURCES += compat/closefrom.c
endif
if NO_DAEMON
nodist_tmux_SOURCES += compat/daemon.c
endif
if NO_GETPROGNAME
nodist_tmux_SOURCES += compat/getprogname.c
endif
if NO_SETPROCTITLE
nodist_tmux_SOURCES += compat/setproctitle.c
endif
if NO_SETENV
nodist_tmux_SOURCES += compat/setenv.c
endif
if NO_STRLCAT
nodist_tmux_SOURCES += compat/strlcat.c
endif
if NO_STRLCPY
nodist_tmux_SOURCES += compat/strlcpy.c
endif
if NO_ASPRINTF
nodist_tmux_SOURCES += compat/asprintf.c
endif
if NO_FGETLN
nodist_tmux_SOURCES += compat/fgetln.c
endif
if NO_FPARSELN
nodist_tmux_SOURCES += compat/fparseln.c
endif
if NO_GETOPT
nodist_tmux_SOURCES += compat/getopt.c
endif
if NO_STRCASESTR
nodist_tmux_SOURCES += compat/strcasestr.c
endif
if NO_STRSEP
nodist_tmux_SOURCES += compat/strsep.c
endif
if NO_VIS
nodist_tmux_SOURCES += compat/vis.c compat/unvis.c
endif
if NO_STRTONUM
nodist_tmux_SOURCES += compat/strtonum.c
endif
if NO_B64_NTOP
nodist_tmux_SOURCES += compat/b64_ntop.c
endif
if NO_CFMAKERAW
nodist_tmux_SOURCES += compat/cfmakeraw.c
endif
if NO_OPENAT
nodist_tmux_SOURCES += compat/openat.c
endif
if NO_REALLOCARRAY
nodist_tmux_SOURCES += compat/reallocarray.c
endif
# Install tmux.1 in the right format.
install-exec-hook:
if test x@MANFORMAT@ = xmdoc; then \
sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1 \
>$(srcdir)/tmux.1.mdoc; \
else \
sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1| \
$(AWK) -f$(srcdir)/mdoc2man.awk >$(srcdir)/tmux.1.man; \
fi
$(mkdir_p) $(DESTDIR)$(mandir)/man1
$(INSTALL_DATA) $(srcdir)/tmux.1.@MANFORMAT@ \
$(DESTDIR)$(mandir)/man1/tmux.1

97
NOTES Normal file
View File

@@ -0,0 +1,97 @@
Welcome to tmux!
tmux is a "terminal multiplexer", it enables a number of terminals (or windows)
to be accessed and controlled from a single terminal. tmux is intended to be a
simple, modern, BSD-licensed alternative to programs such as GNU screen.
This 0.8 release runs on OpenBSD, FreeBSD, Linux and OS X and may still run on
Solaris (although it hasn't been tested in a while). It is usable, although
there remain a number of missing features and some remaining bugs are expected.
If upgrading from 0.5, PLEASE NOTE the following configuration file changes: it
is now required to pass the -g flag to set-option or set-window-option to set
global options; remain-by-default and utf8-default are now gone, use global
window options (set-window-option -g) instead.
tmux consists of a server part and multiple clients. The server is created when
required and runs continuously unless killed by the user. Clients access the
server through a socket in /tmp. Multiple sessions may be created on a single
server and attached to a number of clients. Each session may then have a number
of windows and windows may be linked to a number of sessions. Commands are
available to create, rename and destroy windows and sessions; to attach and
detach sessions from client terminals; to set configuration options; to split
windows into several simultaneously displayed panes; and to bind and unbind
command keys (invoked preceded by a prefix key, by default ctrl-b). Please see
the tmux(1) man page for further information.
The following is a summary of major features implemented in this version:
- Basic multiplexing, window switching, attaching and detaching.
- Window listing and renaming.
- Key binding.
- Handling of client terminal resize.
- Terminal emulation sufficient to handle most curses applications.
- A optional status line (enabled by default).
- Window history and copy and paste.
- Support for VT100 line drawing characters.
- A large command set.
- Vertical window splitting and layout.
- Automatic server locking on inactivity.
- A configuration file.
- UTF-8 support.
And major missing features:
- Proper mouse support.
- No support for programs changing termios(4) settings or other tty(4) ioctls.
A more extensive, but rough, todo list is included in the TODO file.
tmux also depends on several features of the client terminal (TERM), if these
are missing it may refuse to run, or not behave correctly. Known working are
TERM=screen (tmux in screen), xterm, xterm-color and rxvt. Note that TERM=xterm
does not support colour on OpenBSD. screen ignores this, tmux does not: use
xterm-color or rxvt for colour.
tmux supports UTF-8. To use it, the utf8 option must be set on each window;
this may be turned on for all windows by setting it as a global option, see
tmux(1) and the FAQ file. In addition, when starting tmux or attaching to an
existing session from a UTF-8-capable terminal, the -u flag must be specified.
A Vim syntax file is available in the examples directory. To install it:
- Drop the file in the syntax directory in your runtimepath (such as
~/.vim/syntax/tmux.vim).
- Make the filetype recognisable by adding the following to filetype.vim
in your runtimepath (~/.vim/filetype.vim):
augroup filetypedetect
au BufNewFile,BufRead .tmux.conf*,tmux.conf* setf tmux
augroup END
- Switch on syntax highlighting by adding "syntax enable" to your vimrc file.
For debugging, running tmux with -v or -vv will generate server and client log
files in the current directory.
The CVS HEAD version of tmux often has additional features from the release
versions; if interested, testing it is encouraged. It can be obtained by
anonymous CVS from SourceForge:
$ cvs -d:pserver:anoncvs@tmux.cvs.sf.net:/cvsroot/tmux co tmux
If running CVS HEAD, please note it is development code and there may be bugs
and undocumented features; please read the CHANGES file for information.
tmux mailing lists are available; visit:
https://sourceforge.net/mail/?group_id=200378
Bug reports, feature suggestions and especially code contributions are most
welcome. Please send by email to:
nicm@users.sf.net
-- Nicholas Marriott <nicm@users.sf.net>
$Id: NOTES,v 1.45 2009-04-21 20:06:12 nicm Exp $

69
README
View File

@@ -1,69 +0,0 @@
Welcome to tmux!
tmux is a "terminal multiplexer", it enables a number of terminals (or windows)
to be accessed and controlled from a single terminal. tmux is intended to be a
simple, modern, BSD-licensed alternative to programs such as GNU screen.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.
tmux depends on libevent 2.x. Download it from:
http://libevent.org
To build tmux from a release tarball, do:
$ ./configure && make
$ sudo make install
By default, tmux will use the utempter library to update utmp(5), if it is
installed. Run configure with --disable-utempter to disable this.
To get and build the latest from version control:
$ git clone https://github.com/tmux/tmux.git
$ cd tmux
$ sh autogen.sh
$ ./configure && make
For more information see http://git-scm.com. Patches should be sent by email to
the mailing list at tmux-users@googlegroups.com.
For documentation on using tmux, see the tmux.1 manpage. It can be viewed from
the source tree with:
$ nroff -mdoc tmux.1|less
Some common questions are answered in the FAQ file, a rough todo list is in the
TODO file and an example configuration in example_tmux.conf.
A vim(1) syntax file is available at:
https://github.com/keith/tmux.vim
https://raw.githubusercontent.com/keith/tmux.vim/master/syntax/tmux.vim
And a bash(1) completion file at:
https://github.com/imomaliev/tmux-bash-completion
For debugging, running tmux with -v or -vv will generate server and client log
files in the current directory.
tmux mailing lists are available. For general discussion and bug reports:
https://groups.google.com/forum/#!forum/tmux-users
And for Git commit emails:
https://groups.google.com/forum/#!forum/tmux-git
Subscribe by sending an email to <tmux-users+subscribe@googlegroups.com>.
Bug reports, feature suggestions and especially code contributions are most
welcome. Please send by email to:
tmux-users@googlegroups.com
This file and the CHANGES, FAQ, SYNCING and TODO files are licensed under the
ISC license. All other files have a license and copyright notice at their start.
-- Nicholas Marriott <nicholas.marriott@gmail.com>

176
SYNCING
View File

@@ -1,176 +0,0 @@
Preamble
========
Tmux portable relies on repositories "tmux" and "tmux-openbsd".
Here's a description of them:
* "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
OpenBSD base system.
* "tmux-openbsd" is the version of tmux in OpenBSD base system which provides
the basis of the portable tmux version.
Note: The "tmux-openbsd" repository is actually handled by "git cvsimport"
running at 15 minute intervals, so a commit made to OpenBSD's tmux CVS
repository will take at least that long to appear in this git repository.
(It might take longer, depending on the CVS mirror used to import the
OpenBSD code).
If you've never used git before, git tracks meta-data about the committer
and the author, as part of a commit, hence:
% git config [--global] user.name "Your name"
% git config [--global] user.email "you@yourdomain.com"
Note that, if you already have this in the global ~/.gitconfig option, then
this will be used. Setting this per-repository would involve not using the
"--global" flag above. If you wish to use the same credentials always,
pass the "--global" option, as shown.
This is a one-off operation once the repository has been cloned, assuming
this information has ever been set before.
Cloning repositories
====================
This involves having both tmux and tmux-openbsd cloned, as in:
% cd /some/where/useful
% git clone https://github.com/tmux/tmux.git
% git clone https://github.com/ThomasAdam/tmux-openbsd.git
Note that you do not need additional checkouts to manage the sync -- an
existing clone of either repositories will suffice. So if you already have
these checkouts existing, skip that.
Adding in git-remotes
=====================
Because the portable "tmux" git repository and the "tmux-openbsd"
repository do not inherently share any history between each other, the
history has been faked between them. This "faking of history" is something
which has to be told to git for the purposes of comparing the "tmux" and
"tmux-openbsd" repositories for syncing. To do this, we must reference the
clone of the "tmux-openbsd" repository from the "tmux" repository, as
shown by the following command:
% cd /path/to/tmux
% git remote add obsd-tmux file:///path/to/tmux-openbsd
So that now, the remote "obsd-tmux" can be used to reference branches and
commits from the "tmux-openbsd" repository, but from the context of the
portable "tmux" repository, which makes sense because it's the "tmux"
repository which will have the updates applied to them.
Fetching updates
================
To ensure the latest commits from "tmux-openbsd" can be found from within
"tmux", we have to ensure the "master" branch from "tmux-openbsd" is
up-to-date first, and then reference that update in "tmux", as in:
% cd /path/to/tmux-openbsd
% git checkout master
% git pull
Then back in "tmux":
% cd /path/to/tmux
% git fetch obsd-tmux
Creating the necessary branches
===============================
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
"tmux-openbsd" in the "tmux" repository:
% git checkout -b obsd-master obsd-tmux/master
Adding in the fake history points
=================================
To tie both the "master" branch from "tmux" and the "obsd-master"
branch from "tmux-openbsd" together, the fake history points added to the
"tmux" repository need to be added. To do this, we must add an
additional refspec line, as in:
% cd /path/to/tmux
% git config --add remote.origin.fetch '+refs/replace/*:refs/replace/*'
% git fetch origin
Performing the Sync
===================
Make sure the "master" branch is checked out:
% git checkout master
The following will show commits on OpenBSD not yet synched with "tmux":
% git log master..obsd-master
From there, merge the result in, fixing up any conflicts which might arise.
% git merge obsd-master
Then ensure things look correct by BUILDING the result of that sync:
% make clean && ./autogen.sh && ./configure && make
Compare the git merge result with what's on origin/master -- that is, check
which commits you're about to push:
% git log origin/master..master
And if happy:
% git push origin master
Keeping an eye on libutil in OpenBSD
====================================
A lot of the compat/ code in tmux comes from libutil, especially imsg.
Sometimes the API can change, etc., which might cause interesting problems
trying to run the portable version of tmux. It's worth checking
periodically for any changes to libutil in OpenBSD and syncing those files
to compat/ as and when appropriate.
Release tmux for next version
=============================
1. Comment the "found_debug=yes" line in configure.ac, since releases
don't have debugging enabled, otherwise make(1) aborts when
preparing the distribution.
2. Update and commit README and CHANGES. The former should be checked for
anything outdated and updated with a list of things that might break
upgrades and the latter should mention all the major changes since
the last version.
3. Tag with:
% git tag -a 2.X
Where "2.X" is the next version.
Push the tag out with:
% git push 2.X
4. Build the tarball with 'make dist'.
5. Check the tarball. If it's good, go here to select the tag just pushed:
https://github.com/tmux/tmux/tags
Click the "Add release notes", upload the tarball and add a link in the
description field to the CHANGES file.
7. Clone the tmux.github.io repository, and change the RELEASE version in
the Makefile. Commit it, and run 'make' to replace %%VERSION%%. Push
the result out.
8. Bump version in tmux/tmux.git configure.ac and uncomment "found_debug=yes" to
create a debug build by default.

242
TODO
View File

@@ -1,143 +1,103 @@
- 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
* resize-pane -p to match split-window -p
- line mode/char-at-a-time mode a la telnet?
- handle ioctl/termios stuff on window sockets
- figure out once and for all what is going on with backspace and del
backspace should be translated per the termios setting.
del passed through?
- window creation/idle time
- profile/optimise, particularly (i suspect) input.c
- could use bsearch all over the place or get rid of smaller tables (clientmsg)
- better errors when creating new windows/sessions (how?)
- Implicitly add exec to the commands for new windows (switch to disable it)
- it would be nice to have multichar commands so you could have C-b K K for
kill-window to limit accidental presses
- commands:
extend list-clients to list clients attached to a session (-a for all?)
bring back detach-session to detach all clients on a session?
clone-session command to link all windows to a new session
- allow fnmatch for -c, so that you can, eg, detach all clients
- bind non prefix keys
- garbage collect window history (100 lines at a time?) if it hasn't been used
in $x time (need window creation/use times)
- lift SHRT_MAX limits for history
- audit copy/scroll and other modes for problems with very small windows
- split clients into three RB trees by fd: attached/unattached/dead?
or tailqs? what would be fastest per-char?
- c/p is still borken in some ways
- better mode features: search, back word, forward word, etc
- flags to centre screen in window
- better terminal emulation (identify, insert mode, some other bits)
- when resizing, use history
- audit for leftover/unused code
- activity/bell should be per-window not per-link? what if it is cur win in
session not being watched?
- tidy up window modes
- next prev word etc in command prompt; also ^K
- many more info() displays for various things
- vi half page scroll
- backspace should perhaps wrap backwards over newlines which were not moved
down by a newline: screen and the OS X terminal does this but xterm and most
others do not. this might be hard: a flag for each grid line (top bit of size
maybe)? a single flag is insufficient as can't then tell when to /stop/
unwrapping
- input.c is too complicated. simplify?
- use a better termcap internally instead of screen, perhaps xterm
- a command to display the status line briefly when it is turned off
- FAQ "Can I have some examples of cool things I can do with tmux?" -- linkw,
more??
- kill all but current pane
- fix rxvt cursor fg issue (text under cursor can have non-white fg)
- key handling sucks a bit and needs to be reworked
- some people find first window being 0 rather than 1 is awkward on the
keyboard. what about a new-window-index option that sets the base at which
tmux starts numbering new windows, then they can do: set -g new-window-index
1; bind 0 selectw -t:10
- some way to change status line colours based on something? command?
- client sx/sy should be in tty, then can let the terminal wrap at edge
to allow xterm to pick up it should be one line for its c/p
- 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
- command to run something without a window at all - output to
window-more. what for? isnt this the same as doing it w/ splitw/neww now?
- command to purge window history? or apply history-limit changes?
- clone session command
- make command sequences more usable: don't require space around ;, handle
errors better
- would be nice if tmux could be the shell (tmux attach, but hard link to tmux
binary as "tmuxsh" or wrapper script?) -- problems with tty dev permissions
- support other mouse modes (highlight etc) and use it in copy mode
- set-remain-on-exit is a bit of a hack, some way to do it generically?
- set-option should be set-session-option and should be overall global options
for stuff like mode keys?
- a confirm-before command which asks "Are you sure? (y/n)" before executing
command, eg bind-key "&" confirm-before "kill-window"
- might be nice if attach-session behaved like switch-client inside an
existing client
- key to switch to copy mode from scroll mode
- attach should have a flag to create session if it doesn't exist
- clear window title on exit
- better support for stupid margin terminals. strcmp for cons25 sucks, how can
these be autodetected?
- refer to windows by name etc (duplicates? fnmatch?)
- the output code (tty.c) could do with optimisation depending on term
capibilities
- resize-pane-up/down should be resize-pane -U/-D. ditto up-pane/down-pane
should be select-pane -U/-D
- layout/split stuff:
horiz split command, and similar resizing commands as for vert split
display the layout in a readable format somewhere
previous-layout command
select-layout command
make manual layout a bit less of a hack and make it handle a grid
should the layout be a window option???
more layouts
better resizing of shells when changing layout
find and fix bug with clear screen after horiz split
speed improvements? -- still too slow over ssh!
hardcoded 81 for left-vertical is nasty
- test bug sshing from freebsd console (tom iirc?)
- fix build on solaris 10
- rotate-window has redraw bugs... :-/
- make command sequences more usable
* don't require space after ;
* options for error handling: && and ||?
(hopefully) for 0.8, in no particular order:
- nothing!
- options bits and pieces:
* set-remain-on-exit is a complete hack
* way to set socket path from config file
- format improvements:
* 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?
- 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)
- warts on current naming:
* display-time but message-fg/bg/attr
* list-* vs show-*
* split-window -> split-pane?
- better UTF-8 support:
* message display
* prompt input
* searching in copy mode
- copy/paste improvements:
* incremental searching
* paste w/o trailing whitespace
* command to toggle selection not to move it in copy-mode
* regex searching
* copy-pipe should have -x as well
* 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
* searching in copy mode should unwrap lines, so if you search for "foobar"
then it should be found even if it is now "foo\nbar" (if the WRAP flag
is set on the line)
* capture-pane option to preserve spaces but not join lines
- 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
* we do more work than we should if a single read() contains operations
that cancel each other out: for example, writing twice to the same
cell, or writing and then clearing a line; it would be nice to
optimize these. would it mean processing the entire read() data first
then applying changes? or an initial optimization step? or something
else?
- 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? separate command prompt and 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

294
alerts.c
View File

@@ -1,294 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <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 *);
void alerts_run_hook(struct session *, struct winlink *, int);
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) {
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;
}
void
alerts_run_hook(struct session *s, struct winlink *wl, int flags)
{
struct cmd_find_state fs;
if (cmd_find_from_winlink(&fs, s, wl) != 0)
return;
if (flags & WINDOW_BELL)
hooks_run(s->hooks, NULL, &fs, "alert-bell");
if (flags & WINDOW_SILENCE)
hooks_run(s->hooks, NULL, &fs, "alert-silence");
if (flags & WINDOW_ACTIVITY)
hooks_run(s->hooks, NULL, &fs, "alert-activity");
}
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) {
alerts_run_hook(s, wl, alerts);
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 ((w->flags & flags) != flags) {
w->flags |= flags;
log_debug("@%u alerts flags added %#x", w->id, flags);
}
if (!alerts_fired && 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);
}
}

194
arg.c Normal file
View File

@@ -0,0 +1,194 @@
/* $Id: arg.c,v 1.5 2008-08-28 17:45:25 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
struct client *arg_lookup_client(const char *);
struct session *arg_lookup_session(const char *);
struct client *
arg_lookup_client(const char *name)
{
struct client *c;
u_int i;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c != NULL && strcmp(name, c->tty.path) == 0)
return (c);
}
return (NULL);
}
struct session *
arg_lookup_session(const char *name)
{
struct session *s, *newest = NULL;
struct timeval *tv;
u_int i;
tv = NULL;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL || fnmatch(name, s->name, 0) != 0)
continue;
if (tv == NULL || timercmp(&s->tv, tv, >)) {
newest = s;
tv = &s->tv;
}
}
return (newest);
}
struct client *
arg_parse_client(const char *arg)
{
struct client *c;
char *arg2;
size_t n;
if (arg != NULL && (arg[0] != ':' || arg[1] != '\0')) {
arg2 = xstrdup(arg);
/* Trim a trailing : if any from the argument. */
n = strlen(arg2);
if (arg2[n - 1] == ':')
arg2[n - 1] = '\0';
/* Try and look up the client name. */
c = arg_lookup_client(arg2);
xfree(arg2);
return (c);
}
return (NULL);
}
struct session *
arg_parse_session(const char *arg)
{
struct session *s;
struct client *c;
char *arg2;
size_t n;
if (arg != NULL && (arg[0] != ':' || arg[1] != '\0')) {
arg2 = xstrdup(arg);
/* Trim a trailing : if any from the argument. */
n = strlen(arg2);
if (arg2[n - 1] == ':')
arg2[n - 1] = '\0';
/* See if the argument matches a session. */
if ((s = arg_lookup_session(arg2)) != NULL) {
xfree(arg2);
return (s);
}
/* If not try a client. */
if ((c = arg_lookup_client(arg2)) != NULL) {
xfree(arg2);
return (c->session);
}
xfree(arg2);
}
return (NULL);
}
int
arg_parse_window(const char *arg, struct session **s, int *idx)
{
char *arg2, *ptr;
const char *errstr;
*idx = -1;
/* Handle no argument or a single :. */
if (arg == NULL || (arg[0] == ':' && arg[1] == '\0')) {
*s = arg_parse_session(NULL);
return (0);
}
/* Find the separator if any. */
arg2 = xstrdup(arg);
ptr = strrchr(arg2, ':');
/*
* If it is first, this means no session name, so use current session
* and try to convert the rest as index.
*/
if (ptr == arg2) {
*idx = strtonum(ptr + 1, 0, INT_MAX, &errstr);
if (errstr != NULL) {
xfree(arg2);
return (1);
}
xfree(arg2);
*s = arg_parse_session(NULL);
return (0);
}
/* If missing, try as an index, else look up immediately. */
if (ptr == NULL) {
*idx = strtonum(arg2, 0, INT_MAX, &errstr);
if (errstr == NULL) {
/* This is good as an index; use current session. */
xfree(arg2);
*s = arg_parse_session(NULL);
return (0);
}
*idx = -1;
goto lookup;
}
/* If last, strip it and look up as a session. */
if (ptr[1] == '\0') {
*ptr = '\0';
goto lookup;
}
/* Present but not first and not last. Break and convert both. */
*ptr = '\0';
*idx = strtonum(ptr + 1, 0, INT_MAX, &errstr);
if (errstr != NULL) {
xfree(arg2);
return (1);
}
lookup:
/* Look up as session. */
*s = arg_parse_session(arg2);
xfree(arg2);
if (*s == NULL)
return (1);
return (0);
}

View File

@@ -1,259 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.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. */
struct args *
args_create(int argc, ...)
{
struct args *args;
va_list ap;
int i;
args = xcalloc(1, sizeof *args);
args->argc = argc;
if (argc == 0)
args->argv = NULL;
else
args->argv = xcalloc(argc, sizeof *args->argv);
va_start(ap, argc);
for (i = 0; i < argc; i++)
args->argv[i] = xstrdup(va_arg(ap, char *));
va_end(ap);
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. */
struct args *
args_parse(const char *template, int argc, char **argv)
{
struct args *args;
int opt;
args = xcalloc(1, sizeof *args);
optreset = 1;
optind = 1;
while ((opt = getopt(argc, argv, template)) != -1) {
if (opt < 0)
continue;
if (opt == '?' || strchr(template, opt) == NULL) {
args_free(args);
return (NULL);
}
args_set(args, opt, optarg);
}
argc -= optind;
argv += optind;
args->argc = argc;
args->argv = cmd_copy_argv(argc, argv);
return (args);
}
/* Free an arguments set. */
void
args_free(struct args *args)
{
struct args_entry *entry;
struct args_entry *entry1;
cmd_free_argv(args->argc, args->argv);
RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
RB_REMOVE(args_tree, &args->tree, entry);
free(entry->value);
free(entry);
}
free(args);
}
/* Add to string. */
static void printflike(3, 4)
args_print_add(char **buf, size_t *len, const char *fmt, ...)
{
va_list ap;
char *s;
size_t slen;
va_start(ap, fmt);
slen = xvasprintf(&s, fmt, ap);
va_end(ap);
*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. */
RB_FOREACH(entry, args_tree, &args->tree) {
if (entry->value != NULL)
continue;
if (*buf == '\0')
args_print_add(&buf, &len, "-");
args_print_add(&buf, &len, "%c", entry->flag);
}
/* Then the flags with arguments. */
RB_FOREACH(entry, args_tree, &args->tree) {
if (entry->value == NULL)
continue;
if (*buf != '\0')
args_print_add(&buf, &len, " -%c ", entry->flag);
else
args_print_add(&buf, &len, "-%c ", entry->flag);
if (strchr(entry->value, ' ') != NULL)
args_print_add(&buf, &len, "\"%s\"", entry->value);
else
args_print_add(&buf, &len, "%s", entry->value);
}
/* And finally the argument vector. */
for (i = 0; i < args->argc; i++) {
if (*buf != '\0')
args_print_add(&buf, &len, " ");
if (strchr(args->argv[i], ' ') != NULL)
args_print_add(&buf, &len, "\"%s\"", args->argv[i]);
else
args_print_add(&buf, &len, "%s", args->argv[i]);
}
return (buf);
}
/* Return if an argument is present. */
int
args_has(struct args *args, u_char ch)
{
return (args_find(args, ch) == NULL ? 0 : 1);
}
/* Set argument value in the arguments tree. */
void
args_set(struct args *args, u_char ch, const char *value)
{
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)
entry->value = xstrdup(value);
}
/* Get argument value. Will be NULL if it isn't present. */
const char *
args_get(struct args *args, u_char ch)
{
struct args_entry *entry;
if ((entry = args_find(args, ch)) == NULL)
return (NULL);
return (entry->value);
}
/* Convert an argument value to a number. */
long long
args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
char **cause)
{
const char *errstr;
long long ll;
struct args_entry *entry;
if ((entry = args_find(args, ch)) == NULL) {
*cause = xstrdup("missing");
return (0);
}
ll = strtonum(entry->value, minval, maxval, &errstr);
if (errstr != NULL) {
*cause = xstrdup(errstr);
return (0);
}
*cause = NULL;
return (ll);
}

119
array.h Normal file
View File

@@ -0,0 +1,119 @@
/* $Id: array.h,v 1.7 2008-09-29 16:58:02 nicm Exp $ */
/*
* Copyright (c) 2006 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.
*/
#ifndef ARRAY_H
#define ARRAY_H
#define ARRAY_DECL(n, c) \
struct n { \
c *list; \
u_int num; \
size_t space; \
}
#define ARRAY_ITEM(a, i) ((a)->list[i])
#define ARRAY_ITEMSIZE(a) (sizeof *(a)->list)
#define ARRAY_INITIALSPACE(a) (10 * ARRAY_ITEMSIZE(a))
#define ARRAY_ENSURE(a, n) do { \
if (UINT_MAX - (n) < (a)->num) \
fatalx("number too big"); \
if (SIZE_MAX / ((a)->num + (n)) < ARRAY_ITEMSIZE(a)) \
fatalx("size too big"); \
if ((a)->space == 0) { \
(a)->space = ARRAY_INITIALSPACE(a); \
(a)->list = xrealloc((a)->list, 1, (a)->space); \
} \
while ((a)->space <= ((a)->num + (n)) * ARRAY_ITEMSIZE(a)) { \
(a)->list = xrealloc((a)->list, 2, (a)->space); \
(a)->space *= 2; \
} \
} while (0)
#define ARRAY_EMPTY(a) ((a) == NULL || (a)->num == 0)
#define ARRAY_LENGTH(a) ((a)->num)
#define ARRAY_DATA(a) ((a)->list)
#define ARRAY_FIRST(a) ARRAY_ITEM(a, 0)
#define ARRAY_LAST(a) ARRAY_ITEM(a, (a)->num - 1)
#define ARRAY_INIT(a) do { \
(a)->num = 0; \
(a)->list = NULL; \
(a)->space = 0; \
} while (0)
#define ARRAY_CLEAR(a) do { \
(a)->num = 0; \
} while (0)
#define ARRAY_SET(a, i, s) do { \
(a)->list[i] = s; \
} while (0)
#define ARRAY_ADD(a, s) do { \
ARRAY_ENSURE(a, 1); \
(a)->list[(a)->num] = s; \
(a)->num++; \
} while (0)
#define ARRAY_INSERT(a, i, s) do { \
ARRAY_ENSURE(a, 1); \
if ((i) < (a)->num) { \
memmove((a)->list + (i) + 1, (a)->list + (i), \
ARRAY_ITEMSIZE(a) * ((a)->num - (i))); \
} \
(a)->list[i] = s; \
(a)->num++; \
} while (0)
#define ARRAY_REMOVE(a, i) do { \
if ((i) < (a)->num - 1) { \
memmove((a)->list + (i), (a)->list + (i) + 1, \
ARRAY_ITEMSIZE(a) * ((a)->num - (i) - 1)); \
} \
(a)->num--; \
if ((a)->num == 0) \
ARRAY_FREE(a); \
} while (0)
#define ARRAY_EXPAND(a, n) do { \
ARRAY_ENSURE(a, n); \
(a)->num += n; \
} while (0)
#define ARRAY_TRUNC(a, n) do { \
if ((a)->num > n) \
(a)->num -= n; \
else \
ARRAY_FREE(a); \
} while (0)
#define ARRAY_CONCAT(a, b) do { \
ARRAY_ENSURE(a, (b)->num); \
memcpy((a)->list + (a)->num, (b)->list, (b)->num * ARRAY_ITEMSIZE(a)) \
(a)->num += (b)->num; \
} while (0)
#define ARRAY_FREE(a) do { \
if ((a)->list != NULL) \
xfree((a)->list); \
ARRAY_INIT(a); \
} while (0)
#define ARRAY_FREEALL(a) do { \
ARRAY_FREE(a); \
xfree(a); \
} while (0)
#endif

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */
/* $Id: attributes.c,v 1.1 2009-01-27 20:22:33 nicm Exp $ */
/*
* Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org>
@@ -23,24 +23,29 @@
#include "tmux.h"
const char *
attributes_tostring(u_char attr)
attributes_tostring(u_char ch)
{
static char buf[128];
size_t len;
if (attr == 0)
return ("none");
if (ch == 0)
return ("default");
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s",
attr & GRID_ATTR_BRIGHT ? "bright," : "",
attr & GRID_ATTR_DIM ? "dim," : "",
attr & GRID_ATTR_UNDERSCORE ? "underscore," : "",
attr & GRID_ATTR_BLINK ? "blink," : "",
attr & GRID_ATTR_REVERSE ? "reverse," : "",
attr & GRID_ATTR_HIDDEN ? "hidden," : "",
attr & GRID_ATTR_ITALICS ? "italics," : "");
if (len > 0)
buf[len - 1] = '\0';
buf[0] = '\0';
if (ch & GRID_ATTR_BRIGHT)
strlcat(buf, "bright,", sizeof (buf));
if (ch & GRID_ATTR_DIM)
strlcat(buf, "dim,", sizeof (buf));
if (ch & GRID_ATTR_UNDERSCORE)
strlcat(buf, "underscore,", sizeof (buf));
if (ch & GRID_ATTR_BLINK)
strlcat(buf, "blink,", sizeof (buf));
if (ch & GRID_ATTR_REVERSE)
strlcat(buf, "reverse,", sizeof (buf));
if (ch & GRID_ATTR_HIDDEN)
strlcat(buf, "hidden,", sizeof (buf));
if (ch & GRID_ATTR_ITALICS)
strlcat(buf, "italics,", sizeof (buf));
*(strrchr(buf, ',')) = '\0';
return (buf);
}
@@ -49,7 +54,7 @@ int
attributes_fromstring(const char *str)
{
const char delimiters[] = " ,|";
u_char attr;
u_char ch;
size_t end;
if (*str == '\0' || strcspn(str, delimiters) == 0)
@@ -57,31 +62,31 @@ attributes_fromstring(const char *str)
if (strchr(delimiters, str[strlen(str) - 1]) != NULL)
return (-1);
if (strcasecmp(str, "default") == 0 || strcasecmp(str, "none") == 0)
if (strcasecmp(str, "default") == 0)
return (0);
attr = 0;
ch = 0;
do {
end = strcspn(str, delimiters);
if ((end == 6 && strncasecmp(str, "bright", end) == 0) ||
(end == 4 && strncasecmp(str, "bold", end) == 0))
attr |= GRID_ATTR_BRIGHT;
ch |= GRID_ATTR_BRIGHT;
else if (end == 3 && strncasecmp(str, "dim", end) == 0)
attr |= GRID_ATTR_DIM;
ch |= GRID_ATTR_DIM;
else if (end == 10 && strncasecmp(str, "underscore", end) == 0)
attr |= GRID_ATTR_UNDERSCORE;
ch |= GRID_ATTR_UNDERSCORE;
else if (end == 5 && strncasecmp(str, "blink", end) == 0)
attr |= GRID_ATTR_BLINK;
ch |= GRID_ATTR_BLINK;
else if (end == 7 && strncasecmp(str, "reverse", end) == 0)
attr |= GRID_ATTR_REVERSE;
ch |= GRID_ATTR_REVERSE;
else if (end == 6 && strncasecmp(str, "hidden", end) == 0)
attr |= GRID_ATTR_HIDDEN;
ch |= GRID_ATTR_HIDDEN;
else if (end == 7 && strncasecmp(str, "italics", end) == 0)
attr |= GRID_ATTR_ITALICS;
ch |= GRID_ATTR_ITALICS;
else
return (-1);
str += end + strspn(str + end, delimiters);
} while (*str != '\0');
return (attr);
return (ch);
}

View File

@@ -1,17 +0,0 @@
#!/bin/sh
if [ "x$(uname)" = "xOpenBSD" ]; then
[ -z "$AUTOMAKE_VERSION" ] && export AUTOMAKE_VERSION=1.10
[ -z "$AUTOCONF_VERSION" ] && export AUTOCONF_VERSION=2.65
fi
die()
{
echo "$@" >&2
exit 1
}
mkdir -p etc
aclocal || die "aclocal failed"
automake --add-missing --force-missing --copy --foreign || die "automake failed"
autoreconf || die "autoreconf failed"

99
buffer-poll.c Normal file
View File

@@ -0,0 +1,99 @@
/* $Id: buffer-poll.c,v 1.10 2008-09-09 22:16:36 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include "tmux.h"
/* Set up pollfd for buffers. */
void
buffer_set(
struct pollfd *pfd, int fd, unused struct buffer *in, struct buffer *out)
{
pfd->fd = fd;
pfd->events = POLLIN;
if (BUFFER_USED(out) > 0)
pfd->events |= POLLOUT;
}
/* Fill buffers from socket based on poll results. */
int
buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out)
{
ssize_t n;
#if 0
log_debug("buffer_poll (%ld): fd=%d, revents=%d; out=%zu in=%zu",
(long) getpid(),
pfd->fd, pfd->revents, BUFFER_USED(out), BUFFER_USED(in));
#endif
#ifndef BROKEN_POLL
if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP))
return (-1);
#endif
if (pfd->revents & POLLIN) {
buffer_ensure(in, BUFSIZ);
n = read(pfd->fd, BUFFER_IN(in), BUFFER_FREE(in));
#if 0
log_debug("buffer_poll: fd=%d, read=%zd", pfd->fd, n);
#endif
if (n == 0)
return (-1);
if (n == -1) {
if (errno != EINTR && errno != EAGAIN)
return (-1);
} else
buffer_add(in, n);
}
if (BUFFER_USED(out) > 0 && pfd->revents & POLLOUT) {
n = write(pfd->fd, BUFFER_OUT(out), BUFFER_USED(out));
#if 0
log_debug("buffer_poll: fd=%d, write=%zd", pfd->fd, n);
#endif
if (n == -1) {
if (errno != EINTR && errno != EAGAIN)
return (-1);
} else
buffer_remove(out, n);
}
return (0);
}
/* Flush buffer output to socket. */
void
buffer_flush(int fd, struct buffer *in, struct buffer *out)
{
struct pollfd pfd;
while (BUFFER_USED(out) > 0) {
buffer_set(&pfd, fd, in, out);
if (poll(&pfd, 1, INFTIM) == -1) {
if (errno == EAGAIN || errno == EINTR)
continue;
fatal("poll failed");
}
if (buffer_poll(&pfd, in, out) != 0)
break;
}
}

227
buffer.c Normal file
View File

@@ -0,0 +1,227 @@
/* $Id: buffer.c,v 1.5 2008-08-07 20:20:52 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
#include "tmux.h"
/* Create a buffer. */
struct buffer *
buffer_create(size_t size)
{
struct buffer *b;
if (size == 0)
fatalx("zero size");
b = xcalloc(1, sizeof *b);
b->base = xmalloc(size);
b->space = size;
return (b);
}
/* Destroy a buffer. */
void
buffer_destroy(struct buffer *b)
{
xfree(b->base);
xfree(b);
}
/* Empty a buffer. */
void
buffer_clear(struct buffer *b)
{
b->size = 0;
b->off = 0;
}
/* Ensure free space for size in buffer. */
void
buffer_ensure(struct buffer *b, size_t size)
{
if (size == 0)
fatalx("zero size");
if (BUFFER_FREE(b) >= size)
return;
if (b->off > 0) {
if (b->size > 0)
memmove(b->base, b->base + b->off, b->size);
b->off = 0;
}
if (SIZE_MAX - b->size < size)
fatalx("size too big");
while (b->space < b->size + size) {
b->base = xrealloc(b->base, 2, b->space);
b->space *= 2;
}
}
/* Adjust buffer after data appended. */
void
buffer_add(struct buffer *b, size_t size)
{
if (size == 0)
fatalx("zero size");
if (size > b->space - b->size)
fatalx("overflow");
b->size += size;
}
/* Reverse buffer add. */
void
buffer_reverse_add(struct buffer *b, size_t size)
{
if (size == 0)
fatalx("zero size");
if (size > b->size)
fatalx("underflow");
b->size -= size;
}
/* Adjust buffer after data removed. */
void
buffer_remove(struct buffer *b, size_t size)
{
if (size == 0)
fatalx("zero size");
if (size > b->size)
fatalx("underflow");
b->size -= size;
b->off += size;
}
/* Reverse buffer remove. */
void
buffer_reverse_remove(struct buffer *b, size_t size)
{
if (size == 0)
fatalx("zero size");
if (size > b->off)
fatalx("overflow");
b->size += size;
b->off -= size;
}
/* Insert a section into the buffer. */
void
buffer_insert_range(struct buffer *b, size_t base, size_t size)
{
if (size == 0)
fatalx("zero size");
if (base > b->size)
fatalx("range outside buffer");
buffer_ensure(b, size);
memmove(b->base + b->off + base + size,
b->base + b->off + base, b->size - base);
b->size += size;
}
/* Delete a section from the buffer. */
void
buffer_delete_range(struct buffer *b, size_t base, size_t size)
{
if (size == 0)
fatalx("zero size");
if (size > b->size)
fatalx("size too big");
if (base + size > b->size)
fatalx("range outside buffer");
memmove(b->base + b->off + base,
b->base + b->off + base + size, b->size - base - size);
b->size -= size;
}
/* Copy data into a buffer. */
void
buffer_write(struct buffer *b, const void *data, size_t size)
{
if (size == 0)
fatalx("zero size");
buffer_ensure(b, size);
memcpy(BUFFER_IN(b), data, size);
buffer_add(b, size);
}
/* Copy data out of a buffer. */
void
buffer_read(struct buffer *b, void *data, size_t size)
{
if (size == 0)
fatalx("zero size");
if (size > b->size)
fatalx("underflow");
memcpy(data, BUFFER_OUT(b), size);
buffer_remove(b, size);
}
/* Store an 8-bit value. */
void
buffer_write8(struct buffer *b, uint8_t n)
{
buffer_ensure(b, 1);
BUFFER_IN(b)[0] = n;
buffer_add(b, 1);
}
/* Store a 16-bit value. */
void
buffer_write16(struct buffer *b, uint16_t n)
{
buffer_ensure(b, 2);
BUFFER_IN(b)[0] = n & 0xff;
BUFFER_IN(b)[1] = n >> 8;
buffer_add(b, 2);
}
/* Extract an 8-bit value. */
uint8_t
buffer_read8(struct buffer *b)
{
uint8_t n;
n = BUFFER_OUT(b)[0];
buffer_remove(b, 1);
return (n);
}
/* Extract a 16-bit value. */
uint16_t
buffer_read16(struct buffer *b)
{
uint16_t n;
n = BUFFER_OUT(b)[0] | (BUFFER_OUT(b)[1] << 8);
buffer_remove(b, 2);
return (n);
}

225
cfg.c
View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cfg.c,v 1.15 2009-03-31 22:23:43 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,189 +18,104 @@
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
char *cfg_file;
struct cmd_q *cfg_cmd_q;
int cfg_finished;
int cfg_references;
char **cfg_causes;
u_int cfg_ncauses;
struct client *cfg_client;
/*
* Config file parser. Pretty quick and simple, each line is parsed into a
* argv array and executed as a command.
*/
void cfg_default_done(struct cmd_q *);
char *cfg_string(FILE *, char, int);
void printflike2 cfg_print(struct cmd_ctx *, const char *, ...);
void printflike2 cfg_error(struct cmd_ctx *, const char *, ...);
void
set_cfg_file(const char *path)
char *cfg_cause;
void printflike2
cfg_print(unused struct cmd_ctx *ctx, unused const char *fmt, ...)
{
free(cfg_file);
cfg_file = xstrdup(path);
}
void
start_cfg(void)
void printflike2
cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...)
{
const char *home;
int quiet = 0;
va_list ap;
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++;
load_cfg(TMUX_CONF, cfg_cmd_q, 1);
if (cfg_file == NULL && (home = find_home()) != NULL) {
xasprintf(&cfg_file, "%s/.tmux.conf", home);
quiet = 1;
}
if (cfg_file != NULL)
load_cfg(cfg_file, cfg_cmd_q, quiet);
cmdq_continue(cfg_cmd_q);
va_start(ap, fmt);
xvasprintf(&cfg_cause, fmt, ap);
va_end(ap);
}
int
load_cfg(const char *path, struct cmd_q *cmdq, int quiet)
load_cfg(const char *path, char **cause)
{
FILE *f;
char delim[3] = { '\\', '\\', '\0' };
u_int found;
size_t line = 0;
char *buf, *cause1, *p;
FILE *f;
u_int n;
char *buf, *line, *ptr;
size_t len;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
log_debug("loading %s", path);
if ((f = fopen(path, "rb")) == NULL) {
if (errno == ENOENT && quiet)
return (0);
cfg_add_cause("%s: %s", path, strerror(errno));
return (-1);
xasprintf(cause, "%s: %s", path, strerror(errno));
return (1);
}
n = 0;
found = 0;
while ((buf = fparseln(f, NULL, &line, delim, 0)) != NULL) {
log_debug("%s: %s", path, buf);
/* Skip empty lines. */
p = buf;
while (isspace((u_char) *p))
p++;
if (*p == '\0') {
free(buf);
continue;
line = NULL;
while ((buf = fgetln(f, &len))) {
if (buf[len - 1] == '\n')
buf[len - 1] = '\0';
else {
line = xrealloc(line, 1, len + 1);
memcpy(line, buf, len);
line[len] = '\0';
buf = line;
}
n++;
/* Parse and run the command. */
if (cmd_string_parse(p, &cmdlist, path, line, &cause1) != 0) {
free(buf);
if (cause1 == NULL)
if (cmd_string_parse(buf, &cmdlist, cause) != 0) {
if (*cause == NULL)
continue;
cfg_add_cause("%s:%zu: %s", path, line, cause1);
free(cause1);
continue;
goto error;
}
free(buf);
if (cmdlist == NULL)
continue;
cmdq_append(cmdq, cmdlist, NULL);
cfg_cause = NULL;
ctx.msgdata = NULL;
ctx.cursession = NULL;
ctx.curclient = NULL;
ctx.error = cfg_error;
ctx.print = cfg_print;
ctx.info = cfg_print;
ctx.cmdclient = NULL;
cfg_cause = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist);
found++;
if (cfg_cause != NULL) {
*cause = cfg_cause;
goto error;
}
}
if (line != NULL)
xfree(line);
fclose(f);
return (found);
}
void
cfg_default_done(__unused struct cmd_q *cmdq)
{
if (--cfg_references != 0)
return;
cfg_finished = 1;
if (!RB_EMPTY(&sessions))
cfg_show_causes(RB_MIN(sessions, &sessions));
cmdq_free(cfg_cmd_q);
cfg_cmd_q = NULL;
if (cfg_client != NULL) {
/*
* The client command queue starts with client_exit set to 1 so
* only continue if not empty (that is, we have been delayed
* during configuration parsing for long enough that the
* MSG_COMMAND has arrived), else the client will exit before
* the MSG_COMMAND which might tell it not to.
*/
if (!TAILQ_EMPTY(&cfg_client->cmdq->queue))
cmdq_continue(cfg_client->cmdq);
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
cfg_show_causes(struct session *s)
{
struct window_pane *wp;
u_int i;
if (s == NULL || cfg_ncauses == 0)
return;
wp = s->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp);
for (i = 0; i < cfg_ncauses; i++) {
window_copy_add(wp, "%s", cfg_causes[i]);
free(cfg_causes[i]);
}
free(cfg_causes);
cfg_causes = NULL;
cfg_ncauses = 0;
return (0);
error:
fclose(f);
xasprintf(&ptr, "%s: %s at line %u", path, *cause, n);
xfree(*cause);
*cause = ptr;
return (1);
}

92
client-fn.c Normal file
View File

@@ -0,0 +1,92 @@
/* $Id: client-fn.c,v 1.6 2009-03-04 17:24:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
void
client_fill_session(struct msg_command_data *data)
{
char *env, *ptr1, *ptr2, buf[256];
size_t len;
const char *errstr;
long long ll;
data->pid = -1;
if ((env = getenv("TMUX")) == NULL)
return;
if ((ptr2 = strrchr(env, ',')) == NULL || ptr2 == env)
return;
for (ptr1 = ptr2 - 1; ptr1 > env && *ptr1 != ','; ptr1--)
;
if (*ptr1 != ',')
return;
ptr1++;
ptr2++;
len = ptr2 - ptr1 - 1;
if (len > (sizeof buf) - 1)
return;
memcpy(buf, ptr1, len);
buf[len] = '\0';
ll = strtonum(buf, 0, LONG_MAX, &errstr);
if (errstr != NULL)
return;
data->pid = ll;
ll = strtonum(ptr2, 0, UINT_MAX, &errstr);
if (errstr != NULL)
return;
data->idx = ll;
}
void
client_write_server(
struct client_ctx *cctx, enum hdrtype type, void *buf, size_t len)
{
struct hdr hdr;
hdr.type = type;
hdr.size = len;
buffer_write(cctx->srv_out, &hdr, sizeof hdr);
if (buf != NULL && len > 0)
buffer_write(cctx->srv_out, buf, len);
}
void
client_write_server2(struct client_ctx *cctx,
enum hdrtype type, void *buf1, size_t len1, void *buf2, size_t len2)
{
struct hdr hdr;
hdr.type = type;
hdr.size = len1 + len2;
buffer_write(cctx->srv_out, &hdr, sizeof hdr);
if (buf1 != NULL && len1 > 0)
buffer_write(cctx->srv_out, buf1, len1);
if (buf2 != NULL && len2 > 0)
buffer_write(cctx->srv_out, buf2, len2);
}

159
client-msg.c Normal file
View File

@@ -0,0 +1,159 @@
/* $Id: client-msg.c,v 1.18 2009-01-21 22:47:31 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
int client_msg_fn_detach(struct hdr *, struct client_ctx *, char **);
int client_msg_fn_error(struct hdr *, struct client_ctx *, char **);
int client_msg_fn_shutdown(struct hdr *, struct client_ctx *, char **);
int client_msg_fn_exit(struct hdr *, struct client_ctx *, char **);
int client_msg_fn_exited(struct hdr *, struct client_ctx *, char **);
int client_msg_fn_suspend(struct hdr *, struct client_ctx *, char **);
struct client_msg {
enum hdrtype type;
int (*fn)(struct hdr *, struct client_ctx *, char **);
};
struct client_msg client_msg_table[] = {
{ MSG_DETACH, client_msg_fn_detach },
{ MSG_ERROR, client_msg_fn_error },
{ MSG_EXIT, client_msg_fn_exit },
{ MSG_EXITED, client_msg_fn_exited },
{ MSG_SHUTDOWN, client_msg_fn_shutdown },
{ MSG_SUSPEND, client_msg_fn_suspend },
};
int
client_msg_dispatch(struct client_ctx *cctx, char **error)
{
struct hdr hdr;
struct client_msg *msg;
u_int i;
if (BUFFER_USED(cctx->srv_in) < sizeof hdr)
return (1);
memcpy(&hdr, BUFFER_OUT(cctx->srv_in), sizeof hdr);
if (BUFFER_USED(cctx->srv_in) < (sizeof hdr) + hdr.size)
return (1);
buffer_remove(cctx->srv_in, sizeof hdr);
for (i = 0; i < nitems(client_msg_table); i++) {
msg = client_msg_table + i;
if (msg->type == hdr.type) {
if (msg->fn(&hdr, cctx, error) != 0)
return (-1);
return (0);
}
}
fatalx("unexpected message");
}
int
client_msg_fn_error(struct hdr *hdr, struct client_ctx *cctx, char **error)
{
if (hdr->size > SIZE_MAX - 1)
fatalx("bad MSG_ERROR size");
*error = xmalloc(hdr->size + 1);
buffer_read(cctx->srv_in, *error, hdr->size);
(*error)[hdr->size] = '\0';
return (-1);
}
int
client_msg_fn_detach(
struct hdr *hdr, unused struct client_ctx *cctx, unused char **error)
{
if (hdr->size != 0)
fatalx("bad MSG_DETACH size");
client_write_server(cctx, MSG_EXITING, NULL, 0);
cctx->flags |= CCTX_DETACH;
return (0);
}
int
client_msg_fn_shutdown(
struct hdr *hdr, unused struct client_ctx *cctx, unused char **error)
{
if (hdr->size != 0)
fatalx("bad MSG_SHUTDOWN size");
client_write_server(cctx, MSG_EXITING, NULL, 0);
cctx->flags |= CCTX_SHUTDOWN;
return (0);
}
int
client_msg_fn_exit(
struct hdr *hdr, unused struct client_ctx *cctx, unused char **error)
{
if (hdr->size != 0)
fatalx("bad MSG_EXIT size");
client_write_server(cctx, MSG_EXITING, NULL, 0);
cctx->flags |= CCTX_EXIT;
return (0);
}
int
client_msg_fn_exited(
struct hdr *hdr, unused struct client_ctx *cctx, unused char **error)
{
if (hdr->size != 0)
fatalx("bad MSG_EXITED size");
return (-1);
}
int
client_msg_fn_suspend(
struct hdr *hdr, unused struct client_ctx *cctx, unused char **error)
{
struct sigaction act;
if (hdr->size != 0)
fatalx("bad MSG_SUSPEND size");
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART;
act.sa_handler = SIG_DFL;
if (sigaction(SIGTSTP, &act, NULL) != 0)
fatal("sigaction failed");
act.sa_handler = sighandler;
if (sigaction(SIGCONT, &act, NULL) != 0)
fatal("sigaction failed");
kill(getpid(), SIGTSTP);
return (0);
}

798
client.c
View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: client.c,v 1.46 2009-03-31 22:20:42 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -17,688 +17,212 @@
*/
#include <sys/types.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <errno.h>
#include <event.h>
#include <fcntl.h>
#include <signal.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "tmux.h"
struct tmuxproc *client_proc;
struct tmuxpeer *client_peer;
int client_flags;
struct event client_stdin;
enum {
CLIENT_EXIT_NONE,
CLIENT_EXIT_DETACHED,
CLIENT_EXIT_DETACHED_HUP,
CLIENT_EXIT_LOST_TTY,
CLIENT_EXIT_TERMINATED,
CLIENT_EXIT_LOST_SERVER,
CLIENT_EXIT_EXITED,
CLIENT_EXIT_SERVER_EXITED,
} client_exitreason = CLIENT_EXIT_NONE;
int client_exitval;
enum msgtype client_exittype;
const char *client_exitsession;
int client_attached;
void client_handle_winch(struct client_ctx *);
__dead void client_exec(const char *,const char *);
int client_get_lock(char *);
int client_connect(struct event_base *, const char *, int);
void client_send_identify(const char *, const char *);
void client_stdin_callback(int, short, void *);
void client_write(int, const char *, size_t);
void client_signal(int);
void client_dispatch(struct imsg *, void *);
void client_dispatch_attached(struct imsg *);
void client_dispatch_wait(struct imsg *, const char *);
const char *client_exit_message(void);
/*
* Get server create lock. If already held then server start is happening in
* another client, so block until the lock is released and return -2 to
* retry. Return -1 on failure to continue and start the server anyway.
*/
int
client_get_lock(char *lockfile)
client_init(char *path, struct client_ctx *cctx, int start_server, int flags)
{
int lockfd;
struct sockaddr_un sa;
struct stat sb;
struct msg_identify_data data;
struct winsize ws;
size_t size;
int mode;
struct buffer *b;
char *name;
log_debug("lock file is %s", lockfile);
if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) {
log_debug("open failed: %s", strerror(errno));
return (-1);
if (lstat(path, &sb) != 0) {
if (start_server && errno == ENOENT) {
if ((cctx->srv_fd = server_start(path)) == -1)
goto start_failed;
goto server_started;
}
goto not_found;
}
if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
log_debug("flock failed: %s", strerror(errno));
if (errno != EAGAIN)
return (lockfd);
while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
/* nothing */;
close(lockfd);
return (-2);
if (!S_ISSOCK(sb.st_mode)) {
errno = ENOTSOCK;
goto not_found;
}
log_debug("flock succeeded");
return (lockfd);
}
/* Connect client to server. */
int
client_connect(struct event_base *base, const char *path, int start_server)
{
struct sockaddr_un sa;
size_t size;
int fd, lockfd = -1, locked = 0;
char *lockfile = NULL;
memset(&sa, 0, sizeof sa);
sa.sun_family = AF_UNIX;
size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
if (size >= sizeof sa.sun_path) {
errno = ENAMETOOLONG;
return (-1);
}
log_debug("socket is %s", path);
retry:
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
return (-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)
goto failed;
if (!start_server)
goto failed;
close(fd);
if (!locked) {
xasprintf(&lockfile, "%s.lock", path);
if ((lockfd = client_get_lock(lockfile)) < 0) {
log_debug("didn't get lock (%d)", lockfd);
free(lockfile);
lockfile = NULL;
if (lockfd == -2)
goto retry;
}
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);
}
fd = server_start(base, lockfd, lockfile);
goto not_found;
}
if (locked && lockfd >= 0) {
free(lockfile);
close(lockfd);
}
setblocking(fd, 0);
return (fd);
if ((cctx->srv_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
fatal("socket");
failed:
if (locked) {
free(lockfile);
close(lockfd);
}
close(fd);
return (-1);
}
/* Get exit string from reason number. */
const char *
client_exit_message(void)
{
static char msg[256];
switch (client_exitreason) {
case CLIENT_EXIT_NONE:
break;
case CLIENT_EXIT_DETACHED:
if (client_exitsession != NULL) {
xsnprintf(msg, sizeof msg, "detached "
"(from session %s)", client_exitsession);
return (msg);
}
return ("detached");
case CLIENT_EXIT_DETACHED_HUP:
if (client_exitsession != NULL) {
xsnprintf(msg, sizeof msg, "detached and SIGHUP "
"(from session %s)", client_exitsession);
return (msg);
}
return ("detached and SIGHUP");
case CLIENT_EXIT_LOST_TTY:
return ("lost tty");
case CLIENT_EXIT_TERMINATED:
return ("terminated");
case CLIENT_EXIT_LOST_SERVER:
return ("lost server");
case CLIENT_EXIT_EXITED:
return ("exited");
case CLIENT_EXIT_SERVER_EXITED:
return ("server exited");
}
return ("unknown reason");
}
/* Client main loop. */
int
client_main(struct event_base *base, int argc, char **argv, int flags,
const char *shellcmd)
{
struct cmd *cmd;
struct cmd_list *cmdlist;
struct msg_command_data *data;
int cmdflags, fd, i;
const char *ttynam, *cwd;
pid_t ppid;
enum msgtype msg;
char *cause, path[PATH_MAX];
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. */
cmdflags = 0;
if (shellcmd != NULL) {
msg = MSG_SHELL;
cmdflags = CMD_STARTSERVER;
} else if (argc == 0) {
msg = MSG_COMMAND;
cmdflags = CMD_STARTSERVER;
} else {
msg = MSG_COMMAND;
/*
* It sucks parsing the command string twice (in client and
* later in server) but it is necessary to get the start server
* flag.
*/
cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause);
if (cmdlist == NULL) {
fprintf(stderr, "%s\n", cause);
return (1);
}
cmdflags &= ~CMD_STARTSERVER;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
if (cmd->entry->flags & CMD_STARTSERVER)
cmdflags |= CMD_STARTSERVER;
}
cmd_list_free(cmdlist);
}
/* Create client process structure (starts logging). */
client_proc = proc_start("client", base, 0, client_signal);
/* Initialize the client socket and start the server. */
fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
if (fd == -1) {
if (connect(
cctx->srv_fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
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));
if (unlink(path) != 0 || !start_server)
goto not_found;
if ((cctx->srv_fd = server_start(path)) == -1)
goto start_failed;
goto server_started;
}
return (1);
goto not_found;
}
client_peer = proc_add_peer(client_proc, fd, client_dispatch,
(void *)shellcmd);
/* Save these before pledge(). */
if ((cwd = getcwd(path, sizeof path)) == NULL) {
if ((cwd = find_home()) == NULL)
cwd = "/";
server_started:
if ((mode = fcntl(cctx->srv_fd, F_GETFL)) == -1)
fatal("fcntl failed");
if (fcntl(cctx->srv_fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed");
cctx->srv_in = buffer_create(BUFSIZ);
cctx->srv_out = buffer_create(BUFSIZ);
if (isatty(STDIN_FILENO)) {
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
fatal("ioctl(TIOCGWINSZ)");
data.version = PROTOCOL_VERSION;
data.flags = flags;
data.sx = ws.ws_col;
data.sy = ws.ws_row;
*data.tty = '\0';
if (getcwd(data.cwd, sizeof data.cwd) == NULL)
*data.cwd = '\0';
if ((name = ttyname(STDIN_FILENO)) == NULL)
fatal("ttyname failed");
if (strlcpy(data.tty, name, sizeof data.tty) >= sizeof data.tty)
fatalx("ttyname failed");
b = buffer_create(BUFSIZ);
cmd_send_string(b, getenv("TERM"));
client_write_server2(cctx, MSG_IDENTIFY,
&data, sizeof data, BUFFER_OUT(b), BUFFER_USED(b));
buffer_destroy(b);
}
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");
return (0);
start_failed:
log_warnx("server failed to start");
return (1);
not_found:
log_warn("server not found");
return (1);
}
int
client_main(struct client_ctx *cctx)
{
struct pollfd pfd;
char *error;
int xtimeout; /* Yay for ncurses namespace! */
siginit();
logfile("client");
#ifndef NO_SETPROCTITLE
setproctitle("client");
#endif
/* Free stuff that is not used in the client. */
options_free(global_options);
options_free(global_s_options);
options_free(global_w_options);
environ_free(global_environ);
/* Create stdin handler. */
setblocking(STDIN_FILENO, 0);
event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
client_stdin_callback, NULL);
if (client_flags & CLIENT_CONTROLCONTROL) {
if (tcgetattr(STDIN_FILENO, &saved_tio) != 0)
fatal("tcgetattr failed");
cfmakeraw(&tio);
tio.c_iflag = ICRNL|IXANY;
tio.c_oflag = OPOST|ONLCR;
#ifdef NOKERNINFO
tio.c_lflag = NOKERNINFO;
#endif
tio.c_cflag = CREAD|CS8|HUPCL;
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;
cfsetispeed(&tio, cfgetispeed(&saved_tio));
cfsetospeed(&tio, cfgetospeed(&saved_tio));
tcsetattr(STDIN_FILENO, TCSANOW, &tio);
}
/* Send identify messages. */
client_send_identify(ttynam, cwd);
/* Send first command. */
if (msg == MSG_COMMAND) {
/* How big is the command? */
size = 0;
for (i = 0; i < argc; i++)
size += strlen(argv[i]) + 1;
data = xmalloc((sizeof *data) + size);
/* Prepare command for server. */
data->argc = argc;
if (cmd_pack_argv(argc, argv, (char *)(data + 1), size) != 0) {
fprintf(stderr, "command too long\n");
free(data);
return (1);
error = NULL;
xtimeout = INFTIM;
while (!sigterm) {
if (sigchld) {
waitpid(WAIT_ANY, NULL, WNOHANG);
sigchld = 0;
}
size += sizeof *data;
/* Send the command. */
if (proc_send(client_peer, msg, -1, data, size) != 0) {
fprintf(stderr, "failed to send command\n");
free(data);
return (1);
if (sigwinch)
client_handle_winch(cctx);
if (sigcont) {
siginit();
client_write_server(cctx, MSG_WAKEUP, NULL, 0);
sigcont = 0;
}
free(data);
} else if (msg == MSG_SHELL)
proc_send(client_peer, msg, -1, NULL, 0);
/* Start main loop. */
proc_loop(client_proc, NULL);
switch (client_msg_dispatch(cctx, &error)) {
case -1:
goto out;
case 0:
/* May be more in buffer, don't let poll block. */
xtimeout = 0;
break;
default:
/* Out of data, poll may block. */
xtimeout = INFTIM;
break;
}
/* Print the exit message, if any, and exit. */
if (client_attached) {
if (client_exitreason != CLIENT_EXIT_NONE)
printf("[%s]\n", client_exit_message());
pfd.fd = cctx->srv_fd;
pfd.events = POLLIN;
if (BUFFER_USED(cctx->srv_out) > 0)
pfd.events |= POLLOUT;
ppid = getppid();
if (client_exittype == MSG_DETACHKILL && ppid > 1)
kill(ppid, SIGHUP);
} else if (client_flags & CLIENT_CONTROLCONTROL) {
if (client_exitreason != CLIENT_EXIT_NONE)
printf("%%exit %s\n", client_exit_message());
else
printf("%%exit\n");
printf("\033\\");
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
} else if (client_exitreason != CLIENT_EXIT_NONE)
fprintf(stderr, "%s\n", client_exit_message());
setblocking(STDIN_FILENO, 1);
return (client_exitval);
}
/* Send identify messages to server. */
void
client_send_identify(const char *ttynam, const char *cwd)
{
const char *s;
char **ss;
size_t sslen;
int fd, flags = client_flags;
pid_t pid;
proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
if ((s = getenv("TERM")) == NULL)
s = "";
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
strlen(ttynam) + 1);
proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
if ((fd = dup(STDIN_FILENO)) == -1)
fatal("dup failed");
proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
pid = getpid();
proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
for (ss = environ; *ss != NULL; ss++) {
sslen = strlen(*ss) + 1;
if (sslen > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
continue;
proc_send(client_peer, MSG_IDENTIFY_ENVIRON, -1, *ss, sslen);
}
proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0);
}
/* Callback for client stdin read events. */
void
client_stdin_callback(__unused int fd, __unused short events,
__unused void *arg)
{
struct msg_stdin_data data;
data.size = read(STDIN_FILENO, data.data, sizeof data.data);
if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
return;
proc_send(client_peer, MSG_STDIN, -1, &data, sizeof data);
if (data.size <= 0)
event_del(&client_stdin);
}
/* Force write to file descriptor. */
void
client_write(int fd, const char *data, size_t size)
{
ssize_t used;
while (size != 0) {
used = write(fd, data, size);
if (used == -1) {
if (errno == EINTR || errno == EAGAIN)
if (poll(&pfd, 1, xtimeout) == -1) {
if (errno == EAGAIN || errno == EINTR)
continue;
break;
fatal("poll failed");
}
data += used;
size -= used;
if (buffer_poll(&pfd, cctx->srv_in, cctx->srv_out) != 0)
goto server_dead;
}
out:
if (sigterm) {
printf("[terminated]\n");
return (1);
}
if (cctx->flags & CCTX_SHUTDOWN) {
printf("[server exited]\n");
return (0);
}
if (cctx->flags & CCTX_EXIT) {
printf("[exited]\n");
return (0);
}
if (cctx->flags & CCTX_DETACH) {
printf("[detached]\n");
return (0);
}
printf("[error: %s]\n", error);
return (1);
server_dead:
printf("[lost server]\n");
return (0);
}
/* Run command in shell; used for -c. */
__dead void
client_exec(const char *shell, const char *shellcmd)
{
const char *name, *ptr;
char *argv0;
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)
client_handle_winch(struct client_ctx *cctx)
{
struct sigaction sigact;
int status;
struct msg_resize_data data;
struct winsize ws;
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;
case SIGWINCH:
proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
break;
case SIGCONT:
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
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_stderr_data stderrdata;
int retval;
#ifdef __OpenBSD__
static int pledge_applied;
/*
* "sendfd" is no longer required once all of the identify messages
* have been sent. We know the server won't send us anything until that
* point (because we don't ask it to), so we can drop "sendfd" once we
* get the first message from the server.
*/
if (!pledge_applied) {
if (pledge("stdio unix proc exec tty", NULL) != 0)
fatal("pledge failed");
pledge_applied = 1;
};
#endif
data = imsg->data;
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
switch (imsg->hdr.type) {
case MSG_EXIT:
case MSG_SHUTDOWN:
if (datalen != sizeof retval && datalen != 0)
fatalx("bad MSG_EXIT size");
if (datalen == sizeof retval) {
memcpy(&retval, data, sizeof retval);
client_exitval = retval;
}
proc_exit(client_proc);
break;
case MSG_READY:
if (datalen != 0)
fatalx("bad MSG_READY size");
event_del(&client_stdin);
client_attached = 1;
proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
break;
case MSG_STDIN:
if (datalen != 0)
fatalx("bad MSG_STDIN size");
event_add(&client_stdin, NULL);
break;
case MSG_STDOUT:
if (datalen != sizeof stdoutdata)
fatalx("bad MSG_STDOUT size");
memcpy(&stdoutdata, data, sizeof stdoutdata);
client_write(STDOUT_FILENO, stdoutdata.data,
stdoutdata.size);
break;
case MSG_STDERR:
if (datalen != sizeof stderrdata)
fatalx("bad MSG_STDERR size");
memcpy(&stderrdata, data, sizeof stderrdata);
client_write(STDERR_FILENO, stderrdata.data,
stderrdata.size);
break;
case MSG_VERSION:
if (datalen != 0)
fatalx("bad MSG_VERSION size");
fprintf(stderr, "protocol version mismatch "
"(client %d, server %u)\n", PROTOCOL_VERSION,
imsg->hdr.peerid & 0xff);
client_exitval = 1;
proc_exit(client_proc);
break;
case MSG_SHELL:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_SHELL string");
clear_signals(0);
client_exec(data, shellcmd);
/* NOTREACHED */
case MSG_DETACH:
case MSG_DETACHKILL:
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
case MSG_EXITED:
proc_exit(client_proc);
break;
}
}
/* Dispatch imsgs in attached state (after MSG_READY). */
void
client_dispatch_attached(struct imsg *imsg)
{
struct sigaction sigact;
char *data;
ssize_t datalen;
data = imsg->data;
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
switch (imsg->hdr.type) {
case MSG_DETACH:
case MSG_DETACHKILL:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_DETACH string");
client_exitsession = xstrdup(data);
client_exittype = imsg->hdr.type;
if (imsg->hdr.type == MSG_DETACHKILL)
client_exitreason = CLIENT_EXIT_DETACHED_HUP;
else
client_exitreason = CLIENT_EXIT_DETACHED;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
case MSG_EXIT:
if (datalen != 0 && datalen != sizeof (int))
fatalx("bad MSG_EXIT size");
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
client_exitreason = CLIENT_EXIT_EXITED;
break;
case MSG_EXITED:
if (datalen != 0)
fatalx("bad MSG_EXITED size");
proc_exit(client_proc);
break;
case MSG_SHUTDOWN:
if (datalen != 0)
fatalx("bad MSG_SHUTDOWN size");
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
client_exitreason = CLIENT_EXIT_SERVER_EXITED;
client_exitval = 1;
break;
case MSG_SUSPEND:
if (datalen != 0)
fatalx("bad MSG_SUSPEND size");
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_DFL;
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
kill(getpid(), SIGTSTP);
break;
case MSG_LOCK:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_LOCK string");
system(data);
proc_send(client_peer, MSG_UNLOCK, -1, NULL, 0);
break;
}
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
fatal("ioctl failed");
data.sx = ws.ws_col;
data.sy = ws.ws_row;
client_write_server(cctx, MSG_RESIZE, &data, sizeof data);
sigwinch = 0;
}

161
clock.c Normal file
View File

@@ -0,0 +1,161 @@
/* $Id: clock.c,v 1.3 2009-03-27 16:59:57 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <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, u_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);
memcpy(&gc, &grid_default_cell, sizeof gc);
gc.fg = colour;
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);
gc.fg = 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;
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++) {
screen_write_cursormove(ctx, x, y + j);
for (i = 0; i < 5; i++) {
if (clock_table[idx][j][i])
gc.attr |= GRID_ATTR_REVERSE;
else
gc.attr &= ~GRID_ATTR_REVERSE;
screen_write_putc(ctx, &gc, ' ');
}
}
x += 6;
}
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-attach-session.c,v 1.24 2009-01-23 16:59:14 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,147 +18,63 @@
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
/*
* Attach existing session to the current terminal.
*/
enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_q *);
int cmd_attach_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_attach_session_entry = {
.name = "attach-session",
.alias = "attach",
.args = { "c:dErt:", 0, 0 },
.usage = "[-dEr] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION_WITHPANE,
.flags = CMD_STARTSERVER,
.exec = cmd_attach_session_exec
"attach-session", "attach",
"[-d] " CMD_TARGET_SESSION_USAGE,
CMD_DFLAG|CMD_CANTNEST|CMD_STARTSERVER,
cmd_target_init,
cmd_target_parse,
cmd_attach_session_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
enum cmd_retval
cmd_attach_session(struct cmd_q *cmdq, int dflag, int rflag, const char *cflag,
int Eflag)
int
cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct session *s = cmdq->state.tflag.s;
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;
char *cause, *cwd;
struct format_tree *ft;
struct cmd_target_data *data = self->data;
struct session *s;
char *cause;
if (ctx->curclient != NULL)
return (0);
if (RB_EMPTY(&sessions)) {
cmdq_error(cmdq, "no sessions");
return (CMD_RETURN_ERROR);
if (ARRAY_LENGTH(&sessions) == 0) {
ctx->error(ctx, "no sessions");
return (-1);
}
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) {
ctx->error(ctx, "not a terminal");
return (-1);
}
if (c == NULL)
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 (tty_open(&ctx->cmdclient->tty, &cause) != 0) {
ctx->error(ctx, "terminal open failed: %s", cause);
xfree(cause);
return (-1);
}
if (wl != NULL) {
if (wp != NULL)
window_set_active_pane(wp->window, wp);
session_set_current(s, wl);
}
if (data->flags & CMD_DFLAG)
server_write_session(s, MSG_DETACH, NULL, 0);
ctx->cmdclient->session = s;
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) {
TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session != s || c == c_loop)
continue;
server_client_detach(c_loop, MSG_DETACH);
}
}
if (!Eflag) {
update = options_get_string(s->options,
"update-environment");
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;
} else {
if (server_client_open(c, &cause) != 0) {
cmdq_error(cmdq, "open terminal failed: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (rflag)
c->flags |= CLIENT_READONLY;
if (dflag) {
TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session != s || c == c_loop)
continue;
server_client_detach(c_loop, MSG_DETACH);
}
}
if (!Eflag) {
update = options_get_string(s->options,
"update-environment");
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;
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;
}
server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
recalculate_sizes();
alerts_check_session(s);
server_update_socket();
server_redraw_client(ctx->cmdclient);
return (CMD_RETURN_NORMAL);
return (1);
}
enum cmd_retval
cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
return (cmd_attach_session(cmdq, args_has(args, 'd'),
args_has(args, 'r'), args_get(args, 'c'), args_has(args, 'E')));
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-bind-key.c,v 1.20 2009-03-28 14:08:09 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,154 +18,140 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Bind a key to a command, this recurses through cmd_*.
*/
enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmd_q *);
int cmd_bind_key_parse(struct cmd *, int, char **, char **);
int cmd_bind_key_exec(struct cmd *, struct cmd_ctx *);
void cmd_bind_key_send(struct cmd *, struct buffer *);
void cmd_bind_key_recv(struct cmd *, struct buffer *);
void cmd_bind_key_free(struct cmd *);
size_t cmd_bind_key_print(struct cmd *, char *, size_t);
enum cmd_retval cmd_bind_key_mode_table(struct cmd *, struct cmd_q *,
key_code);
const struct cmd_entry cmd_bind_key_entry = {
.name = "bind-key",
.alias = "bind",
.args = { "cnrR:t:T:", 1, -1 },
.usage = "[-cnr] [-t mode-table] [-R repeat-count] [-T key-table] key "
"command [arguments]",
.flags = 0,
.exec = cmd_bind_key_exec
struct cmd_bind_key_data {
int key;
int can_repeat;
struct cmd_list *cmdlist;
};
enum cmd_retval
cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
const struct cmd_entry cmd_bind_key_entry = {
"bind-key", "bind",
"[-r] key command [arguments]",
0,
NULL,
cmd_bind_key_parse,
cmd_bind_key_exec,
cmd_bind_key_send,
cmd_bind_key_recv,
cmd_bind_key_free,
cmd_bind_key_print
};
int
cmd_bind_key_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct args *args = self->args;
char *cause;
struct cmd_list *cmdlist;
key_code key;
const char *tablename;
struct cmd_bind_key_data *data;
int opt;
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);
self->data = data = xmalloc(sizeof *data);
data->can_repeat = 0;
data->cmdlist = NULL;
while ((opt = getopt(argc, argv, "r")) != -1) {
switch (opt) {
case 'r':
data->can_repeat = 1;
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (argc < 1)
goto usage;
key = key_string_lookup_string(args->argv[0]);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
cmdq_error(cmdq, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
if ((data->key = key_string_lookup_string(argv[0])) == KEYC_NONE) {
xasprintf(cause, "unknown key: %s", argv[0]);
goto error;
}
if (args_has(args, 't'))
return (cmd_bind_key_mode_table(self, cmdq, key));
argc--;
argv++;
if ((data->cmdlist = cmd_list_parse(argc, argv, cause)) == NULL)
goto error;
if (args_has(args, 'T'))
tablename = args_get(args, 'T');
else if (args_has(args, 'n'))
tablename = "root";
else
tablename = "prefix";
return (0);
cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0,
&cause);
if (cmdlist == NULL) {
cmdq_error(cmdq, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
key_bindings_add(tablename, key, args_has(args, 'r'), cmdlist);
return (CMD_RETURN_NORMAL);
error:
self->entry->free(self);
return (-1);
}
enum cmd_retval
cmd_bind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, key_code key)
int
cmd_bind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
{
struct args *args = self->args;
const char *tablename, *arg;
const struct mode_key_table *mtab;
struct mode_key_binding *mbind, mtmp;
enum mode_key_cmd cmd;
char *cause;
u_int repeat;
struct cmd_bind_key_data *data = self->data;
tablename = args_get(args, 't');
if ((mtab = mode_key_findtable(tablename)) == NULL) {
cmdq_error(cmdq, "unknown key table: %s", tablename);
return (CMD_RETURN_ERROR);
}
if (data == NULL)
return (0);
cmd = mode_key_fromstring(mtab->cmdstr, args->argv[1]);
if (cmd == MODEKEY_NONE) {
cmdq_error(cmdq, "unknown command: %s", args->argv[1]);
return (CMD_RETURN_ERROR);
}
key_bindings_add(data->key, data->can_repeat, data->cmdlist);
data->cmdlist = NULL; /* avoid free */
switch (cmd) {
case MODEKEYCOPY_APPENDSELECTION:
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);
}
}
break;
case MODEKEYCOPY_COPYPIPE:
if (args->argc != 3) {
cmdq_error(cmdq, "no argument given");
return (CMD_RETURN_ERROR);
}
arg = args->argv[2];
break;
default:
if (args->argc != 2) {
cmdq_error(cmdq, "no argument allowed");
return (CMD_RETURN_ERROR);
}
arg = NULL;
break;
}
repeat = 1;
if (args_has(args, 'R')) {
repeat = args_strtonum(args, 'R', 1, SHRT_MAX, &cause);
if (cause != NULL) {
cmdq_error(cmdq, "repeat count %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
mtmp.key = key;
mtmp.mode = !!args_has(args, 'c');
if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) == NULL) {
mbind = xmalloc(sizeof *mbind);
mbind->key = mtmp.key;
mbind->mode = mtmp.mode;
RB_INSERT(mode_key_tree, mtab->tree, mbind);
}
mbind->repeat = repeat;
mbind->cmd = cmd;
mbind->arg = arg != NULL ? xstrdup(arg) : NULL;
return (CMD_RETURN_NORMAL);
return (0);
}
void
cmd_bind_key_send(struct cmd *self, struct buffer *b)
{
struct cmd_bind_key_data *data = self->data;
buffer_write(b, data, sizeof *data);
cmd_list_send(data->cmdlist, b);
}
void
cmd_bind_key_recv(struct cmd *self, struct buffer *b)
{
struct cmd_bind_key_data *data;
self->data = data = xmalloc(sizeof *data);
buffer_read(b, data, sizeof *data);
data->cmdlist = cmd_list_recv(b);
}
void
cmd_bind_key_free(struct cmd *self)
{
struct cmd_bind_key_data *data = self->data;
if (data->cmdlist != NULL)
cmd_list_free(data->cmdlist);
xfree(data);
}
size_t
cmd_bind_key_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_bind_key_data *data = self->data;
size_t off = 0;
const char *skey;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len) {
skey = key_string_lookup_key(data->key);
off += xsnprintf(buf + off, len - off, " %s ", skey);
}
if (off < len)
off += cmd_list_print(data->cmdlist, buf + off, len - off);
return (off);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-break-pane.c,v 1.1 2009-03-07 09:29:54 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -26,89 +26,67 @@
* 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 *);
int cmd_break_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_break_pane_entry = {
.name = "break-pane",
.alias = "breakp",
.args = { "dPF:s:t:", 0, 0 },
.usage = "[-dP] [-F format] [-s src-pane] [-t dst-window]",
.sflag = CMD_PANE,
.tflag = CMD_WINDOW_INDEX,
.flags = 0,
.exec = cmd_break_pane_exec
"break-pane", "breakp",
CMD_PANE_WINDOW_USAGE " [-d]",
CMD_DFLAG,
cmd_pane_init,
cmd_pane_parse,
cmd_break_pane_exec,
cmd_pane_send,
cmd_pane_recv,
cmd_pane_free,
cmd_pane_print
};
enum cmd_retval
cmd_break_pane_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct winlink *wl = cmdq->state.sflag.wl;
struct session *src_s = cmdq->state.sflag.s;
struct session *dst_s = cmdq->state.tflag.s;
struct window_pane *wp = cmdq->state.sflag.wp;
struct window *w = wl->window;
char *name;
struct cmd_pane_data *data = self->data;
struct winlink *wl;
struct session *s;
struct window_pane *wp;
struct window *w;
char *cause;
int idx = cmdq->state.tflag.idx;
struct format_tree *ft;
const char *template;
char *cp;
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);
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
if (data->pane == -1)
wp = wl->window->active;
else {
wp = window_pane_at_index(wl->window, data->pane);
if (wp == NULL) {
ctx->error(ctx, "no pane: %d", data->pane);
return (-1);
}
}
if (window_count_panes(w) == 1) {
cmdq_error(cmdq, "can't break with only one pane");
return (CMD_RETURN_ERROR);
if (window_count_panes(wl->window) == 1) {
ctx->error(ctx, "can't break pane: %d", data->pane);
return (-1);
}
server_unzoom_window(w);
TAILQ_REMOVE(&w->panes, wp, entry);
window_lost_pane(w, wp);
layout_close_pane(wp);
w = wp->window = window_create1(dst_s->sx, dst_s->sy);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp;
name = default_window_name(w);
window_set_name(w, name);
free(name);
layout_init(w, wp);
wp->flags |= PANE_CHANGED;
if (idx == -1)
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'))
session_select(dst_s, wl->idx);
server_redraw_session(src_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 ((template = args_get(args, 'F')) == NULL)
template = BREAK_PANE_TEMPLATE;
ft = format_create(cmdq, 0);
format_defaults(ft, cmdq->state.c, dst_s, wl, wp);
cp = format_expand(ft, template);
cmdq_print(cmdq, "%s", cp);
free(cp);
format_free(ft);
TAILQ_REMOVE(&wl->window->panes, wp, entry);
if (wl->window->active == wp) {
wl->window->active = TAILQ_PREV(wp, window_panes, entry);
if (wl->window->active == NULL)
wl->window->active = TAILQ_NEXT(wp, entry);
}
return (CMD_RETURN_NORMAL);
window_fit_panes(wl->window);
w = wp->window = window_create1(s->sx, s->sy);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp;
window_fit_panes(w);
w->name = default_window_name(w);
wl = session_attach(s, w, -1, &cause); /* can't fail */
if (!(data->flags & CMD_DFLAG))
session_select(s, wl->idx);
server_redraw_session(s);
return (0);
}

View File

@@ -1,223 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Jonathan Alvarado <radobobo@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"
/*
* Write the entire contents of a pane to a buffer or stdout.
*/
enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmd_q *);
char *cmd_capture_pane_append(char *, size_t *, char *, size_t);
char *cmd_capture_pane_pending(struct args *, struct window_pane *,
size_t *);
char *cmd_capture_pane_history(struct args *, struct cmd_q *,
struct window_pane *, size_t *);
const struct cmd_entry cmd_capture_pane_entry = {
.name = "capture-pane",
.alias = "capturep",
.args = { "ab:CeE:JpPqS:t:", 0, 0 },
.usage = "[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] "
"[-S start-line]" CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_capture_pane_exec
};
char *
cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen)
{
buf = xrealloc(buf, *len + linelen + 1);
memcpy(buf + *len, line, linelen);
*len += linelen;
return (buf);
}
char *
cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
size_t *len)
{
struct evbuffer *pending;
char *buf, *line, tmp[5];
size_t linelen;
u_int i;
pending = input_pending(wp);
if (pending == NULL)
return (xstrdup(""));
line = EVBUFFER_DATA(pending);
linelen = EVBUFFER_LENGTH(pending);
buf = xstrdup("");
if (args_has(args, 'C')) {
for (i = 0; i < linelen; i++) {
if (line[i] >= ' ') {
tmp[0] = line[i];
tmp[1] = '\0';
} else
xsnprintf(tmp, sizeof tmp, "\\%03hho", line[i]);
buf = cmd_capture_pane_append(buf, len, tmp,
strlen(tmp));
}
} else
buf = cmd_capture_pane_append(buf, len, line, linelen);
return (buf);
}
char *
cmd_capture_pane_history(struct args *args, struct cmd_q *cmdq,
struct window_pane *wp, size_t *len)
{
struct grid *gd;
const struct grid_line *gl;
struct grid_cell *gc = NULL;
int n, with_codes, escape_c0, join_lines;
u_int i, sx, top, bottom, tmp;
char *cause, *buf, *line;
const char *Sflag, *Eflag;
size_t linelen;
sx = screen_size_x(&wp->base);
if (args_has(args, 'a')) {
gd = wp->saved_grid;
if (gd == NULL) {
if (!args_has(args, 'q')) {
cmdq_error(cmdq, "no alternate screen");
return (NULL);
}
return (xstrdup(""));
}
} else
gd = wp->base.grid;
Sflag = args_get(args, 'S');
if (Sflag != NULL && strcmp(Sflag, "-") == 0)
top = 0;
else {
n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause);
if (cause != NULL) {
top = gd->hsize;
free(cause);
} else if (n < 0 && (u_int) -n > gd->hsize)
top = 0;
else
top = gd->hsize + n;
if (top > gd->hsize + gd->sy - 1)
top = gd->hsize + gd->sy - 1;
}
Eflag = args_get(args, 'E');
if (Eflag != NULL && strcmp(Eflag, "-") == 0)
bottom = gd->hsize + gd->sy - 1;
else {
n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause);
if (cause != NULL) {
bottom = gd->hsize + gd->sy - 1;
free(cause);
} else if (n < 0 && (u_int) -n > gd->hsize)
bottom = 0;
else
bottom = gd->hsize + n;
if (bottom > gd->hsize + gd->sy - 1)
bottom = gd->hsize + gd->sy - 1;
}
if (bottom < top) {
tmp = bottom;
bottom = top;
top = tmp;
}
with_codes = args_has(args, 'e');
escape_c0 = args_has(args, 'C');
join_lines = args_has(args, 'J');
buf = NULL;
for (i = top; i <= bottom; i++) {
line = grid_string_cells(gd, 0, i, sx, &gc, with_codes,
escape_c0, !join_lines);
linelen = strlen(line);
buf = cmd_capture_pane_append(buf, len, line, linelen);
gl = grid_peek_line(gd, i);
if (!join_lines || !(gl->flags & GRID_LINE_WRAPPED))
buf[(*len)++] = '\n';
free(line);
}
return (buf);
}
enum cmd_retval
cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c;
struct window_pane *wp = cmdq->state.tflag.wp;
char *buf, *cause;
const char *bufname;
size_t len;
len = 0;
if (args_has(args, 'P'))
buf = cmd_capture_pane_pending(args, wp, &len);
else
buf = cmd_capture_pane_history(args, cmdq, wp, &len);
if (buf == NULL)
return (CMD_RETURN_ERROR);
if (args_has(args, 'p')) {
c = cmdq->client;
if (c == NULL ||
(c->session != NULL && !(c->flags & CLIENT_CONTROL))) {
cmdq_error(cmdq, "can't write to stdout");
free(buf);
return (CMD_RETURN_ERROR);
}
evbuffer_add(c->stdout_data, buf, len);
free(buf);
if (args_has(args, 'P') && len > 0)
evbuffer_add(c->stdout_data, "\n", 1);
server_client_push_stdout(c);
} else {
bufname = NULL;
if (args_has(args, 'b'))
bufname = args_get(args, 'b');
if (paste_set(buf, len, bufname, &cause) != 0) {
cmdq_error(cmdq, "%s", cause);
free(cause);
free(buf);
return (CMD_RETURN_ERROR);
}
}
return (CMD_RETURN_NORMAL);
}

View File

@@ -1,100 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include "tmux.h"
/*
* 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 *);
const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer",
.alias = NULL,
.args = { "F:t:", 0, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_choose_buffer_exec
};
enum cmd_retval
cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c = cmdq->state.c;
struct winlink *wl = cmdq->state.tflag.wl;
struct window_choose_data *cdata;
struct paste_buffer *pb;
char *action, *action_data;
const char *template;
u_int idx;
if (c == NULL) {
cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}
if ((template = args_get(args, 'F')) == NULL)
template = CHOOSE_BUFFER_TEMPLATE;
if (paste_get_top(NULL) == NULL)
return (CMD_RETURN_NORMAL);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (CMD_RETURN_NORMAL);
if (args->argc != 0)
action = xstrdup(args->argv[0]);
else
action = xstrdup("paste-buffer -b '%%'");
idx = 0;
pb = NULL;
while ((pb = paste_walk(pb)) != NULL) {
cdata = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = idx;
cdata->ft_template = xstrdup(template);
format_defaults_paste_buffer(cdata->ft, pb);
xasprintf(&action_data, "%s", paste_buffer_name(pb));
cdata->command = cmd_template_replace(action, action_data, 1);
free(action_data);
window_choose_add(wl->window->active, cdata);
idx++;
}
free(action);
window_choose_ready(wl->window->active, 0, NULL);
return (CMD_RETURN_NORMAL);
}

View File

@@ -1,134 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include "tmux.h"
/*
* 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 *);
void cmd_choose_client_callback(struct window_choose_data *);
const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client",
.alias = NULL,
.args = { "F:t:", 0, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_choose_client_exec
};
struct cmd_choose_client_data {
struct client *client;
};
enum cmd_retval
cmd_choose_client_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c = cmdq->state.c;
struct client *c1;
struct window_choose_data *cdata;
struct winlink *wl = cmdq->state.tflag.wl;
const char *template;
char *action;
u_int idx, cur;
if (c == NULL) {
cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (CMD_RETURN_NORMAL);
if ((template = args_get(args, 'F')) == NULL)
template = CHOOSE_CLIENT_TEMPLATE;
if (args->argc != 0)
action = xstrdup(args->argv[0]);
else
action = xstrdup("detach-client -t '%%'");
cur = idx = 0;
TAILQ_FOREACH(c1, &clients, entry) {
if (c1->session == NULL || c1->tty.path == NULL)
continue;
if (c1 == cmdq->client)
cur = idx;
cdata = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = idx;
cdata->ft_template = xstrdup(template);
format_add(cdata->ft, "line", "%u", idx);
format_defaults(cdata->ft, c1, NULL, NULL, NULL);
cdata->command = cmd_template_replace(action, c1->tty.path, 1);
window_choose_add(wl->window->active, cdata);
idx++;
}
free(action);
window_choose_ready(wl->window->active, cur,
cmd_choose_client_callback);
return (CMD_RETURN_NORMAL);
}
void
cmd_choose_client_callback(struct window_choose_data *cdata)
{
struct client *c;
u_int idx;
if (cdata == NULL)
return;
if (cdata->start_client->flags & CLIENT_DEAD)
return;
idx = 0;
TAILQ_FOREACH(c, &clients, entry) {
if (idx == cdata->idx)
break;
idx++;
}
if (c == NULL || c->session == NULL)
return;
window_choose_data_run(cdata);
}

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

@@ -0,0 +1,107 @@
/* $Id: cmd-choose-session.c,v 1.6 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Enter choice mode to choose a session.
*/
int cmd_choose_session_exec(struct cmd *, struct cmd_ctx *);
void cmd_choose_session_callback(void *, int);
const struct cmd_entry cmd_choose_session_entry = {
"choose-session", NULL,
CMD_TARGET_WINDOW_USAGE,
0,
cmd_target_init,
cmd_target_parse,
cmd_choose_session_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
struct cmd_choose_session_data {
u_int client;
};
int
cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct cmd_choose_session_data *cdata;
struct winlink *wl;
struct session *s;
u_int i, idx, cur;
if (ctx->curclient == NULL) {
ctx->error(ctx, "must be run interactively");
return (-1);
}
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (0);
cur = idx = 0;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
if (s == ctx->curclient->session)
cur = idx;
idx++;
window_choose_add(wl->window->active, i,
"%s: %u windows [%ux%u]%s", s->name,
winlink_count(&s->windows), s->sx, s->sy,
s->flags & SESSION_UNATTACHED ? "" : " (attached)");
}
cdata = xmalloc(sizeof *cdata);
cdata->client = server_client_index(ctx->curclient);
window_choose_ready(
wl->window->active, cur, cmd_choose_session_callback, cdata);
return (0);
}
void
cmd_choose_session_callback(void *data, int idx)
{
struct cmd_choose_session_data *cdata = data;
struct client *c;
if (idx != -1 && cdata->client <= ARRAY_LENGTH(&clients) - 1) {
c = ARRAY_ITEM(&clients, cdata->client);
if (c != NULL && (u_int) idx <= ARRAY_LENGTH(&sessions) - 1) {
c->session = ARRAY_ITEM(&sessions, idx);
recalculate_sizes();
server_redraw_client(c);
}
}
xfree(cdata);
}

View File

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

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

@@ -0,0 +1,106 @@
/* $Id: cmd-choose-window.c,v 1.7 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Enter choice mode to choose a window.
*/
int cmd_choose_window_exec(struct cmd *, struct cmd_ctx *);
void cmd_choose_window_callback(void *, int);
const struct cmd_entry cmd_choose_window_entry = {
"choose-window", NULL,
CMD_TARGET_WINDOW_USAGE,
0,
cmd_target_init,
cmd_target_parse,
cmd_choose_window_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
struct cmd_choose_window_data {
u_int session;
};
int
cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct cmd_choose_window_data *cdata;
struct session *s;
struct winlink *wl, *wm;
struct window *w;
u_int idx, cur;
if (ctx->curclient == NULL) {
ctx->error(ctx, "must be run interactively");
return (-1);
}
s = ctx->curclient->session;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (0);
cur = idx = 0;
RB_FOREACH(wm, winlinks, &s->windows) {
w = wm->window;
if (wm == s->curw)
cur = idx;
idx++;
window_choose_add(wl->window->active,
wm->idx, "%3d: %s [%ux%u] (%u panes)", wm->idx, w->name,
w->sx, w->sy, window_count_panes(w));
}
cdata = xmalloc(sizeof *cdata);
if (session_index(s, &cdata->session) != 0)
fatalx("session not found");
window_choose_ready(
wl->window->active, cur, cmd_choose_window_callback, cdata);
return (0);
}
void
cmd_choose_window_callback(void *data, int idx)
{
struct cmd_choose_window_data *cdata = data;
struct session *s;
if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) {
s = ARRAY_ITEM(&sessions, cdata->session);
if (s != NULL && session_select(s, idx) == 0)
server_redraw_session(s);
recalculate_sizes();
}
xfree(cdata);
}

54
cmd-clock-mode.c Normal file
View File

@@ -0,0 +1,54 @@
/* $Id: cmd-clock-mode.c,v 1.3 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Enter clock mode.
*/
int cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_clock_mode_entry = {
"clock-mode", NULL,
CMD_TARGET_WINDOW_USAGE,
0,
cmd_target_init,
cmd_target_parse,
cmd_clock_mode_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
int
cmd_clock_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
window_pane_set_mode(wl->window->active, &window_clock_mode);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-command-prompt.c,v 1.16 2009-02-16 18:58:14 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -19,9 +19,7 @@
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "tmux.h"
@@ -29,146 +27,152 @@
* Prompt for command in client.
*/
enum cmd_retval cmd_command_prompt_exec(struct cmd *, struct cmd_q *);
void cmd_command_prompt_init(struct cmd *, int);
int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *);
int cmd_command_prompt_callback(void *, const char *);
void cmd_command_prompt_free(void *);
const struct cmd_entry cmd_command_prompt_entry = {
.name = "command-prompt",
.alias = NULL,
.args = { "I:p:t:", 0, 1 },
.usage = "[-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
"[template]",
.tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_command_prompt_exec
"command-prompt", NULL,
CMD_TARGET_CLIENT_USAGE " [template]",
CMD_ARG01,
cmd_command_prompt_init,
cmd_target_parse,
cmd_command_prompt_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
struct cmd_command_prompt_cdata {
struct cmd_command_prompt_data {
struct client *c;
char *inputs;
char *next_input;
char *next_prompt;
char *prompts;
char *template;
int idx;
};
enum cmd_retval
cmd_command_prompt_exec(struct cmd *self, struct cmd_q *cmdq)
void
cmd_command_prompt_init(struct cmd *self, int key)
{
struct args *args = self->args;
const char *inputs, *prompts;
struct cmd_command_prompt_cdata *cdata;
struct client *c = cmdq->state.c;
char *prompt, *ptr, *input = NULL;
size_t n;
struct cmd_target_data *data;
cmd_target_init(self, key);
data = self->data;
switch (key) {
case ',':
data->arg = xstrdup("rename-window '%%'");
break;
case '.':
data->arg = xstrdup("move-window -t '%%'");
break;
case 'f':
data->arg = xstrdup("find-window '%%'");
break;
}
}
int
cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct cmd_command_prompt_data *cdata;
struct client *c;
char *hdr, *ptr;
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
if (c->prompt_string != NULL)
return (CMD_RETURN_NORMAL);
return (0);
cdata = xmalloc(sizeof *cdata);
cdata->c = c;
cdata->idx = 1;
cdata->inputs = NULL;
cdata->next_input = NULL;
cdata->next_prompt = NULL;
cdata->prompts = NULL;
cdata->template = NULL;
if (args->argc != 0)
cdata->template = xstrdup(args->argv[0]);
else
cdata->template = xstrdup("%1");
if ((prompts = args_get(args, 'p')) != NULL)
cdata->prompts = xstrdup(prompts);
else if (args->argc != 0) {
n = strcspn(cdata->template, " ,");
xasprintf(&cdata->prompts, "(%.*s) ", (int) n, cdata->template);
} else
cdata->prompts = xstrdup(":");
/* Get first prompt. */
cdata->next_prompt = cdata->prompts;
ptr = strsep(&cdata->next_prompt, ",");
if (prompts == NULL)
prompt = xstrdup(ptr);
else
xasprintf(&prompt, "%s ", ptr);
/* Get initial prompt input. */
if ((inputs = args_get(args, 'I')) != NULL) {
cdata->inputs = xstrdup(inputs);
cdata->next_input = cdata->inputs;
input = strsep(&cdata->next_input, ",");
if (data->arg != NULL) {
cdata->template = xstrdup(data->arg);
if ((ptr = strchr(data->arg, ' ')) == NULL)
ptr = strchr(data->arg, '\0');
xasprintf(&hdr, "(%.*s) ", (int) (ptr - data->arg), data->arg);
} else {
cdata->template = NULL;
hdr = xstrdup(":");
}
status_prompt_set(c, hdr, cmd_command_prompt_callback, cdata, 0);
xfree(hdr);
status_prompt_set(c, prompt, input, cmd_command_prompt_callback,
cmd_command_prompt_free, cdata, 0);
free(prompt);
return (CMD_RETURN_NORMAL);
return (0);
}
int
cmd_command_prompt_callback(void *data, const char *s)
{
struct cmd_command_prompt_cdata *cdata = data;
struct cmd_command_prompt_data *cdata = data;
struct client *c = cdata->c;
struct cmd_list *cmdlist;
char *cause, *new_template, *prompt, *ptr;
char *input = NULL;
struct cmd_ctx ctx;
char *cause, *ptr, *buf, ch;
size_t len, slen;
if (s == NULL)
if (s == NULL) {
xfree(cdata);
return (0);
new_template = cmd_template_replace(cdata->template, s, cdata->idx);
free(cdata->template);
cdata->template = new_template;
/*
* Check if there are more prompts; if so, get its respective input
* and update the prompt data.
*/
if ((ptr = strsep(&cdata->next_prompt, ",")) != NULL) {
xasprintf(&prompt, "%s ", ptr);
input = strsep(&cdata->next_input, ",");
status_prompt_update(c, prompt, input);
free(prompt);
cdata->idx++;
return (1);
}
slen = strlen(s);
if (cmd_string_parse(new_template, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(c, "%s", cause);
free(cause);
len = 0;
buf = NULL;
if (cdata->template != NULL) {
ptr = cdata->template;
while (*ptr != '\0') {
switch (ch = *ptr++) {
case '%':
if (*ptr != '%')
break;
ptr++;
buf = xrealloc(buf, 1, len + slen + 1);
memcpy(buf + len, s, slen);
len += slen;
break;
default:
buf = xrealloc(buf, 1, len + 2);
buf[len++] = ch;
break;
}
}
return (0);
}
xfree(cdata->template);
cmdq_run(c->cmdq, cmdlist, NULL);
buf[len] = '\0';
s = buf;
}
xfree(cdata);
if (cmd_string_parse(s, &cmdlist, &cause) != 0) {
if (cause == NULL)
return (0);
*cause = toupper((u_char) *cause);
status_message_set(c, cause);
xfree(cause);
cmdlist = NULL;
}
if (buf != NULL)
xfree(buf);
if (cmdlist == NULL)
return (0);
ctx.msgdata = NULL;
ctx.cursession = c->session;
ctx.curclient = c;
ctx.error = key_bindings_error;
ctx.print = key_bindings_print;
ctx.info = key_bindings_info;
ctx.cmdclient = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist);
if (c->prompt_callbackfn != (void *) &cmd_command_prompt_callback)
if (c->prompt_callback != (void *) &cmd_command_prompt_callback)
return (1);
return (0);
}
void
cmd_command_prompt_free(void *data)
{
struct cmd_command_prompt_cdata *cdata = data;
free(cdata->inputs);
free(cdata->prompts);
free(cdata->template);
free(cdata);
}

View File

@@ -1,126 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.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"
/*
* Asks for confirmation before executing a command.
*/
enum cmd_retval cmd_confirm_before_exec(struct cmd *, struct cmd_q *);
int cmd_confirm_before_callback(void *, const char *);
void cmd_confirm_before_free(void *);
const struct cmd_entry cmd_confirm_before_entry = {
.name = "confirm-before",
.alias = "confirm",
.args = { "p:t:", 1, 1 },
.usage = "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
.tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_confirm_before_exec
};
struct cmd_confirm_before_data {
char *cmd;
struct client *client;
};
enum cmd_retval
cmd_confirm_before_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct cmd_confirm_before_data *cdata;
struct client *c = cmdq->state.c;
char *cmd, *copy, *new_prompt, *ptr;
const char *prompt;
if ((prompt = args_get(args, 'p')) != NULL)
xasprintf(&new_prompt, "%s ", prompt);
else {
ptr = copy = xstrdup(args->argv[0]);
cmd = strsep(&ptr, " \t");
xasprintf(&new_prompt, "Confirm '%s'? (y/n) ", cmd);
free(copy);
}
cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(args->argv[0]);
cdata->client = c;
cdata->client->references++;
status_prompt_set(c, new_prompt, NULL,
cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
PROMPT_SINGLE);
free(new_prompt);
return (CMD_RETURN_NORMAL);
}
int
cmd_confirm_before_callback(void *data, const char *s)
{
struct cmd_confirm_before_data *cdata = data;
struct client *c = cdata->client;
struct cmd_list *cmdlist;
char *cause;
if (c->flags & CLIENT_DEAD)
return (0);
if (s == NULL || *s == '\0')
return (0);
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
return (0);
if (cmd_string_parse(cdata->cmd, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) {
cmdq_error(c->cmdq, "%s", cause);
free(cause);
}
return (0);
}
cmdq_run(c->cmdq, cmdlist, NULL);
cmd_list_free(cmdlist);
return (0);
}
void
cmd_confirm_before_free(void *data)
{
struct cmd_confirm_before_data *cdata = data;
struct client *c = cdata->client;
server_client_unref(c);
free(cdata->cmd);
free(cdata);
}

222
cmd-copy-buffer.c Normal file
View File

@@ -0,0 +1,222 @@
/* $Id: cmd-copy-buffer.c,v 1.1 2009-02-03 17:21:19 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.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 <stdlib.h>
#include "tmux.h"
/*
* Copies a session paste buffer to another session.
*/
int cmd_copy_buffer_parse(struct cmd *, int, char **, char **);
int cmd_copy_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_copy_buffer_send(struct cmd *, struct buffer *);
void cmd_copy_buffer_recv(struct cmd *, struct buffer *);
void cmd_copy_buffer_free(struct cmd *);
void cmd_copy_buffer_init(struct cmd *, int);
size_t cmd_copy_buffer_print(struct cmd *, char *, size_t);
struct cmd_copy_buffer_data {
char *dst_session;
char *src_session;
int dst_idx;
int src_idx;
};
const struct cmd_entry cmd_copy_buffer_entry = {
"copy-buffer", "copyb",
"[-a src-index] [-b dst-index] [-s src-session] [-t dst-session]",
0,
cmd_copy_buffer_init,
cmd_copy_buffer_parse,
cmd_copy_buffer_exec,
cmd_copy_buffer_send,
cmd_copy_buffer_recv,
cmd_copy_buffer_free,
cmd_copy_buffer_print
};
void
cmd_copy_buffer_init(struct cmd *self, unused int arg)
{
struct cmd_copy_buffer_data *data;
self->data = data = xmalloc(sizeof *data);
data->dst_session = NULL;
data->src_session = NULL;
data->dst_idx = -1;
data->src_idx = -1;
}
int
cmd_copy_buffer_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_copy_buffer_data *data;
const char *errstr;
int n, opt;
self->entry->init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "a:b:s:t:")) != -1) {
switch (opt) {
case 'a':
if (data->src_idx == -1) {
n = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr != NULL) {
xasprintf(cause, "buffer %s", errstr);
goto error;
}
data->src_idx = n;
}
break;
case 'b':
if (data->dst_idx == -1) {
n = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr != NULL) {
xasprintf(cause, "buffer %s", errstr);
goto error;
}
data->dst_idx = n;
}
break;
case 's':
if (data->src_session == NULL)
data->src_session = xstrdup(optarg);
break;
case 't':
if (data->dst_session == NULL)
data->dst_session = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
error:
self->entry->free(self);
return (-1);
}
int
cmd_copy_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_copy_buffer_data *data = self->data;
struct paste_buffer *pb;
struct session *dst_session, *src_session;
u_int limit;
if ((dst_session = cmd_find_session(ctx, data->dst_session)) == NULL ||
(src_session = cmd_find_session(ctx, data->src_session)) == NULL)
return (-1);
if (data->src_idx == -1) {
if ((pb = paste_get_top(&src_session->buffers)) == NULL) {
ctx->error(ctx, "no buffers");
return (-1);
}
} else {
if ((pb = paste_get_index(&src_session->buffers,
data->src_idx)) == NULL) {
ctx->error(ctx, "no buffer %d", data->src_idx);
return (-1);
}
}
limit = options_get_number(&dst_session->options, "buffer-limit");
if (data->dst_idx == -1) {
paste_add(&dst_session->buffers, xstrdup(pb->data), limit);
return (0);
}
if (paste_replace(&dst_session->buffers, data->dst_idx,
xstrdup(pb->data)) != 0) {
ctx->error(ctx, "no buffer %d", data->dst_idx);
return (-1);
}
return (0);
}
void
cmd_copy_buffer_send(struct cmd *self, struct buffer *b)
{
struct cmd_copy_buffer_data *data = self->data;
buffer_write(b, data, sizeof *data);
cmd_send_string(b, data->dst_session);
cmd_send_string(b, data->src_session);
}
void
cmd_copy_buffer_recv(struct cmd *self, struct buffer *b)
{
struct cmd_copy_buffer_data *data;
self->data = data = xmalloc(sizeof *data);
buffer_read(b, data, sizeof *data);
data->dst_session = cmd_recv_string(b);
data->src_session = cmd_recv_string(b);
}
void
cmd_copy_buffer_free(struct cmd *self)
{
struct cmd_copy_buffer_data *data = self->data;
if (data->dst_session != NULL)
xfree(data->dst_session);
if (data->src_session != NULL)
xfree(data->src_session);
xfree(data);
}
size_t
cmd_copy_buffer_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_copy_buffer_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->src_idx != -1) {
off += xsnprintf(buf + off, len - off, " -a %d",
data->src_idx);
}
if (off < len && data->dst_idx != -1) {
off += xsnprintf(buf + off, len - off, " -b %d",
data->dst_idx);
}
if (off < len && data->src_session != NULL) {
off += cmd_prarg(buf + off, len - off, " -s ",
data->src_session);
}
if (off < len && data->dst_session != NULL) {
off += cmd_prarg(buf + off, len - off, " -t ",
data->dst_session);
}
return (off);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-copy-mode.c,v 1.16 2009-02-25 21:56:46 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -21,69 +21,36 @@
#include "tmux.h"
/*
* Enter copy or clock mode.
* Enter copy mode.
*/
enum cmd_retval cmd_copy_mode_exec(struct cmd *, struct cmd_q *);
int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_copy_mode_entry = {
.name = "copy-mode",
.alias = NULL,
.args = { "Met:u", 0, 0 },
.usage = "[-Mu] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_copy_mode_exec
"copy-mode", NULL,
CMD_TARGET_WINDOW_USAGE,
CMD_UFLAG,
cmd_target_init,
cmd_target_parse,
cmd_copy_mode_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
NULL
};
const struct cmd_entry cmd_clock_mode_entry = {
.name = "clock-mode",
.alias = NULL,
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_copy_mode_exec
};
enum cmd_retval
cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c = cmdq->client;
struct session *s;
struct window_pane *wp = cmdq->state.tflag.wp;
struct cmd_target_data *data = self->data;
struct winlink *wl;
if (args_has(args, 'M')) {
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 ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (self->entry == &cmd_clock_mode_entry) {
window_pane_set_mode(wp, &window_clock_mode);
return (CMD_RETURN_NORMAL);
}
window_pane_set_mode(wl->window->active, &window_copy_mode);
if (data->flags & CMD_UFLAG)
window_copy_pageup(wl->window->active);
if (wp->mode != &window_copy_mode) {
if (window_pane_set_mode(wp, &window_copy_mode) != 0)
return (CMD_RETURN_NORMAL);
window_copy_init_from_pane(wp, 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'))
window_copy_pageup(wp, 0);
return (CMD_RETURN_NORMAL);
return (0);
}

61
cmd-delete-buffer.c Normal file
View File

@@ -0,0 +1,61 @@
/* $Id: cmd-delete-buffer.c,v 1.4 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Delete a paste buffer.
*/
int cmd_delete_buffer_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_delete_buffer_entry = {
"delete-buffer", "deleteb",
CMD_BUFFER_SESSION_USAGE,
0,
cmd_buffer_init,
cmd_buffer_parse,
cmd_delete_buffer_exec,
cmd_buffer_send,
cmd_buffer_recv,
cmd_buffer_free,
cmd_buffer_print
};
int
cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_buffer_data *data = self->data;
struct session *s;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (data->buffer == -1)
paste_free_top(&s->buffers);
else if (paste_free_index(&s->buffers, data->buffer) != 0) {
ctx->error(ctx, "no buffer %d", data->buffer);
return (-1);
}
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-detach-client.c,v 1.7 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,80 +18,37 @@
#include <sys/types.h>
#include <string.h>
#include "tmux.h"
/*
* Detach a client.
*/
enum cmd_retval cmd_detach_client_exec(struct cmd *, struct cmd_q *);
int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_detach_client_entry = {
.name = "detach-client",
.alias = "detach",
.args = { "as:t:P", 0, 0 },
.usage = "[-P] [-a] [-s target-session] " CMD_TARGET_CLIENT_USAGE,
.sflag = CMD_SESSION,
.tflag = CMD_CLIENT,
.flags = CMD_READONLY,
.exec = cmd_detach_client_exec
"detach-client", "detach",
CMD_TARGET_CLIENT_USAGE,
0,
cmd_target_init,
cmd_target_parse,
cmd_detach_client_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
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
cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c = cmdq->state.c, *cloop;
struct session *s;
enum msgtype msgtype;
struct cmd_target_data *data = self->data;
struct client *c;
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 ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
if (args_has(args, 'P'))
msgtype = MSG_DETACHKILL;
else
msgtype = MSG_DETACH;
server_write_client(c, MSG_DETACH, NULL, 0);
if (args_has(args, 's')) {
s = cmdq->state.sflag.s;
TAILQ_FOREACH(cloop, &clients, entry) {
if (cloop->session == s)
server_client_detach(cloop, msgtype);
}
return (CMD_RETURN_STOP);
}
if (args_has(args, 'a')) {
TAILQ_FOREACH(cloop, &clients, entry) {
if (cloop->session != NULL && cloop != c)
server_client_detach(cloop, msgtype);
}
return (CMD_RETURN_NORMAL);
}
server_client_detach(c, msgtype);
return (CMD_RETURN_STOP);
return (0);
}

View File

@@ -1,88 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.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 <time.h>
#include "tmux.h"
/*
* 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 *);
const struct cmd_entry cmd_display_message_entry = {
.name = "display-message",
.alias = "display",
.args = { "c:pt:F:", 0, 1 },
.usage = "[-p] [-c target-client] [-F format] "
CMD_TARGET_PANE_USAGE " [message]",
.cflag = CMD_CLIENT_CANFAIL,
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_display_message_exec
};
enum cmd_retval
cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c = cmdq->state.c;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl;
struct window_pane *wp = cmdq->state.tflag.wp;
const char *template;
char *msg;
struct format_tree *ft;
if (args_has(args, 'F') && args->argc != 0) {
cmdq_error(cmdq, "only one of -F or argument must be given");
return (CMD_RETURN_ERROR);
}
template = args_get(args, 'F');
if (args->argc != 0)
template = args->argv[0];
if (template == NULL)
template = DISPLAY_MESSAGE_TEMPLATE;
ft = format_create(cmdq, 0);
format_defaults(ft, c, s, wl, wp);
msg = format_expand_time(ft, template, time(NULL));
if (args_has(self->args, 'p'))
cmdq_print(cmdq, "%s", msg);
else if (c != NULL)
status_message_set(c, "%s", msg);
free(msg);
format_free(ft);
return (CMD_RETURN_NORMAL);
}

View File

@@ -1,97 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Display panes on a client.
*/
static enum cmd_retval cmd_display_panes_exec(struct cmd *, struct cmd_q *);
static void cmd_display_panes_callback(struct client *,
struct window_pane *);
const struct cmd_entry cmd_display_panes_entry = {
.name = "display-panes",
.alias = "displayp",
.args = { "t:", 0, 1 },
.usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_display_panes_exec
};
static enum cmd_retval
cmd_display_panes_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c = cmdq->state.c;
if (c->identify_callback != NULL)
return (CMD_RETURN_NORMAL);
c->identify_callback = cmd_display_panes_callback;
if (args->argc != 0)
c->identify_callback_data = xstrdup(args->argv[0]);
else
c->identify_callback_data = xstrdup("select-pane -t '%%'");
server_set_identify(c);
return (CMD_RETURN_NORMAL);
}
static void
cmd_display_panes_callback(struct client *c, struct window_pane *wp)
{
struct cmd_list *cmdlist;
char *template, *cmd, *expanded, *cause;
template = c->identify_callback_data;
if (wp != NULL) {
xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(template, expanded, 1);
if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(c, "%s", cause);
free(cause);
}
} else {
cmdq_run(c->cmdq, cmdlist, NULL);
cmd_list_free(cmdlist);
}
free(cmd);
free(expanded);
}
free(c->identify_callback_data);
c->identify_callback_data = NULL;
c->identify_callback = NULL;
}

61
cmd-down-pane.c Normal file
View File

@@ -0,0 +1,61 @@
/* $Id: cmd-down-pane.c,v 1.7 2009-04-01 21:10:08 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Move down a pane.
*/
int cmd_down_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_down_pane_entry = {
"down-pane", "downp",
CMD_TARGET_WINDOW_USAGE,
0,
cmd_target_init,
cmd_target_parse,
cmd_down_pane_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
int
cmd_down_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct window *w;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
w = wl->window;
do {
w->active = TAILQ_NEXT(w->active, entry);
if (w->active == NULL)
w->active = TAILQ_FIRST(&w->panes);
layout_refresh(w, 1);
} while (w->active->flags & PANE_HIDDEN);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-find-window.c,v 1.6 2009-03-29 11:18:28 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,8 +18,6 @@
#include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -28,156 +26,91 @@
* Find window containing text.
*/
#define FIND_WINDOW_TEMPLATE \
"#{window_index}: #{window_name} " \
"[#{window_width}x#{window_height}] " \
"(#{window_panes} panes) #{window_find_matches}"
int cmd_find_window_exec(struct cmd *, struct cmd_ctx *);
enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmd_q *);
void cmd_find_window_callback(struct window_choose_data *);
/* Flags for determining matching behavior. */
#define CMD_FIND_WINDOW_BY_TITLE 0x1
#define CMD_FIND_WINDOW_BY_CONTENT 0x2
#define CMD_FIND_WINDOW_BY_NAME 0x4
#define CMD_FIND_WINDOW_ALL \
(CMD_FIND_WINDOW_BY_TITLE | \
CMD_FIND_WINDOW_BY_CONTENT | \
CMD_FIND_WINDOW_BY_NAME)
void cmd_find_window_callback(void *, int);
char *cmd_find_window_search(struct window_pane *, const char *);
const struct cmd_entry cmd_find_window_entry = {
.name = "find-window",
.alias = "findw",
.args = { "F:CNt:T", 1, 4 },
.usage = "[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string",
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_find_window_exec
"find-window", "findw",
CMD_TARGET_WINDOW_USAGE " match-string",
CMD_ARG1,
cmd_target_init,
cmd_target_parse,
cmd_find_window_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
struct cmd_find_window_data {
struct winlink *wl;
char *list_ctx;
u_int pane_id;
TAILQ_ENTRY(cmd_find_window_data) entry;
u_int session;
};
TAILQ_HEAD(cmd_find_window_list, cmd_find_window_data);
u_int cmd_find_window_match_flags(struct args *);
void cmd_find_window_match(struct cmd_find_window_list *, int,
struct winlink *, const char *, const char *);
u_int
cmd_find_window_match_flags(struct args *args)
int
cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
u_int match_flags = 0;
/* Turn on flags based on the options. */
if (args_has(args, 'T'))
match_flags |= CMD_FIND_WINDOW_BY_TITLE;
if (args_has(args, 'C'))
match_flags |= CMD_FIND_WINDOW_BY_CONTENT;
if (args_has(args, 'N'))
match_flags |= CMD_FIND_WINDOW_BY_NAME;
/* If none of the flags were set, default to matching anything. */
if (match_flags == 0)
match_flags = CMD_FIND_WINDOW_ALL;
return (match_flags);
}
void
cmd_find_window_match(struct cmd_find_window_list *find_list,
int match_flags, struct winlink *wl, const char *str,
const char *searchstr)
{
struct cmd_find_window_data *find_data;
struct cmd_target_data *data = self->data;
struct cmd_find_window_data *cdata;
struct session *s;
struct winlink *wl, *wm;
struct window *w;
struct window_pane *wp;
u_int i, line;
char *sres;
ARRAY_DECL(, u_int) list_idx;
ARRAY_DECL(, char *) list_ctx;
char *sres, *sctx;
u_int i;
find_data = xcalloc(1, sizeof *find_data);
if (ctx->curclient == NULL) {
ctx->error(ctx, "must be run interactively");
return (-1);
}
s = ctx->curclient->session;
i = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
i++;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
ARRAY_INIT(&list_idx);
ARRAY_INIT(&list_ctx);
if ((match_flags & CMD_FIND_WINDOW_BY_NAME) &&
fnmatch(searchstr, wl->window->name, 0) == 0) {
find_data->list_ctx = xstrdup("");
break;
}
RB_FOREACH(wm, winlinks, &s->windows) {
i = 0;
TAILQ_FOREACH(wp, &wm->window->panes, entry) {
i++;
if ((match_flags & CMD_FIND_WINDOW_BY_TITLE) &&
fnmatch(searchstr, wp->base.title, 0) == 0) {
xasprintf(&find_data->list_ctx,
"pane %u title: \"%s\"", i - 1, wp->base.title);
break;
}
if (match_flags & CMD_FIND_WINDOW_BY_CONTENT &&
(sres = window_pane_search(wp, str, &line)) != NULL) {
xasprintf(&find_data->list_ctx,
"pane %u line %u: \"%s\"", i - 1, line + 1, sres);
free(sres);
break;
if (strstr(wm->window->name, data->arg) != NULL)
sctx = xstrdup("");
else {
sres = cmd_find_window_search(wp, data->arg);
if (sres == NULL &&
strstr(wp->base.title, data->arg) == NULL)
continue;
if (sres == NULL) {
xasprintf(&sctx,
"pane %u title: \"%s\"", i - 1,
wp->base.title);
} else {
xasprintf(&sctx, "\"%s\"", sres);
xfree(sres);
}
}
ARRAY_ADD(&list_idx, wm->idx);
ARRAY_ADD(&list_ctx, sctx);
}
}
if (find_data->list_ctx != NULL) {
find_data->wl = wl;
find_data->pane_id = i - 1;
TAILQ_INSERT_TAIL(find_list, find_data, entry);
} else
free(find_data);
}
enum cmd_retval
cmd_find_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c = cmdq->state.c;
struct window_choose_data *cdata;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl, *wm;
struct cmd_find_window_list find_list;
struct cmd_find_window_data *find_data;
struct cmd_find_window_data *find_data1;
char *str, *searchstr;
const char *template;
u_int i, match_flags;
if (c == NULL) {
cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
if (ARRAY_LENGTH(&list_idx) == 0) {
ctx->error(ctx, "no windows matching: %s", data->arg);
ARRAY_FREE(&list_idx);
ARRAY_FREE(&list_ctx);
return (-1);
}
if ((template = args_get(args, 'F')) == NULL)
template = FIND_WINDOW_TEMPLATE;
match_flags = cmd_find_window_match_flags(args);
str = args->argv[0];
TAILQ_INIT(&find_list);
xasprintf(&searchstr, "*%s*", str);
RB_FOREACH(wm, winlinks, &s->windows)
cmd_find_window_match(&find_list, match_flags, wm, str, searchstr);
free(searchstr);
if (TAILQ_EMPTY(&find_list)) {
cmdq_error(cmdq, "no windows matching: %s", str);
return (CMD_RETURN_ERROR);
}
if (TAILQ_NEXT(TAILQ_FIRST(&find_list), entry) == NULL) {
if (session_select(s, TAILQ_FIRST(&find_list)->wl->idx) == 0)
if (ARRAY_LENGTH(&list_idx) == 1) {
if (session_select(s, ARRAY_FIRST(&list_idx)) == 0)
server_redraw_session(s);
recalculate_sizes();
goto out;
@@ -186,55 +119,86 @@ cmd_find_window_exec(struct cmd *self, struct cmd_q *cmdq)
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
goto out;
i = 0;
TAILQ_FOREACH(find_data, &find_list, entry) {
cdata = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = find_data->wl->idx;
cdata->wl = find_data->wl;
cdata->ft_template = xstrdup(template);
cdata->pane_id = find_data->pane_id;
format_add(cdata->ft, "line", "%u", i);
format_add(cdata->ft, "window_find_matches", "%s",
find_data->list_ctx);
format_defaults(cdata->ft, NULL, s, find_data->wl, NULL);
window_choose_add(wl->window->active, cdata);
i++;
for (i = 0; i < ARRAY_LENGTH(&list_idx); i++) {
wm = winlink_find_by_index(
&s->windows, ARRAY_ITEM(&list_idx, i));
w = wm->window;
sctx = ARRAY_ITEM(&list_ctx, i);
window_choose_add(wl->window->active,
wm->idx, "%3d: %s [%ux%u] (%u panes) %s", wm->idx, w->name,
w->sx, w->sy, window_count_panes(w), sctx);
xfree(sctx);
}
window_choose_ready(wl->window->active, 0, cmd_find_window_callback);
cdata = xmalloc(sizeof *cdata);
if (session_index(s, &cdata->session) != 0)
fatalx("session not found");
window_choose_ready(
wl->window->active, 0, cmd_find_window_callback, cdata);
out:
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);
ARRAY_FREE(&list_idx);
ARRAY_FREE(&list_ctx);
return (0);
}
void
cmd_find_window_callback(struct window_choose_data *cdata)
cmd_find_window_callback(void *data, int idx)
{
struct session *s;
struct window_pane *wp;
struct cmd_find_window_data *cdata = data;
struct session *s;
if (cdata == NULL)
return;
s = cdata->start_session;
if (!session_alive(s))
return;
wp = window_pane_at_index(cdata->wl->window, cdata->pane_id);
if (wp != NULL && window_pane_visible(wp))
window_set_active_pane(cdata->wl->window, wp);
if (session_select(s, cdata->idx) == 0) {
server_redraw_session(s);
if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) {
s = ARRAY_ITEM(&sessions, cdata->session);
if (s != NULL && session_select(s, idx) == 0)
server_redraw_session(s);
recalculate_sizes();
}
xfree(cdata);
}
char *
cmd_find_window_search(struct window_pane *wp, const char *searchstr)
{
const struct grid_cell *gc;
const struct grid_utf8 *gu;
char *buf, *s;
size_t off;
u_int i, j, k;
buf = xmalloc(1);
for (j = 0; j < screen_size_y(&wp->base); j++) {
off = 0;
for (i = 0; i < screen_size_x(&wp->base); i++) {
gc = grid_view_peek_cell(wp->base.grid, i, j);
if (gc->flags & GRID_FLAG_UTF8) {
gu = grid_view_peek_utf8(wp->base.grid, i, j);
buf = xrealloc(buf, 1, off + 8);
for (k = 0; k < UTF8_SIZE; k++) {
if (gu->data[k] == 0xff)
break;
buf[off++] = gu->data[k];
}
} else {
buf = xrealloc(buf, 1, off + 1);
buf[off++] = gc->data;
}
}
while (off > 0 && buf[off - 1] == ' ')
off--;
buf[off] = '\0';
if ((s = strstr(buf, searchstr)) != NULL) {
s = section_string(buf, off, s - buf, 40);
xfree(buf);
return (s);
}
}
xfree(buf);
return (NULL);
}

1257
cmd-find.c

File diff suppressed because it is too large Load Diff

694
cmd-generic.c Normal file
View File

@@ -0,0 +1,694 @@
/* $Id: cmd-generic.c,v 1.25 2009-04-03 17:31:44 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
#define CMD_FLAGS "adDgkuU"
#define CMD_FLAGMASK (CMD_AFLAG|CMD_DFLAG|CMD_UPPERDFLAG|CMD_GFLAG|CMD_KFLAG| \
CMD_UFLAG|CMD_UPPERUFLAG)
int cmd_do_flags(int, int, int *);
size_t cmd_print_flags(char *, size_t, size_t, int);
int cmd_fill_argument(int, char **, int, char **);
size_t
cmd_prarg(char *buf, size_t len, const char *prefix, char *arg)
{
if (strchr(arg, ' ' ) != NULL)
return (xsnprintf(buf, len, "%s\"%s\"", prefix, arg));
return (xsnprintf(buf, len, "%s%s", prefix, arg));
}
int
cmd_do_flags(int opt, int iflags, int *oflags)
{
switch (opt) {
case 'a':
if (iflags & CMD_AFLAG) {
(*oflags) |= CMD_AFLAG;
return (0);
}
return (-1);
case 'd':
if (iflags & CMD_DFLAG) {
(*oflags) |= CMD_DFLAG;
return (0);
}
return (-1);
case 'D':
if (iflags & CMD_UPPERDFLAG) {
(*oflags) |= CMD_UPPERDFLAG;
return (0);
}
return (-1);
case 'g':
if (iflags & CMD_GFLAG) {
(*oflags) |= CMD_GFLAG;
return (0);
}
return (-1);
case 'k':
if (iflags & CMD_KFLAG) {
(*oflags) |= CMD_KFLAG;
return (0);
}
return (-1);
case 'u':
if (iflags & CMD_UFLAG) {
(*oflags) |= CMD_UFLAG;
return (0);
}
return (-1);
case 'U':
if (iflags & CMD_UPPERUFLAG) {
(*oflags) |= CMD_UPPERUFLAG;
return (0);
}
return (-1);
}
return (1);
}
size_t
cmd_print_flags(char *buf, size_t len, size_t off, int flags)
{
size_t boff = off;
if ((flags & CMD_FLAGMASK) == 0)
return (0);
off += xsnprintf(buf + off, len - off, " -");
if (off < len && flags & CMD_AFLAG)
off += xsnprintf(buf + off, len - off, "a");
if (off < len && flags & CMD_UPPERDFLAG)
off += xsnprintf(buf + off, len - off, "D");
if (off < len && flags & CMD_DFLAG)
off += xsnprintf(buf + off, len - off, "d");
if (off < len && flags & CMD_GFLAG)
off += xsnprintf(buf + off, len - off, "g");
if (off < len && flags & CMD_KFLAG)
off += xsnprintf(buf + off, len - off, "k");
if (off < len && flags & CMD_UFLAG)
off += xsnprintf(buf + off, len - off, "u");
if (off < len && flags & CMD_UPPERUFLAG)
off += xsnprintf(buf + off, len - off, "U");
return (off - boff);
}
int
cmd_fill_argument(int flags, char **arg, int argc, char **argv)
{
*arg = NULL;
if (flags & CMD_ARG1) {
if (argc != 1)
return (-1);
*arg = xstrdup(argv[0]);
return (0);
}
if (flags & CMD_ARG01) {
if (argc != 0 && argc != 1)
return (-1);
if (argc == 1)
*arg = xstrdup(argv[0]);
return (0);
}
if (argc != 0)
return (-1);
return (0);
}
void
cmd_target_init(struct cmd *self, unused int key)
{
struct cmd_target_data *data;
self->data = data = xmalloc(sizeof *data);
data->flags = 0;
data->target = NULL;
data->arg = NULL;
}
int
cmd_target_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_target_data *data;
int opt;
/* Don't use the entry version since it may be dependent on key. */
cmd_target_init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, CMD_FLAGS "t:")) != -1) {
switch (cmd_do_flags(opt, self->entry->flags, &data->flags)) {
case -1:
goto usage;
case 0:
continue;
}
switch (opt) {
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0)
goto usage;
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
void
cmd_target_send(struct cmd *self, struct buffer *b)
{
struct cmd_target_data *data = self->data;
buffer_write(b, data, sizeof *data);
cmd_send_string(b, data->target);
cmd_send_string(b, data->arg);
}
void
cmd_target_recv(struct cmd *self, struct buffer *b)
{
struct cmd_target_data *data;
self->data = data = xmalloc(sizeof *data);
buffer_read(b, data, sizeof *data);
data->target = cmd_recv_string(b);
data->arg = cmd_recv_string(b);
}
void
cmd_target_free(struct cmd *self)
{
struct cmd_target_data *data = self->data;
if (data->target != NULL)
xfree(data->target);
if (data->arg != NULL)
xfree(data->arg);
xfree(data);
}
size_t
cmd_target_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_target_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
off += cmd_print_flags(buf, len, off, data->flags);
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
if (off < len && data->arg != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->arg);
return (off);
}
void
cmd_srcdst_init(struct cmd *self, unused int key)
{
struct cmd_srcdst_data *data;
self->data = data = xmalloc(sizeof *data);
data->flags = 0;
data->src = NULL;
data->dst = NULL;
data->arg = NULL;
}
int
cmd_srcdst_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_srcdst_data *data;
int opt;
cmd_srcdst_init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, CMD_FLAGS "s:t:")) != -1) {
switch (cmd_do_flags(opt, self->entry->flags, &data->flags)) {
case -1:
goto usage;
case 0:
continue;
}
switch (opt) {
case 's':
if (data->src == NULL)
data->src = xstrdup(optarg);
break;
case 't':
if (data->dst == NULL)
data->dst = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0)
goto usage;
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
void
cmd_srcdst_send(struct cmd *self, struct buffer *b)
{
struct cmd_srcdst_data *data = self->data;
buffer_write(b, data, sizeof *data);
cmd_send_string(b, data->src);
cmd_send_string(b, data->dst);
cmd_send_string(b, data->arg);
}
void
cmd_srcdst_recv(struct cmd *self, struct buffer *b)
{
struct cmd_srcdst_data *data;
self->data = data = xmalloc(sizeof *data);
buffer_read(b, data, sizeof *data);
data->src = cmd_recv_string(b);
data->dst = cmd_recv_string(b);
data->arg = cmd_recv_string(b);
}
void
cmd_srcdst_free(struct cmd *self)
{
struct cmd_srcdst_data *data = self->data;
if (data->src != NULL)
xfree(data->src);
if (data->dst != NULL)
xfree(data->dst);
if (data->arg != NULL)
xfree(data->arg);
xfree(data);
}
size_t
cmd_srcdst_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_srcdst_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
off += cmd_print_flags(buf, len, off, data->flags);
if (off < len && data->src != NULL)
off += xsnprintf(buf + off, len - off, " -s %s", data->src);
if (off < len && data->dst != NULL)
off += xsnprintf(buf + off, len - off, " -t %s", data->dst);
if (off < len && data->arg != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->arg);
return (off);
}
void
cmd_buffer_init(struct cmd *self, unused int key)
{
struct cmd_buffer_data *data;
self->data = data = xmalloc(sizeof *data);
data->flags = 0;
data->target = NULL;
data->buffer = -1;
data->arg = NULL;
}
int
cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_buffer_data *data;
int opt, n;
const char *errstr;
cmd_buffer_init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, CMD_FLAGS "b:t:")) != -1) {
switch (cmd_do_flags(opt, self->entry->flags, &data->flags)) {
case -1:
goto usage;
case 0:
continue;
}
switch (opt) {
case 'b':
if (data->buffer == -1) {
n = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr != NULL) {
xasprintf(cause, "buffer %s", errstr);
goto error;
}
data->buffer = n;
}
break;
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0)
goto usage;
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
error:
self->entry->free(self);
return (-1);
}
void
cmd_buffer_send(struct cmd *self, struct buffer *b)
{
struct cmd_buffer_data *data = self->data;
buffer_write(b, data, sizeof *data);
cmd_send_string(b, data->target);
cmd_send_string(b, data->arg);
}
void
cmd_buffer_recv(struct cmd *self, struct buffer *b)
{
struct cmd_buffer_data *data;
self->data = data = xmalloc(sizeof *data);
buffer_read(b, data, sizeof *data);
data->target = cmd_recv_string(b);
data->arg = cmd_recv_string(b);
}
void
cmd_buffer_free(struct cmd *self)
{
struct cmd_buffer_data *data = self->data;
if (data->target != NULL)
xfree(data->target);
if (data->arg != NULL)
xfree(data->arg);
xfree(data);
}
size_t
cmd_buffer_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_buffer_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
off += cmd_print_flags(buf, len, off, data->flags);
if (off < len && data->buffer != -1)
off += xsnprintf(buf + off, len - off, " -b %d", data->buffer);
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
if (off < len && data->arg != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->arg);
return (off);
}
void
cmd_option_init(struct cmd *self, unused int key)
{
struct cmd_option_data *data;
self->data = data = xmalloc(sizeof *data);
data->flags = 0;
data->target = NULL;
data->option = NULL;
data->value = NULL;
}
int
cmd_option_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_option_data *data;
int opt;
/* Don't use the entry version since it may be dependent on key. */
cmd_option_init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, CMD_FLAGS "t:")) != -1) {
switch (cmd_do_flags(opt, self->entry->flags, &data->flags)) {
case -1:
goto usage;
case 0:
continue;
}
switch (opt) {
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (argc == 2) {
data->option = xstrdup(argv[0]);
data->value = xstrdup(argv[1]);
} else if (argc == 1)
data->option = xstrdup(argv[0]);
else
goto usage;
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
void
cmd_option_send(struct cmd *self, struct buffer *b)
{
struct cmd_option_data *data = self->data;
buffer_write(b, data, sizeof *data);
cmd_send_string(b, data->target);
cmd_send_string(b, data->option);
cmd_send_string(b, data->value);
}
void
cmd_option_recv(struct cmd *self, struct buffer *b)
{
struct cmd_option_data *data;
self->data = data = xmalloc(sizeof *data);
buffer_read(b, data, sizeof *data);
data->target = cmd_recv_string(b);
data->option = cmd_recv_string(b);
data->value = cmd_recv_string(b);
}
void
cmd_option_free(struct cmd *self)
{
struct cmd_option_data *data = self->data;
if (data->target != NULL)
xfree(data->target);
if (data->option != NULL)
xfree(data->option);
if (data->value != NULL)
xfree(data->value);
xfree(data);
}
size_t
cmd_option_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_option_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
off += cmd_print_flags(buf, len, off, data->flags);
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
if (off < len && data->option != NULL)
off += xsnprintf(buf + off, len - off, " %s", data->option);
if (off < len && data->value != NULL)
off += xsnprintf(buf + off, len - off, " %s", data->value);
return (off);
}
void
cmd_pane_init(struct cmd *self, unused int key)
{
struct cmd_pane_data *data;
self->data = data = xmalloc(sizeof *data);
data->flags = 0;
data->target = NULL;
data->arg = NULL;
data->pane = -1;
}
int
cmd_pane_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_pane_data *data;
int opt, n;
const char *errstr;
/* Don't use the entry version since it may be dependent on key. */
cmd_pane_init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, CMD_FLAGS "p:t:")) != -1) {
switch (cmd_do_flags(opt, self->entry->flags, &data->flags)) {
case -1:
goto usage;
case 0:
continue;
}
switch (opt) {
case 'p':
if (data->pane == -1) {
n = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr != NULL) {
xasprintf(cause, "pane %s", errstr);
goto error;
}
data->pane = n;
}
break;
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0)
goto usage;
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
error:
self->entry->free(self);
return (-1);
}
void
cmd_pane_send(struct cmd *self, struct buffer *b)
{
struct cmd_pane_data *data = self->data;
buffer_write(b, data, sizeof *data);
cmd_send_string(b, data->target);
cmd_send_string(b, data->arg);
}
void
cmd_pane_recv(struct cmd *self, struct buffer *b)
{
struct cmd_pane_data *data;
self->data = data = xmalloc(sizeof *data);
buffer_read(b, data, sizeof *data);
data->target = cmd_recv_string(b);
data->arg = cmd_recv_string(b);
}
void
cmd_pane_free(struct cmd *self)
{
struct cmd_pane_data *data = self->data;
if (data->target != NULL)
xfree(data->target);
if (data->arg != NULL)
xfree(data->arg);
xfree(data);
}
size_t
cmd_pane_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_pane_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
off += cmd_print_flags(buf, len, off, data->flags);
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
if (off < len && data->arg != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->arg);
return (off);
}

View File

@@ -1,5 +1,7 @@
/* $Id: cmd-has-session.c,v 1.12 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2016 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,26 +20,32 @@
#include "tmux.h"
#if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
const char *
getprogname(void)
{
extern char *program_invocation_short_name;
/*
* Cause client to report an error and exit with 1 if session doesn't exist.
*/
return (program_invocation_short_name);
}
#elif defined(HAVE___PROGNAME)
const char *
getprogname(void)
{
extern char *__progname;
int cmd_has_session_exec(struct cmd *, struct cmd_ctx *);
return (__progname);
}
#else
const char *
getprogname(void)
const struct cmd_entry cmd_has_session_entry = {
"has-session", "has",
CMD_TARGET_SESSION_USAGE,
0,
cmd_target_init,
cmd_target_parse,
cmd_has_session_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
int
cmd_has_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
return ("tmux");
struct cmd_target_data *data = self->data;
if (cmd_find_session(ctx, data->target) == NULL)
return (-1);
return (0);
}
#endif

View File

@@ -1,205 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
* Copyright (c) 2009 Nicholas Marriott <nicm@openbsd.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 <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Executes a tmux command if a shell command returns true or false.
*/
enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmd_q *);
void cmd_if_shell_callback(struct job *);
void cmd_if_shell_done(struct cmd_q *);
void cmd_if_shell_free(void *);
const struct cmd_entry cmd_if_shell_entry = {
.name = "if-shell",
.alias = "if",
.args = { "bFt:", 2, 3 },
.usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command "
"[command]",
.tflag = CMD_PANE_CANFAIL,
.flags = 0,
.exec = cmd_if_shell_exec
};
struct cmd_if_shell_data {
char *cmd_if;
char *cmd_else;
struct cmd_q *cmdq;
struct mouse_event mouse;
int bflag;
int references;
};
enum cmd_retval
cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct cmd_if_shell_data *cdata;
char *shellcmd, *cmd, *cause;
struct cmd_list *cmdlist;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl;
struct window_pane *wp = cmdq->state.tflag.wp;
struct format_tree *ft;
const char *cwd;
if (cmdq->client != NULL && cmdq->client->session == NULL)
cwd = cmdq->client->cwd;
else if (s != NULL)
cwd = s->cwd;
else
cwd = NULL;
ft = format_create(cmdq, 0);
format_defaults(ft, cmdq->state.c, s, wl, wp);
shellcmd = format_expand(ft, args->argv[0]);
format_free(ft);
if (args_has(args, 'F')) {
cmd = NULL;
if (*shellcmd != '0' && *shellcmd != '\0')
cmd = args->argv[1];
else if (args->argc == 3)
cmd = args->argv[2];
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->cmd_if = xstrdup(args->argv[1]);
if (args->argc == 3)
cdata->cmd_else = xstrdup(args->argv[2]);
else
cdata->cmd_else = NULL;
cdata->bflag = args_has(args, 'b');
cdata->cmdq = cmdq;
memcpy(&cdata->mouse, &cmdq->item->mouse, sizeof cdata->mouse);
cmdq->references++;
cdata->references = 1;
job_run(shellcmd, s, cwd, cmd_if_shell_callback, cmd_if_shell_free,
cdata);
free(shellcmd);
if (cdata->bflag)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
void
cmd_if_shell_callback(struct job *job)
{
struct cmd_if_shell_data *cdata = job->data;
struct cmd_q *cmdq = cdata->cmdq, *cmdq1;
struct cmd_list *cmdlist;
char *cause, *cmd;
if (cmdq->flags & CMD_Q_DEAD)
return;
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
cmd = cdata->cmd_else;
else
cmd = cdata->cmd_if;
if (cmd == NULL)
return;
if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) {
cmdq_error(cmdq, "%s", cause);
free(cause);
}
return;
}
cmdq1 = cmdq_new(cmdq->client);
cmdq1->flags |= cmdq->flags & CMD_Q_NOHOOKS;
cmdq1->emptyfn = cmd_if_shell_done;
cmdq1->data = cdata;
cdata->references++;
cmdq_run(cmdq1, cmdlist, &cdata->mouse);
cmd_list_free(cmdlist);
}
void
cmd_if_shell_done(struct cmd_q *cmdq1)
{
struct cmd_if_shell_data *cdata = cmdq1->data;
struct cmd_q *cmdq = cdata->cmdq;
if (cmdq1->client_exit >= 0)
cmdq->client_exit = cmdq1->client_exit;
cmdq_free(cmdq1);
if (--cdata->references != 0)
return;
if (!cmdq_free(cmdq) && !cdata->bflag)
cmdq_continue(cmdq);
free(cdata->cmd_else);
free(cdata->cmd_if);
free(cdata);
}
void
cmd_if_shell_free(void *data)
{
struct cmd_if_shell_data *cdata = data;
struct cmd_q *cmdq = cdata->cmdq;
if (--cdata->references != 0)
return;
if (!cmdq_free(cmdq) && !cdata->bflag)
cmdq_continue(cmdq);
free(cdata->cmd_else);
free(cdata->cmd_if);
free(cdata);
}

View File

@@ -1,161 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2011 George Nachman <tmux@georgester.com>
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include "tmux.h"
/*
* Join or move a pane into another (like split/swap/kill).
*/
enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmd_q *);
enum cmd_retval join_pane(struct cmd *, struct cmd_q *, int);
const struct cmd_entry cmd_join_pane_entry = {
.name = "join-pane",
.alias = "joinp",
.args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.sflag = CMD_PANE_MARKED,
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_join_pane_exec
};
const struct cmd_entry cmd_move_pane_entry = {
.name = "move-pane",
.alias = "movep",
.args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.sflag = CMD_PANE,
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_join_pane_exec
};
enum cmd_retval
cmd_join_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
return (join_pane(self, cmdq, self->entry == &cmd_join_pane_entry));
}
enum cmd_retval
join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
{
struct args *args = self->args;
struct session *dst_s;
struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w;
struct window_pane *src_wp, *dst_wp;
char *cause;
int size, percentage, dst_idx;
enum layout_type type;
struct layout_cell *lc;
dst_s = cmdq->state.tflag.s;
dst_wl = cmdq->state.tflag.wl;
dst_wp = cmdq->state.tflag.wp;
dst_w = dst_wl->window;
dst_idx = dst_wl->idx;
server_unzoom_window(dst_w);
src_wl = cmdq->state.sflag.wl;
src_wp = cmdq->state.sflag.wp;
src_w = src_wl->window;
server_unzoom_window(src_w);
if (not_same_window && src_w == dst_w) {
cmdq_error(cmdq, "can't join a pane to its own window");
return (CMD_RETURN_ERROR);
}
if (!not_same_window && src_wp == dst_wp) {
cmdq_error(cmdq, "source and target panes must be different");
return (CMD_RETURN_ERROR);
}
type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT;
size = -1;
if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(cmdq, "size %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, 100, &cause);
if (cause != NULL) {
cmdq_error(cmdq, "percentage %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (type == LAYOUT_TOPBOTTOM)
size = (dst_wp->sy * percentage) / 100;
else
size = (dst_wp->sx * percentage) / 100;
}
lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b'), 0);
if (lc == NULL) {
cmdq_error(cmdq, "create pane failed: pane too small");
return (CMD_RETURN_ERROR);
}
layout_close_pane(src_wp);
window_lost_pane(src_w, src_wp);
TAILQ_REMOVE(&src_w->panes, src_wp, entry);
src_wp->window = dst_w;
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
layout_assign_pane(lc, src_wp);
recalculate_sizes();
server_redraw_window(src_w);
server_redraw_window(dst_w);
if (!args_has(args, 'd')) {
window_set_active_pane(dst_w, src_wp);
session_select(dst_s, dst_idx);
server_redraw_session(dst_s);
} else
server_status_session(dst_s);
if (window_count_panes(src_w) == 0)
server_kill_window(src_w);
else
notify_window_layout_changed(src_w);
notify_window_layout_changed(dst_w);
return (CMD_RETURN_NORMAL);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-kill-pane.c,v 1.6 2009-04-01 21:10:08 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -26,48 +26,47 @@
* Kill pane.
*/
enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmd_q *);
int cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_pane_entry = {
.name = "kill-pane",
.alias = "killp",
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_kill_pane_exec
"kill-pane", "killp",
CMD_PANE_WINDOW_USAGE,
0,
cmd_pane_init,
cmd_pane_parse,
cmd_kill_pane_exec,
cmd_pane_send,
cmd_pane_recv,
cmd_pane_free,
cmd_pane_print
};
enum cmd_retval
cmd_kill_pane_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct winlink *wl = cmdq->state.tflag.wl;
struct window_pane *loopwp, *tmpwp, *wp = cmdq->state.tflag.wp;
server_unzoom_window(wl->window);
struct cmd_pane_data *data = self->data;
struct winlink *wl;
struct window_pane *wp;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (data->pane == -1)
wp = wl->window->active;
else {
wp = window_pane_at_index(wl->window, data->pane);
if (wp == NULL) {
ctx->error(ctx, "no pane: %d", data->pane);
return (-1);
}
}
if (window_count_panes(wl->window) == 1) {
/* Only one pane, kill the window. */
server_kill_window(wl->window);
recalculate_sizes();
return (CMD_RETURN_NORMAL);
ctx->error(ctx, "can't kill pane: %d", data->pane);
return (-1);
}
if (args_has(self->args, 'a')) {
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
if (loopwp == wp)
continue;
layout_close_pane(loopwp);
window_remove_pane(wl->window, loopwp);
}
} else {
layout_close_pane(wp);
window_remove_pane(wl->window, wp);
}
window_remove_pane(wl->window, wp);
server_redraw_window(wl->window);
return (CMD_RETURN_NORMAL);
layout_refresh(wl->window, 0);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-kill-server.c,v 1.6 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -27,35 +27,25 @@
* Kill the server and do nothing else.
*/
enum cmd_retval cmd_kill_server_exec(struct cmd *, struct cmd_q *);
int cmd_kill_server_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_server_entry = {
.name = "kill-server",
.alias = NULL,
.args = { "", 0, 0 },
.usage = "",
.flags = 0,
.exec = cmd_kill_server_exec
"kill-server", NULL,
"",
0,
NULL,
NULL,
cmd_kill_server_exec,
NULL,
NULL,
NULL,
NULL
};
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
cmd_kill_server_exec(struct cmd *self, __unused struct cmd_q *cmdq)
int
cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
{
if (self->entry == &cmd_kill_server_entry)
kill(getpid(), SIGTERM);
sigterm = 1;
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-kill-session.c,v 1.12 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -27,46 +27,42 @@
* Note this deliberately has no alias to make it hard to hit by accident.
*/
enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmd_q *);
int cmd_kill_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_session_entry = {
.name = "kill-session",
.alias = NULL,
.args = { "aCt:", 0, 0 },
.usage = "[-aC] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_kill_session_exec
"kill-session", NULL,
CMD_TARGET_SESSION_USAGE,
0,
cmd_target_init,
cmd_target_parse,
cmd_kill_session_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
enum cmd_retval
cmd_kill_session_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s, *sloop, *stmp;
struct winlink *wl;
struct cmd_target_data *data = self->data;
struct session *s;
struct client *c;
u_int i;
s = cmdq->state.tflag.s;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (args_has(args, 'C')) {
RB_FOREACH(wl, winlinks, &s->windows) {
wl->window->flags &= ~WINDOW_ALERTFLAGS;
wl->flags &= ~WINLINK_ALERTFLAGS;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c->session == s) {
c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0);
}
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 {
server_destroy_session(s);
session_destroy(s);
}
return (CMD_RETURN_NORMAL);
recalculate_sizes();
session_destroy(s);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-kill-window.c,v 1.15 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -24,58 +24,46 @@
* Destroy window.
*/
enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmd_q *);
int cmd_kill_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_window_entry = {
.name = "kill-window",
.alias = "killw",
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_kill_window_exec
"kill-window", "killw",
CMD_TARGET_WINDOW_USAGE,
0,
cmd_target_init,
cmd_target_parse,
cmd_kill_window_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
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
cmd_kill_window_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct winlink *wl = cmdq->state.tflag.wl, *wl2, *wl3;
struct window *w = wl->window;
struct session *s = cmdq->state.tflag.s;
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct session *s;
struct client *c;
u_int i;
int destroyed;
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);
}
server_unlink_window(s, wl);
} else {
if (args_has(args, 'a')) {
RB_FOREACH_SAFE(wl2, winlinks, &s->windows, wl3) {
if (wl != wl2)
server_kill_window(wl2->window);
}
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
destroyed = session_detach(s, wl);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != s)
continue;
if (destroyed) {
c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0);
} else
server_kill_window(wl->window);
server_redraw_client(c);
}
recalculate_sizes();
return (CMD_RETURN_NORMAL);
return (0);
}

60
cmd-last-window.c Normal file
View File

@@ -0,0 +1,60 @@
/* $Id: cmd-last-window.c,v 1.16 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Move to last window.
*/
int cmd_last_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_last_window_entry = {
"last-window", "last",
CMD_TARGET_SESSION_USAGE,
0,
cmd_target_init,
cmd_target_parse,
cmd_last_window_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
int
cmd_last_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct session *s;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (session_last(s) == 0)
server_redraw_session(s);
else {
ctx->error(ctx, "no last window");
return (-1);
}
recalculate_sizes();
return (0);
}

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

@@ -0,0 +1,109 @@
/* $Id: cmd-link-window.c,v 1.28 2009-01-23 16:59:14 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Link a window into another session.
*/
int cmd_link_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_link_window_entry = {
"link-window", "linkw",
"[-dk] " CMD_SRCDST_WINDOW_USAGE,
CMD_DFLAG|CMD_KFLAG,
cmd_srcdst_init,
cmd_srcdst_parse,
cmd_link_window_exec,
cmd_srcdst_send,
cmd_srcdst_recv,
cmd_srcdst_free,
cmd_srcdst_print
};
int
cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_srcdst_data *data = self->data;
struct session *dst;
struct winlink *wl_src, *wl_dst;
char *cause;
int idx;
if ((wl_src = cmd_find_window(ctx, data->src, NULL)) == NULL)
return (-1);
if (arg_parse_window(data->dst, &dst, &idx) != 0) {
ctx->error(ctx, "bad window: %s", data->dst);
return (-1);
}
if (dst == NULL)
dst = ctx->cursession;
if (dst == NULL)
dst = cmd_current_session(ctx);
if (dst == NULL) {
ctx->error(ctx, "session not found: %s", data->dst);
return (-1);
}
wl_dst = NULL;
if (idx != -1)
wl_dst = winlink_find_by_index(&dst->windows, idx);
if (wl_dst != NULL) {
if (wl_dst->window == wl_src->window)
return (0);
if (data->flags & CMD_KFLAG) {
/*
* Can't use session_detach as it will destroy session
* if this makes it empty.
*/
session_alert_cancel(dst, wl_dst);
winlink_stack_remove(&dst->lastw, wl_dst);
winlink_remove(&dst->windows, wl_dst);
/* Force select/redraw if current. */
if (wl_dst == dst->curw) {
data->flags &= ~CMD_DFLAG;
dst->curw = NULL;
}
}
}
wl_dst = session_attach(dst, wl_src->window, idx, &cause);
if (wl_dst == NULL) {
ctx->error(ctx, "create session failed: %s", cause);
xfree(cause);
return (-1);
}
if (data->flags & CMD_DFLAG)
server_status_session(dst);
else {
session_select(dst, wl_dst->idx);
server_redraw_session(dst);
}
recalculate_sizes();
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-list-buffers.c,v 1.7 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -27,45 +26,66 @@
* 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 *);
int cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_buffers_entry = {
.name = "list-buffers",
.alias = "lsb",
.args = { "F:", 0, 0 },
.usage = "[-F format]",
.flags = 0,
.exec = cmd_list_buffers_exec
"list-buffers", "lsb",
CMD_TARGET_SESSION_USAGE,
0,
cmd_target_init,
cmd_target_parse,
cmd_list_buffers_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
enum cmd_retval
cmd_list_buffers_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_list_buffers_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct session *s;
struct paste_buffer *pb;
struct format_tree *ft;
char *line;
const char *template;
u_int idx;
char *tmp;
size_t size, in, out;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_BUFFERS_TEMPLATE;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
pb = NULL;
while ((pb = paste_walk(pb)) != NULL) {
ft = format_create(cmdq, 0);
format_defaults_paste_buffer(ft, pb);
line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line);
free(line);
format_free(ft);
if (s->sx > 35) { /* leave three for ... */
size = s->sx - 32;
tmp = xmalloc(size + 1);
} else {
size = 0;
tmp = NULL;
}
return (CMD_RETURN_NORMAL);
idx = 0;
while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) {
if (tmp != NULL) {
in = out = 0;
while (out < size && pb->data[in] != '\0') {
if (pb->data[in] > 31 && pb->data[in] != 127)
tmp[out++] = pb->data[in];
in++;
}
tmp[out] = '\0';
if (out == size) {
tmp[out - 1] = '.';
tmp[out - 2] = '.';
tmp[out - 3] = '.';
}
ctx->print(ctx, "%d: %zu bytes: \"%s\"",
idx - 1, strlen(pb->data), tmp);
} else
ctx->print(ctx, "%d: %zu bytes", idx, strlen(pb->data));
}
if (tmp != NULL)
xfree(tmp);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-list-clients.c,v 1.13 2009-02-11 17:50:32 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -28,62 +27,35 @@
* 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 *);
int cmd_list_clients_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_clients_entry = {
.name = "list-clients",
.alias = "lsc",
.args = { "F:t:", 0, 0 },
.usage = "[-F format] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.flags = CMD_READONLY,
.exec = cmd_list_clients_exec
"list-clients", "lsc",
"",
0,
NULL,
NULL,
cmd_list_clients_exec,
NULL,
NULL,
NULL,
NULL
};
enum cmd_retval
cmd_list_clients_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_list_clients_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c;
struct session *s;
struct format_tree *ft;
const char *template;
u_int idx;
char *line;
struct client *c;
u_int i;
if (args_has(args, 't'))
s = cmdq->state.tflag.s;
else
s = NULL;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_CLIENTS_TEMPLATE;
idx = 0;
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == NULL || (s != NULL && s != c->session))
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
continue;
ft = format_create(cmdq, 0);
format_add(ft, "line", "%u", idx);
format_defaults(ft, c, NULL, NULL, NULL);
line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line);
free(line);
format_free(ft);
idx++;
ctx->print(ctx, "%s: %s [%ux%u %s]", c->tty.path,
c->session->name, c->tty.sx, c->tty.sy, c->tty.termname);
}
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,5 +1,7 @@
/* $Id: cmd-list-commands.c,v 1.3 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2016 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -16,36 +18,34 @@
#include <sys/types.h>
#include <string.h>
#include "tmux.h"
#if defined(HAVE_PRCTL) && defined(HAVE_PR_SET_NAME)
/*
* List all commands with usages.
*/
#include <sys/prctl.h>
int cmd_list_commands_exec(struct cmd *, struct cmd_ctx *);
void
setproctitle(const char *fmt, ...)
const struct cmd_entry cmd_list_commands_entry = {
"list-commands", "lscm",
"",
0,
NULL,
NULL,
cmd_list_commands_exec,
NULL,
NULL,
NULL,
NULL
};
int
cmd_list_commands_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{
char title[16], name[16], *cp;
va_list ap;
int used;
const struct cmd_entry **entryp;
va_start(ap, fmt);
vsnprintf(title, sizeof title, fmt, ap);
va_end(ap);
for (entryp = cmd_table; *entryp != NULL; entryp++)
ctx->print(ctx, "%s %s", (*entryp)->name, (*entryp)->usage);
used = snprintf(name, sizeof name, "%s: %s", getprogname(), title);
if (used >= (int)sizeof name) {
cp = strrchr(name, ' ');
if (cp != NULL)
*cp = '\0';
}
prctl(PR_SET_NAME, name);
return (0);
}
#else
void
setproctitle(const char *fmt, ...)
{
}
#endif

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-list-keys.c,v 1.13 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,219 +18,42 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* List key bindings.
*/
static enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmd_q *);
static enum cmd_retval cmd_list_keys_table(struct cmd *, struct cmd_q *);
static enum cmd_retval cmd_list_keys_commands(struct cmd *, struct cmd_q *);
int cmd_list_keys_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_keys_entry = {
.name = "list-keys",
.alias = "lsk",
.args = { "t:T:", 0, 0 },
.usage = "[-t mode-table] [-T key-table]",
.flags = CMD_STARTSERVER,
.exec = cmd_list_keys_exec
"list-keys", "lsk",
"",
0,
NULL,
NULL,
cmd_list_keys_exec,
NULL,
NULL,
NULL,
NULL
};
const struct cmd_entry cmd_list_commands_entry = {
.name = "list-commands",
.alias = "lscm",
.args = { "F:", 0, 0 },
.usage = "[-F format]",
.flags = CMD_STARTSERVER,
.exec = cmd_list_keys_exec
};
static enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_list_keys_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct key_table *table;
struct key_binding *bd;
const char *key, *tablename, *r;
char *cp, tmp[BUFSIZ];
int repeat, width, tablewidth, keywidth;
const char *key;
char tmp[BUFSIZ];
if (self->entry == &cmd_list_commands_entry)
return (cmd_list_keys_commands(self, cmdq));
if (args_has(args, 't'))
return (cmd_list_keys_table(self, cmdq));
tablename = args_get(args, 'T');
if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(cmdq, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR);
}
repeat = 0;
tablewidth = keywidth = 0;
RB_FOREACH(table, key_tables, &key_tables) {
if (tablename != NULL && strcmp(table->name, tablename) != 0)
SPLAY_FOREACH(bd, key_bindings, &key_bindings) {
if ((key = key_string_lookup_key(bd->key)) == NULL)
continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
key = key_string_lookup_key(bd->key);
if (bd->can_repeat)
repeat = 1;
width = utf8_cstrwidth(table->name);
if (width > tablewidth)
tablewidth = width;
width = utf8_cstrwidth(key);
if (width > keywidth)
keywidth = width;
}
*tmp = '\0';
cmd_list_print(bd->cmdlist, tmp, sizeof tmp);
ctx->print(ctx, "%11s: %s", key, tmp);
}
RB_FOREACH(table, key_tables, &key_tables) {
if (tablename != NULL && strcmp(table->name, tablename) != 0)
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);
cmdq_print(cmdq, "bind-key %s", tmp);
}
}
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
const char *tablename, *key, *cmdstr, *mode;
const struct mode_key_table *mtab;
struct mode_key_binding *mbind;
char repeat[16];
int width, keywidth, repeatwidth, any_mode;
tablename = args_get(args, 't');
if ((mtab = mode_key_findtable(tablename)) == NULL) {
cmdq_error(cmdq, "unknown key table: %s", tablename);
return (CMD_RETURN_ERROR);
}
keywidth = repeatwidth = 0;
any_mode = 0;
RB_FOREACH(mbind, mode_key_tree, mtab->tree) {
key = key_string_lookup_key(mbind->key);
if (mbind->mode != 0)
any_mode = 1;
width = strlen(key);
if (width > keywidth)
keywidth = width;
if (mbind->repeat != 1) {
snprintf(repeat, sizeof repeat, "%u", mbind->repeat);
width = strlen(repeat);
if (width > repeatwidth)
repeatwidth = width;
}
}
RB_FOREACH(mbind, mode_key_tree, mtab->tree) {
key = key_string_lookup_key(mbind->key);
mode = "";
if (mbind->mode != 0)
mode = "c";
snprintf(repeat, sizeof repeat, "%u", mbind->repeat);
cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd);
if (cmdstr != NULL) {
cmdq_print(cmdq,
"bind-key -%st %s%s%s%*s %*s %s%s%s%s",
mode, any_mode && *mode == '\0' ? " " : "",
mtab->name,
mbind->repeat != 1 ? " -R " :
(repeatwidth == 0 ? "" : " "),
repeatwidth, mbind->repeat != 1 ? repeat : "",
(int)keywidth, key, cmdstr,
mbind->arg != NULL ? " \"" : "",
mbind->arg != NULL ? mbind->arg : "",
mbind->arg != NULL ? "\"": "");
}
}
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_list_keys_commands(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
const struct cmd_entry **entryp;
const struct cmd_entry *entry;
struct format_tree *ft;
const char *template;
char *line;
if ((template = args_get(args, 'F')) == NULL) {
template = "#{command_list_name}"
"#{?command_list_alias, (#{command_list_alias}),} "
"#{command_list_usage}";
}
ft = format_create(cmdq, 0);
format_defaults(ft, NULL, NULL, NULL, NULL);
for (entryp = cmd_table; *entryp != NULL; entryp++) {
entry = *entryp;
format_add(ft, "command_list_name", "%s", entry->name);
if (entry->alias != NULL) {
format_add(ft, "command_list_alias", "%s",
entry->alias);
}
if (entry->alias != NULL) {
format_add(ft, "command_list_usage", "%s",
entry->usage);
}
line = format_expand(ft, template);
if (*line != '\0')
cmdq_print(cmdq, "%s", line);
free(line);
}
format_free(ft);
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,137 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* List panes on given window.
*/
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_session(struct cmd *, struct session *, struct cmd_q *,
int);
void cmd_list_panes_window(struct cmd *, struct session *, struct winlink *,
struct cmd_q *, int);
const struct cmd_entry cmd_list_panes_entry = {
.name = "list-panes",
.alias = "lsp",
.args = { "asF:t:", 0, 0 },
.usage = "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_list_panes_exec
};
enum cmd_retval
cmd_list_panes_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl;
if (args_has(args, 'a'))
cmd_list_panes_server(self, cmdq);
else if (args_has(args, 's'))
cmd_list_panes_session(self, s, cmdq, 1);
else
cmd_list_panes_window(self, s, wl, cmdq, 0);
return (CMD_RETURN_NORMAL);
}
void
cmd_list_panes_server(struct cmd *self, struct cmd_q *cmdq)
{
struct session *s;
RB_FOREACH(s, sessions, &sessions)
cmd_list_panes_session(self, s, cmdq, 2);
}
void
cmd_list_panes_session(struct cmd *self, struct session *s, struct cmd_q *cmdq,
int type)
{
struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows)
cmd_list_panes_window(self, s, wl, cmdq, type);
}
void
cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
struct cmd_q *cmdq, int type)
{
struct args *args = self->args;
struct window_pane *wp;
u_int n;
struct format_tree *ft;
const char *template;
char *line;
template = args_get(args, 'F');
if (template == NULL) {
switch (type) {
case 0:
template = "#{pane_index}: "
"[#{pane_width}x#{pane_height}] [history "
"#{history_size}/#{history_limit}, "
"#{history_bytes} bytes] #{pane_id}"
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
break;
case 1:
template = "#{window_index}.#{pane_index}: "
"[#{pane_width}x#{pane_height}] [history "
"#{history_size}/#{history_limit}, "
"#{history_bytes} bytes] #{pane_id}"
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
break;
case 2:
template = "#{session_name}:#{window_index}."
"#{pane_index}: [#{pane_width}x#{pane_height}] "
"[history #{history_size}/#{history_limit}, "
"#{history_bytes} bytes] #{pane_id}"
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
break;
}
}
n = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
ft = format_create(cmdq, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, wp);
line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line);
free(line);
format_free(ft);
n++;
}
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-list-sessions.c,v 1.19 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -28,53 +27,41 @@
* 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 *);
int cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_sessions_entry = {
.name = "list-sessions",
.alias = "ls",
.args = { "F:", 0, 0 },
.usage = "[-F format]",
.flags = 0,
.exec = cmd_list_sessions_exec
"list-sessions", "ls", "",
0,
NULL,
NULL,
cmd_list_sessions_exec,
NULL,
NULL,
NULL,
NULL
};
enum cmd_retval
cmd_list_sessions_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s;
u_int n;
struct format_tree *ft;
const char *template;
char *line;
struct session *s;
char *tim;
u_int i;
time_t t;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_SESSIONS_TEMPLATE;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
n = 0;
RB_FOREACH(s, sessions, &sessions) {
ft = format_create(cmdq, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, NULL, NULL);
t = s->tv.tv_sec;
tim = ctime(&t);
*strchr(tim, '\n') = '\0';
line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line);
free(line);
format_free(ft);
n++;
ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s",
s->name, winlink_count(&s->windows), tim, s->sx, s->sy,
s->flags & SESSION_UNATTACHED ? "" : " (attached)");
}
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-list-windows.c,v 1.33 2009-03-28 20:17:29 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include "tmux.h"
@@ -27,93 +26,62 @@
* 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 *);
void cmd_list_windows_server(struct cmd *, struct cmd_q *);
void cmd_list_windows_session(struct cmd *, struct session *,
struct cmd_q *, int);
int cmd_list_windows_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_windows_entry = {
.name = "list-windows",
.alias = "lsw",
.args = { "F:at:", 0, 0 },
.usage = "[-a] [-F format] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_list_windows_exec
"list-windows", "lsw",
CMD_TARGET_SESSION_USAGE,
0,
cmd_target_init,
cmd_target_parse,
cmd_list_windows_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
enum cmd_retval
cmd_list_windows_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
if (args_has(args, 'a'))
cmd_list_windows_server(self, cmdq);
else
cmd_list_windows_session(self, cmdq->state.tflag.s, cmdq, 0);
return (CMD_RETURN_NORMAL);
}
void
cmd_list_windows_server(struct cmd *self, struct cmd_q *cmdq)
{
struct session *s;
RB_FOREACH(s, sessions, &sessions)
cmd_list_windows_session(self, s, cmdq, 1);
}
void
cmd_list_windows_session(struct cmd *self, struct session *s,
struct cmd_q *cmdq, int type)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct session *s;
struct winlink *wl;
u_int n;
struct format_tree *ft;
const char *template;
char *line;
struct window *w;
struct window_pane *wp;
struct grid *gd;
u_int i;
unsigned long long size;
const char *name;
template = args_get(args, 'F');
if (template == NULL) {
switch (type) {
case 0:
template = LIST_WINDOWS_TEMPLATE;
break;
case 1:
template = LIST_WINDOWS_WITH_SESSION_TEMPLATE;
break;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
RB_FOREACH(wl, winlinks, &s->windows) {
w = wl->window;
ctx->print(ctx,
"%3d: %s [%ux%u]", wl->idx, w->name, w->sx, w->sy);
TAILQ_FOREACH(wp, &w->panes, entry) {
gd = wp->base.grid;
size = 0;
for (i = 0; i < gd->hsize; i++) {
size += gd->size[i] * sizeof **gd->data;
size += gd->usize[i] * sizeof **gd->udata;
}
size += gd->hsize * (sizeof *gd->data);
size += gd->hsize * (sizeof *gd->size);
if (wp->fd != -1)
name = ttyname(wp->fd);
else
name = "unknown";
ctx->print(ctx,
" %s [%ux%u] [history %u/%u, %llu bytes]",
name, wp->sx, wp->sy, gd->hsize, gd->hlimit, size);
}
}
n = 0;
RB_FOREACH(wl, winlinks, &s->windows) {
ft = format_create(cmdq, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, NULL);
line = format_expand(ft, template);
cmdq_print(cmdq, "%s", line);
free(line);
format_free(ft);
n++;
}
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-list.c,v 1.3 2009-02-16 18:57:16 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,109 +18,122 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
struct cmd_list *
cmd_list_parse(int argc, char **argv, const char *file, u_int line,
char **cause)
cmd_list_parse(int argc, char **argv, char **cause)
{
struct cmd_list *cmdlist;
struct cmd *cmd;
int i, lastsplit;
size_t arglen, new_argc;
char **copy_argv, **new_argv;
copy_argv = cmd_copy_argv(argc, argv);
cmdlist = xcalloc(1, sizeof *cmdlist);
cmdlist->references = 1;
TAILQ_INIT(&cmdlist->list);
cmdlist = xmalloc(sizeof *cmdlist);
TAILQ_INIT(cmdlist);
lastsplit = 0;
for (i = 0; i < argc; i++) {
arglen = strlen(copy_argv[i]);
if (arglen == 0 || copy_argv[i][arglen - 1] != ';')
continue;
copy_argv[i][arglen - 1] = '\0';
if (arglen > 1 && copy_argv[i][arglen - 2] == '\\') {
copy_argv[i][arglen - 2] = ';';
continue;
if (strcmp(argv[i], "\\;") == 0) {
argv[i][0] = ';';
argv[i][1] = '\0';
} else if (strcmp(argv[i], ";") == 0) {
cmd = cmd_parse(i - lastsplit, argv + lastsplit, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(cmdlist, cmd, qentry);
lastsplit = i + 1;
}
new_argc = i - lastsplit;
new_argv = copy_argv + lastsplit;
if (arglen != 1)
new_argc++;
cmd = cmd_parse(new_argc, new_argv, file, line, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
lastsplit = i + 1;
}
if (lastsplit != argc) {
cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit,
file, line, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
}
cmd_free_argv(argc, copy_argv);
cmd = cmd_parse(argc - lastsplit, argv + lastsplit, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(cmdlist, cmd, qentry);
return (cmdlist);
bad:
cmd_list_free(cmdlist);
cmd_free_argv(argc, copy_argv);
return (NULL);
}
int
cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx)
{
struct cmd *cmd;
int n;
TAILQ_FOREACH(cmd, cmdlist, qentry) {
if ((n = cmd_exec(cmd, ctx)) != 0)
return (n);
}
return (0);
}
void
cmd_list_send(struct cmd_list *cmdlist, struct buffer *b)
{
struct cmd *cmd;
u_int n;
n = 0;
TAILQ_FOREACH(cmd, cmdlist, qentry)
n++;
buffer_write(b, &n, sizeof n);
TAILQ_FOREACH(cmd, cmdlist, qentry)
cmd_send(cmd, b);
}
struct cmd_list *
cmd_list_recv(struct buffer *b)
{
struct cmd_list *cmdlist;
struct cmd *cmd;
u_int n;
buffer_read(b, &n, sizeof n);
cmdlist = xmalloc(sizeof *cmdlist);
TAILQ_INIT(cmdlist);
while (n-- > 0) {
cmd = cmd_recv(b);
TAILQ_INSERT_TAIL(cmdlist, cmd, qentry);
}
return (cmdlist);
}
void
cmd_list_free(struct cmd_list *cmdlist)
{
struct cmd *cmd, *cmd1;
if (--cmdlist->references != 0)
return;
TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) {
TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
args_free(cmd->args);
free(cmd->file);
free(cmd);
struct cmd *cmd;
while (!TAILQ_EMPTY(cmdlist)) {
cmd = TAILQ_FIRST(cmdlist);
TAILQ_REMOVE(cmdlist, cmd, qentry);
cmd_free(cmd);
}
free(cmdlist);
xfree(cmdlist);
}
char *
cmd_list_print(struct cmd_list *cmdlist)
size_t
cmd_list_print(struct cmd_list *cmdlist, char *buf, size_t len)
{
struct cmd *cmd;
char *buf, *this;
size_t len;
size_t off;
len = 1;
buf = xcalloc(1, len);
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
this = cmd_print(cmd);
len += strlen(this) + 3;
buf = xrealloc(buf, len);
strlcat(buf, this, len);
off = 0;
TAILQ_FOREACH(cmd, cmdlist, qentry) {
if (off >= len)
break;
off += cmd_print(cmd, buf + off, len - off);
if (off >= len)
break;
if (TAILQ_NEXT(cmd, qentry) != NULL)
strlcat(buf, " ; ", len);
free(this);
off += xsnprintf(buf + off, len - off, " ; ");
}
return (buf);
return (off);
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */
/* $Id: cmd-load-buffer.c,v 1.2 2009-01-27 23:26:15 nicm Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -17,10 +17,9 @@
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -28,146 +27,76 @@
#include "tmux.h"
/*
* Loads a paste buffer from a file.
* Loads a session paste buffer from a file.
*/
enum cmd_retval cmd_load_buffer_exec(struct cmd *, struct cmd_q *);
void cmd_load_buffer_callback(struct client *, int, void *);
int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_load_buffer_entry = {
.name = "load-buffer",
.alias = "loadb",
.args = { "b:", 1, 1 },
.usage = CMD_BUFFER_USAGE " path",
.flags = 0,
.exec = cmd_load_buffer_exec
"load-buffer", "loadb",
CMD_BUFFER_SESSION_USAGE " path",
CMD_ARG1,
cmd_buffer_init,
cmd_buffer_parse,
cmd_load_buffer_exec,
cmd_buffer_send,
cmd_buffer_recv,
cmd_buffer_free,
cmd_buffer_print
};
enum cmd_retval
cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c = cmdq->client;
struct session *s;
FILE *f;
const char *path, *bufname, *cwd;
char *pdata, *new_pdata, *cause, *file, resolved[PATH_MAX];
size_t psize;
int ch, error;
struct cmd_buffer_data *data = self->data;
struct session *s;
struct stat statbuf;
FILE *f;
char *buf;
u_int limit;
bufname = NULL;
if (args_has(args, 'b'))
bufname = args_get(args, 'b');
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
path = args->argv[0];
if (strcmp(path, "-") == 0) {
error = server_set_stdin_callback(c, cmd_load_buffer_callback,
(void *)bufname, &cause);
if (error != 0) {
cmdq_error(cmdq, "%s: %s", path, cause);
free(cause);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_WAIT);
if (stat(data->arg, &statbuf) < 0) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1);
}
if (c != NULL && c->session == NULL && c->cwd != NULL)
cwd = c->cwd;
else if ((s = c->session) != NULL && s->cwd != NULL)
cwd = s->cwd;
else
cwd = ".";
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);
}
f = fopen(resolved, "rb");
free(file);
if (f == NULL) {
cmdq_error(cmdq, "%s: %s", resolved, strerror(errno));
return (CMD_RETURN_ERROR);
if ((f = fopen(data->arg, "r")) == NULL) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1);
}
pdata = NULL;
psize = 0;
while ((ch = getc(f)) != EOF) {
/* Do not let the server die due to memory exhaustion. */
if ((new_pdata = realloc(pdata, psize + 2)) == NULL) {
cmdq_error(cmdq, "realloc error: %s", strerror(errno));
goto error;
}
pdata = new_pdata;
pdata[psize++] = ch;
/*
* We don't want to die due to memory exhaustion, hence xmalloc can't
* be used here.
*/
if ((buf = malloc(statbuf.st_size + 1)) == NULL) {
ctx->error(ctx, "malloc error: %s", strerror(errno));
return (-1);
}
if (ferror(f)) {
cmdq_error(cmdq, "%s: read error", resolved);
goto error;
}
if (pdata != NULL)
pdata[psize] = '\0';
if (fread(buf, 1, statbuf.st_size, f) != (size_t) statbuf.st_size) {
ctx->error(ctx, "%s: fread error", data->arg);
xfree(buf);
fclose(f);
return (-1);
}
buf[statbuf.st_size] = '\0';
fclose(f);
if (paste_set(pdata, psize, bufname, &cause) != 0) {
cmdq_error(cmdq, "%s", cause);
free(pdata);
free(cause);
return (CMD_RETURN_ERROR);
limit = options_get_number(&s->options, "buffer-limit");
if (data->buffer == -1) {
paste_add(&s->buffers, buf, limit);
return (0);
}
if (paste_replace(&s->buffers, data->buffer, buf) != 0) {
ctx->error(ctx, "no buffer %d", data->buffer);
xfree(buf);
return (-1);
}
return (CMD_RETURN_NORMAL);
error:
free(pdata);
if (f != NULL)
fclose(f);
return (CMD_RETURN_ERROR);
}
void
cmd_load_buffer_callback(struct client *c, int closed, void *data)
{
const char *bufname = data;
char *pdata, *cause, *saved;
size_t psize;
if (!closed)
return;
c->stdin_callback = NULL;
server_client_unref(c);
if (c->flags & CLIENT_DEAD)
return;
psize = EVBUFFER_LENGTH(c->stdin_data);
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL)
goto out;
memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize);
pdata[psize] = '\0';
evbuffer_drain(c->stdin_data, psize);
if (paste_set(pdata, psize, bufname, &cause) != 0) {
/* No context so can't use server_client_msg_error. */
if (~c->flags & CLIENT_UTF8) {
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);
}
out:
cmdq_continue(c->cmdq);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-lock-server.c,v 1.2 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,62 +18,37 @@
#include <sys/types.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
/*
* Lock commands.
* Lock server.
*/
enum cmd_retval cmd_lock_server_exec(struct cmd *, struct cmd_q *);
int cmd_lock_server_exec(struct cmd *, struct cmd_ctx *);
int cmd_lock_server_callback(void *, const char *);
const struct cmd_entry cmd_lock_server_entry = {
.name = "lock-server",
.alias = "lock",
.args = { "", 0, 0 },
.usage = "",
.flags = 0,
.exec = cmd_lock_server_exec
"lock-server", "lock",
"",
0,
NULL,
NULL,
cmd_lock_server_exec,
NULL,
NULL,
NULL,
NULL,
};
const struct cmd_entry cmd_lock_session_entry = {
.name = "lock-session",
.alias = "locks",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_lock_server_exec
};
const struct cmd_entry cmd_lock_client_entry = {
.name = "lock-client",
.alias = "lockc",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_lock_server_exec
};
enum cmd_retval
cmd_lock_server_exec(struct cmd *self, __unused struct cmd_q *cmdq)
int
cmd_lock_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
{
if (self->entry == &cmd_lock_server_entry)
server_lock();
else if (self->entry == &cmd_lock_session_entry)
server_lock_session(cmdq->state.tflag.s);
else
server_lock_client(cmdq->state.c);
server_lock();
recalculate_sizes();
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-move-window.c,v 1.5 2009-01-23 16:59:14 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -26,83 +26,98 @@
* Move a window.
*/
enum cmd_retval cmd_move_window_exec(struct cmd *, struct cmd_q *);
int cmd_move_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_move_window_entry = {
.name = "move-window",
.alias = "movew",
.args = { "adkrs:t:", 0, 0 },
.usage = "[-dkr] " CMD_SRCDST_WINDOW_USAGE,
.sflag = CMD_WINDOW,
.tflag = CMD_MOVEW_R,
.flags = 0,
.exec = cmd_move_window_exec
"move-window", "movew",
"[-dk] " CMD_SRCDST_WINDOW_USAGE,
CMD_DFLAG|CMD_KFLAG,
cmd_srcdst_init,
cmd_srcdst_parse,
cmd_move_window_exec,
cmd_srcdst_send,
cmd_srcdst_recv,
cmd_srcdst_free,
cmd_srcdst_print
};
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
cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *src = cmdq->state.sflag.s;
struct session *dst = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.sflag.wl;
char *cause;
int idx = cmdq->state.tflag.idx, kflag, dflag, sflag;
struct cmd_srcdst_data *data = self->data;
struct session *src, *dst;
struct winlink *wl_src, *wl_dst;
struct client *c;
u_int i;
int destroyed, idx;
char *cause;
kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd');
if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL)
return (-1);
if (args_has(args, 'r')) {
session_renumber_windows(dst);
recalculate_sizes();
return (CMD_RETURN_NORMAL);
if (arg_parse_window(data->dst, &dst, &idx) != 0) {
ctx->error(ctx, "bad window: %s", data->dst);
return (-1);
}
if (dst == NULL)
dst = ctx->cursession;
if (dst == NULL)
dst = cmd_current_session(ctx);
if (dst == NULL) {
ctx->error(ctx, "session not found: %s", data->dst);
return (-1);
}
kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd');
sflag = args_has(self->args, 's');
wl_dst = NULL;
if (idx != -1)
wl_dst = winlink_find_by_index(&dst->windows, idx);
if (wl_dst != NULL) {
if (wl_dst->window == wl_src->window)
return (0);
if (args_has(self->args, 'a')) {
if ((idx = winlink_shuffle_up(dst, dst->curw)) == -1)
return (CMD_RETURN_ERROR);
if (data->flags & CMD_KFLAG) {
/*
* Can't use session_detach as it will destroy session
* if this makes it empty.
*/
session_alert_cancel(dst, wl_dst);
winlink_stack_remove(&dst->lastw, wl_dst);
winlink_remove(&dst->windows, wl_dst);
/* Force select/redraw if current. */
if (wl_dst == dst->curw) {
data->flags &= ~CMD_DFLAG;
dst->curw = NULL;
}
}
}
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);
wl_dst = session_attach(dst, wl_src->window, idx, &cause);
if (wl_dst == NULL) {
ctx->error(ctx, "attach window failed: %s", cause);
xfree(cause);
return (-1);
}
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);
destroyed = session_detach(src, wl_src);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != src)
continue;
if (destroyed) {
c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0);
} else
server_redraw_client(c);
}
if (data->flags & CMD_DFLAG)
server_status_session(dst);
else {
session_select(dst, wl_dst->idx);
server_redraw_session(dst);
}
recalculate_sizes();
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-new-session.c,v 1.40 2009-04-01 18:21:24 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,307 +18,231 @@
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "tmux.h"
/*
* Create a new session and attach to the current terminal unless -d is given.
*/
#define NEW_SESSION_TEMPLATE "#{session_name}:"
int cmd_new_session_parse(struct cmd *, int, char **, char **);
int cmd_new_session_exec(struct cmd *, struct cmd_ctx *);
void cmd_new_session_send(struct cmd *, struct buffer *);
void cmd_new_session_recv(struct cmd *, struct buffer *);
void cmd_new_session_free(struct cmd *);
void cmd_new_session_init(struct cmd *, int);
size_t cmd_new_session_print(struct cmd *, char *, size_t);
enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_q *);
struct cmd_new_session_data {
char *newname;
char *winname;
char *cmd;
int flag_detached;
};
const struct cmd_entry cmd_new_session_entry = {
.name = "new-session",
.alias = "new",
.args = { "Ac:dDEF:n:Ps:t:x:y:", 0, -1 },
.usage = "[-AdDEP] [-c start-directory] [-F format] [-n window-name] "
"[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
"[-y height] [command]",
.tflag = CMD_SESSION_CANFAIL,
.flags = CMD_STARTSERVER,
.exec = cmd_new_session_exec
"new-session", "new",
"[-d] [-n window-name] [-s session-name] [command]",
CMD_STARTSERVER|CMD_CANTNEST,
cmd_new_session_init,
cmd_new_session_parse,
cmd_new_session_exec,
cmd_new_session_send,
cmd_new_session_recv,
cmd_new_session_free,
cmd_new_session_print
};
const struct cmd_entry cmd_has_session_entry = {
.name = "has-session",
.alias = "has",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_new_session_exec
};
enum cmd_retval
cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
void
cmd_new_session_init(struct cmd *self, unused int arg)
{
struct args *args = self->args;
struct client *c = cmdq->client;
struct session *s, *as;
struct session *groupwith = cmdq->state.tflag.s;
struct window *w;
struct environ *env;
struct termios tio, *tiop;
const char *newname, *target, *update, *errstr, *template;
const char *path, *cwd, *to_free = NULL;
char **argv, *cmd, *cause, *cp;
int detached, already_attached, idx, argc;
u_int sx, sy;
struct format_tree *ft;
struct environ_entry *envent;
struct cmd_new_session_data *data;
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);
}
self->data = data = xmalloc(sizeof *data);
data->flag_detached = 0;
data->newname = NULL;
data->winname = NULL;
data->cmd = NULL;
}
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);
}
int
cmd_new_session_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_new_session_data *data;
int opt;
newname = args_get(args, 's');
if (newname != NULL) {
if (!session_check_name(newname)) {
cmdq_error(cmdq, "bad session name: %s", newname);
return (CMD_RETURN_ERROR);
self->entry->init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "ds:n:")) != -1) {
switch (opt) {
case 'd':
data->flag_detached = 1;
break;
case 's':
if (data->newname == NULL)
data->newname = xstrdup(optarg);
break;
case 'n':
if (data->winname == NULL)
data->winname = xstrdup(optarg);
break;
default:
goto usage;
}
if ((as = session_find(newname)) != NULL) {
if (args_has(args, 'A')) {
/*
* 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.
*/
cmd_find_from_session(&cmdq->state.tflag, as);
return (cmd_attach_session(cmdq,
args_has(args, 'D'), 0, NULL,
args_has(args, 'E')));
}
cmdq_error(cmdq, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR);
}
argc -= optind;
argv += optind;
if (argc != 0 && argc != 1)
goto usage;
if (argc == 1)
data->cmd = xstrdup(argv[0]);
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
int
cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_new_session_data *data = self->data;
struct client *c = ctx->cmdclient;
struct session *s;
char *cmd, *cwd, *cause;
u_int sx, sy;
if (ctx->curclient != NULL)
return (0);
if (!data->flag_detached) {
if (c == NULL) {
ctx->error(ctx, "no client to attach to");
return (-1);
}
if (!(c->flags & CLIENT_TERMINAL)) {
ctx->error(ctx, "not a terminal");
return (-1);
}
}
if ((target = args_get(args, 't')) != NULL) {
if (groupwith == NULL) {
cmdq_error(cmdq, "no such session: %s", target);
goto error;
}
} else
groupwith = NULL;
if (data->newname != NULL && session_find(data->newname) != NULL) {
ctx->error(ctx, "duplicate session: %s", data->newname);
return (-1);
}
/* Set -d if no client. */
detached = args_has(args, 'd');
if (c == NULL)
detached = 1;
/* Is this client already attached? */
already_attached = 0;
if (c != NULL && c->session != NULL)
already_attached = 1;
/* Get the new session working directory. */
if (args_has(args, 'c')) {
ft = format_create(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 && c->cwd != NULL)
cwd = c->cwd;
cmd = data->cmd;
if (cmd == NULL)
cmd = options_get_string(&global_options, "default-command");
if (c == NULL || c->cwd == NULL)
cwd = options_get_string(&global_options, "default-path");
else
cwd = ".";
cwd = c->cwd;
/*
* If this is a new client, check for nesting and save the termios
* settings (part of which is used for new windows in this session).
*
* tcgetattr() is used rather than using tty.tio since if the client is
* detached, tty_open won't be called. It must be done before opening
* the terminal as that calls tcsetattr() to prepare for tmux taking
* over.
*/
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)
fatal("tcgetattr failed");
tiop = &tio;
} else
tiop = NULL;
/* Open the terminal if necessary. */
if (!detached && !already_attached) {
if (server_client_open(c, &cause) != 0) {
cmdq_error(cmdq, "open terminal failed: %s", cause);
free(cause);
goto error;
}
}
/* Find new session size. */
if (c != NULL) {
sx = 80;
sy = 25;
if (!data->flag_detached) {
sx = c->tty.sx;
sy = c->tty.sy;
} else {
sx = 80;
sy = 24;
}
if (detached && args_has(args, 'x')) {
sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(cmdq, "width %s", errstr);
goto error;
}
}
if (detached && args_has(args, 'y')) {
sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(cmdq, "height %s", errstr);
goto error;
}
}
if (sy > 0 && options_get_number(global_s_options, "status"))
sy--;
if (sx == 0)
sx = 1;
if (sy == 0)
sy = 1;
/* Figure out the command for the new window. */
argc = -1;
argv = NULL;
if (!args_has(args, 't') && args->argc != 0) {
argc = args->argc;
argv = args->argv;
} else if (groupwith == 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
envent = environ_find(global_environ, "PATH");
if (envent != NULL)
path = envent->value;
/* Construct the environment. */
env = environ_create();
if (c != NULL && !args_has(args, 'E')) {
update = options_get_string(global_s_options,
"update-environment");
environ_update(update, c->environ, env);
if (options_get_number(&global_options, "status")) {
if (sy == 0)
sy = 1;
else
sy--;
}
/* Create the new session. */
idx = -1 - options_get_number(global_s_options, "base-index");
s = session_create(newname, argc, argv, path, cwd, env, tiop, idx, sx,
sy, &cause);
environ_free(env);
if (!data->flag_detached && tty_open(&c->tty, &cause) != 0) {
ctx->error(ctx, "open terminal failed: %s", cause);
xfree(cause);
return (-1);
}
s = session_create(data->newname, cmd, cwd, sx, sy, &cause);
if (s == NULL) {
cmdq_error(cmdq, "create session failed: %s", cause);
free(cause);
goto error;
ctx->error(ctx, "create session failed: %s", cause);
xfree(cause);
return (-1);
}
if (data->winname != NULL) {
xfree(s->curw->window->name);
s->curw->window->name = xstrdup(data->winname);
options_set_number(
&s->curw->window->options, "automatic-rename", 0);
}
/* Set the initial window name if one given. */
if (argc >= 0 && args_has(args, 'n')) {
w = s->curw->window;
window_set_name(w, args_get(args, 'n'));
options_set_number(w->options, "automatic-rename", 0);
}
/*
* If a target session is given, this is to be part of a session group,
* so add it to the group and synchronize.
*/
if (groupwith != NULL) {
session_group_add(groupwith, s);
session_group_synchronize_to(s);
session_select(s, RB_MIN(winlinks, &s->windows)->idx);
}
/*
* Set the client to the new session. If a command client exists, it is
* taking this session and needs to get MSG_READY and stay around.
*/
if (!detached) {
if (!already_attached) {
if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0);
} else if (c->session != NULL)
c->last_session = c->session;
if (data->flag_detached) {
if (c != NULL)
server_write_client(c, MSG_EXIT, NULL, 0);
} else {
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_write_client(c, MSG_READY, NULL, 0);
server_redraw_client(c);
}
recalculate_sizes();
server_update_socket();
/*
* If there are still configuration file errors to display, put the new
* session's current window into more mode and display them now.
*/
if (cfg_finished)
cfg_show_causes(s);
/* Print if requested. */
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = NEW_SESSION_TEMPLATE;
ft = format_create(cmdq, 0);
format_defaults(ft, c, s, NULL, NULL);
cp = format_expand(ft, template);
cmdq_print(cmdq, "%s", cp);
free(cp);
format_free(ft);
}
if (!detached)
cmdq->client_exit = 0;
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_NORMAL);
error:
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_ERROR);
return (1);
}
void
cmd_new_session_send(struct cmd *self, struct buffer *b)
{
struct cmd_new_session_data *data = self->data;
buffer_write(b, data, sizeof *data);
cmd_send_string(b, data->newname);
cmd_send_string(b, data->winname);
cmd_send_string(b, data->cmd);
}
void
cmd_new_session_recv(struct cmd *self, struct buffer *b)
{
struct cmd_new_session_data *data;
self->data = data = xmalloc(sizeof *data);
buffer_read(b, data, sizeof *data);
data->newname = cmd_recv_string(b);
data->winname = cmd_recv_string(b);
data->cmd = cmd_recv_string(b);
}
void
cmd_new_session_free(struct cmd *self)
{
struct cmd_new_session_data *data = self->data;
if (data->newname != NULL)
xfree(data->newname);
if (data->winname != NULL)
xfree(data->winname);
if (data->cmd != NULL)
xfree(data->cmd);
xfree(data);
}
size_t
cmd_new_session_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_new_session_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->flag_detached)
off += xsnprintf(buf + off, len - off, " -d");
if (off < len && data->newname != NULL)
off += cmd_prarg(buf + off, len - off, " -s ", data->newname);
if (off < len && data->winname != NULL)
off += cmd_prarg(buf + off, len - off, " -n ", data->winname);
if (off < len && data->cmd != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->cmd);
return (off);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-new-window.c,v 1.31 2009-01-23 16:59:14 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,11 +18,7 @@
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
@@ -30,134 +26,216 @@
* Create a new window.
*/
#define NEW_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
int cmd_new_window_parse(struct cmd *, int, char **, char **);
int cmd_new_window_exec(struct cmd *, struct cmd_ctx *);
void cmd_new_window_send(struct cmd *, struct buffer *);
void cmd_new_window_recv(struct cmd *, struct buffer *);
void cmd_new_window_free(struct cmd *);
void cmd_new_window_init(struct cmd *, int);
size_t cmd_new_window_print(struct cmd *, char *, size_t);
enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_new_window_entry = {
.name = "new-window",
.alias = "neww",
.args = { "ac:dF:kn:Pt:", 0, -1 },
.usage = "[-adkP] [-c start-directory] [-F format] [-n window-name] "
CMD_TARGET_WINDOW_USAGE " [command]",
.tflag = CMD_WINDOW_INDEX,
.flags = 0,
.exec = cmd_new_window_exec
struct cmd_new_window_data {
char *target;
char *name;
char *cmd;
int flag_detached;
int flag_kill;
};
enum cmd_retval
cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
const struct cmd_entry cmd_new_window_entry = {
"new-window", "neww",
"[-dk] [-n window-name] [-t target-window] [command]",
0,
cmd_new_window_init,
cmd_new_window_parse,
cmd_new_window_exec,
cmd_new_window_send,
cmd_new_window_recv,
cmd_new_window_free,
cmd_new_window_print
};
void
cmd_new_window_init(struct cmd *self, unused int arg)
{
struct args *args = self->args;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl;
struct client *c = cmdq->state.c;
int idx = cmdq->state.tflag.idx;
const char *cmd, *path, *template, *cwd, *to_free;
char **argv, *cause, *cp;
int argc, detached;
struct format_tree *ft;
struct environ_entry *envent;
struct cmd_new_window_data *data;
if (args_has(args, 'a')) {
if ((idx = winlink_shuffle_up(s, wl)) == -1) {
cmdq_error(cmdq, "no free window indexes");
return (CMD_RETURN_ERROR);
self->data = data = xmalloc(sizeof *data);
data->target = NULL;
data->name = NULL;
data->cmd = NULL;
data->flag_detached = 0;
data->flag_kill = 0;
}
int
cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_new_window_data *data;
int opt;
self->entry->init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "dkt:n:")) != -1) {
switch (opt) {
case 'd':
data->flag_detached = 1;
break;
case 'k':
data->flag_kill = 1;
break;
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
case 'n':
if (data->name == NULL)
data->name = xstrdup(optarg);
break;
default:
goto usage;
}
}
detached = args_has(args, 'd');
argc -= optind;
argv += optind;
if (argc != 0 && argc != 1)
goto usage;
if (args->argc == 0) {
cmd = options_get_string(s->options, "default-command");
if (cmd != NULL && *cmd != '\0') {
argc = 1;
argv = (char **)&cmd;
} else {
argc = 0;
argv = NULL;
}
} else {
argc = args->argc;
argv = args->argv;
if (argc == 1)
data->cmd = xstrdup(argv[0]);
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
int
cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_new_window_data *data = self->data;
struct session *s;
struct winlink *wl;
char *cmd, *cwd, *cause;
int idx;
if (data == NULL)
return (0);
if (arg_parse_window(data->target, &s, &idx) != 0) {
ctx->error(ctx, "bad window: %s", data->target);
return (-1);
}
if (s == NULL)
s = ctx->cursession;
if (s == NULL)
s = cmd_current_session(ctx);
if (s == NULL) {
ctx->error(ctx, "session not found: %s", data->target);
return (-1);
}
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;
if (idx != -1)
wl = winlink_find_by_index(&s->windows, idx);
if (wl != NULL && args_has(args, 'k')) {
/*
* Can't use session_detach as it will destroy session if this
* makes it empty.
*/
notify_window_unlinked(s, wl->window);
wl->flags &= ~WINLINK_ALERTFLAGS;
winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl);
if (wl != NULL) {
if (data->flag_kill) {
/*
* Can't use session_detach as it will destroy session
* if this makes it empty.
*/
session_alert_cancel(s, wl);
winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl);
/* Force select/redraw if current. */
if (wl == s->curw) {
detached = 0;
s->curw = NULL;
/* Force select/redraw if current. */
if (wl == s->curw) {
data->flag_detached = 0;
s->curw = NULL;
}
}
}
if (idx == -1)
idx = -1 - options_get_number(s->options, "base-index");
wl = session_new(s, args_get(args, 'n'), argc, argv, path, cwd, idx,
&cause);
cmd = data->cmd;
if (cmd == NULL)
cmd = options_get_string(&s->options, "default-command");
if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL)
cwd = options_get_string(&global_options, "default-path");
else
cwd = ctx->cmdclient->cwd;
wl = session_new(s, data->name, cmd, cwd, idx, &cause);
if (wl == NULL) {
cmdq_error(cmdq, "create window failed: %s", cause);
free(cause);
goto error;
ctx->error(ctx, "create window failed: %s", cause);
xfree(cause);
return (-1);
}
if (!detached) {
if (!data->flag_detached) {
session_select(s, wl->idx);
server_redraw_session_group(s);
server_redraw_session(s);
} else
server_status_session_group(s);
server_status_session(s);
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = NEW_WINDOW_TEMPLATE;
ft = format_create(cmdq, 0);
format_defaults(ft, c, s, wl, NULL);
cp = format_expand(ft, template);
cmdq_print(cmdq, "%s", cp);
free(cp);
format_free(ft);
}
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_NORMAL);
error:
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_ERROR);
return (0);
}
void
cmd_new_window_send(struct cmd *self, struct buffer *b)
{
struct cmd_new_window_data *data = self->data;
buffer_write(b, data, sizeof *data);
cmd_send_string(b, data->target);
cmd_send_string(b, data->name);
cmd_send_string(b, data->cmd);
}
void
cmd_new_window_recv(struct cmd *self, struct buffer *b)
{
struct cmd_new_window_data *data;
self->data = data = xmalloc(sizeof *data);
buffer_read(b, data, sizeof *data);
data->target = cmd_recv_string(b);
data->name = cmd_recv_string(b);
data->cmd = cmd_recv_string(b);
}
void
cmd_new_window_free(struct cmd *self)
{
struct cmd_new_window_data *data = self->data;
if (data->target != NULL)
xfree(data->target);
if (data->name != NULL)
xfree(data->name);
if (data->cmd != NULL)
xfree(data->cmd);
xfree(data);
}
size_t
cmd_new_window_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_new_window_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->flag_detached)
off += xsnprintf(buf + off, len - off, " -d");
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
if (off < len && data->name != NULL)
off += cmd_prarg(buf + off, len - off, " -n ", data->name);
if (off < len && data->cmd != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->cmd);
return (off);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-next-layout.c,v 1.1 2009-04-01 18:21:26 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -21,35 +21,34 @@
#include "tmux.h"
/*
* Clear pane history.
* Switch window to next layout.
*/
enum cmd_retval cmd_clear_history_exec(struct cmd *, struct cmd_q *);
int cmd_next_layout_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_clear_history_entry = {
.name = "clear-history",
.alias = "clearhist",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_clear_history_exec
const struct cmd_entry cmd_next_layout_entry = {
"next-layout", "nextl",
CMD_TARGET_WINDOW_USAGE,
0,
cmd_target_init,
cmd_target_parse,
cmd_next_layout_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
enum cmd_retval
cmd_clear_history_exec(__unused struct cmd *self, struct cmd_q *cmdq)
int
cmd_next_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct window_pane *wp = cmdq->state.tflag.wp;
struct grid *gd;
struct cmd_target_data *data = self->data;
struct winlink *wl;
gd = cmdq->state.tflag.wp->base.grid;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (wp->mode == &window_copy_mode)
window_pane_reset_mode(wp);
grid_clear_history(gd);
layout_next(wl->window);
return (CMD_RETURN_NORMAL);
return (0);
}

78
cmd-next-window.c Normal file
View File

@@ -0,0 +1,78 @@
/* $Id: cmd-next-window.c,v 1.16 2009-03-28 14:08:09 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Move to next window.
*/
void cmd_next_window_init(struct cmd *, int);
int cmd_next_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_next_window_entry = {
"next-window", "next",
CMD_TARGET_SESSION_USAGE,
CMD_AFLAG,
cmd_next_window_init,
cmd_target_parse,
cmd_next_window_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
void
cmd_next_window_init(struct cmd *self, int key)
{
struct cmd_target_data *data;
cmd_target_init(self, key);
data = self->data;
if (key == KEYC_ADDESC('n'))
data->flags |= CMD_AFLAG;
}
int
cmd_next_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct session *s;
int activity;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
activity = 0;
if (data->flags & CMD_AFLAG)
activity = 1;
if (session_next(s, activity) == 0)
server_redraw_session(s);
else {
ctx->error(ctx, "no next window");
return (-1);
}
recalculate_sizes();
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-paste-buffer.c,v 1.15 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -27,84 +26,53 @@
* Paste paste buffer if present.
*/
enum cmd_retval cmd_paste_buffer_exec(struct cmd *, struct cmd_q *);
void cmd_paste_buffer_filter(struct window_pane *,
const char *, size_t, const char *, int);
int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_paste_buffer_entry = {
.name = "paste-buffer",
.alias = "pasteb",
.args = { "db:prs:t:", 0, 0 },
.usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " "
CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_paste_buffer_exec
"paste-buffer", "pasteb",
"[-d] " CMD_BUFFER_WINDOW_USAGE,
CMD_DFLAG,
cmd_buffer_init,
cmd_buffer_parse,
cmd_paste_buffer_exec,
cmd_buffer_send,
cmd_buffer_recv,
cmd_buffer_free,
cmd_buffer_print
};
enum cmd_retval
cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct window_pane *wp = cmdq->state.tflag.wp;
struct cmd_buffer_data *data = self->data;
struct winlink *wl;
struct window *w;
struct session *s;
struct paste_buffer *pb;
const char *sepstr, *bufname, *bufdata, *bufend, *line;
size_t seplen, bufsize;
int bracket = args_has(args, 'p');
bufname = NULL;
if (args_has(args, 'b'))
bufname = args_get(args, 'b');
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
w = wl->window;
if (bufname == NULL)
pb = paste_get_top(NULL);
if (data->buffer == -1)
pb = paste_get_top(&s->buffers);
else {
pb = paste_get_name(bufname);
if (pb == NULL) {
cmdq_error(cmdq, "no buffer %s", bufname);
return (CMD_RETURN_ERROR);
if ((pb = paste_get_index(&s->buffers, data->buffer)) == NULL) {
ctx->error(ctx, "no buffer %d", data->buffer);
return (-1);
}
}
if (pb != NULL && ~wp->flags & PANE_INPUTOFF) {
sepstr = args_get(args, 's');
if (sepstr == NULL) {
if (args_has(args, 'r'))
sepstr = "\n";
else
sepstr = "\r";
}
seplen = strlen(sepstr);
if (pb != NULL)
buffer_write(w->active->out, pb->data, strlen(pb->data));
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 (data->flags & CMD_DFLAG) {
if (data->buffer == -1)
paste_free_top(&s->buffers);
else
paste_free_index(&s->buffers, data->buffer);
}
if (pb != NULL && args_has(args, 'd'))
paste_free(pb);
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,153 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "tmux.h"
/*
* Open pipe to redirect pane output. If already open, close first.
*/
enum cmd_retval cmd_pipe_pane_exec(struct cmd *, struct cmd_q *);
void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *);
const struct cmd_entry cmd_pipe_pane_entry = {
.name = "pipe-pane",
.alias = "pipep",
.args = { "ot:", 0, 1 },
.usage = "[-o] " CMD_TARGET_PANE_USAGE " [command]",
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_pipe_pane_exec
};
enum cmd_retval
cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c = cmdq->state.c;
struct window_pane *wp = cmdq->state.tflag.wp;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl;
char *cmd;
int old_fd, pipe_fd[2], null_fd;
struct format_tree *ft;
/* Destroy the old pipe. */
old_fd = wp->pipe_fd;
if (wp->pipe_fd != -1) {
bufferevent_free(wp->pipe_event);
close(wp->pipe_fd);
wp->pipe_fd = -1;
}
/* If no pipe command, that is enough. */
if (args->argc == 0 || *args->argv[0] == '\0')
return (CMD_RETURN_NORMAL);
/*
* With -o, only open the new pipe if there was no previous one. This
* allows a pipe to be toggled with a single key, for example:
*
* bind ^p pipep -o 'cat >>~/output'
*/
if (args_has(self->args, 'o') && old_fd != -1)
return (CMD_RETURN_NORMAL);
/* Open the new pipe. */
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) {
cmdq_error(cmdq, "socketpair error: %s", strerror(errno));
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. */
switch (fork()) {
case -1:
cmdq_error(cmdq, "fork error: %s", strerror(errno));
free(cmd);
return (CMD_RETURN_ERROR);
case 0:
/* Child process. */
close(pipe_fd[0]);
clear_signals(1);
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
_exit(1);
if (pipe_fd[1] != STDIN_FILENO)
close(pipe_fd[1]);
null_fd = open(_PATH_DEVNULL, O_WRONLY, 0);
if (dup2(null_fd, STDOUT_FILENO) == -1)
_exit(1);
if (dup2(null_fd, STDERR_FILENO) == -1)
_exit(1);
if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO)
close(null_fd);
closefrom(STDERR_FILENO + 1);
execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
_exit(1);
default:
/* Parent process. */
close(pipe_fd[1]);
wp->pipe_fd = pipe_fd[0];
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
wp->pipe_event = bufferevent_new(wp->pipe_fd,
NULL, NULL, cmd_pipe_pane_error_callback, wp);
bufferevent_enable(wp->pipe_event, EV_WRITE);
setblocking(wp->pipe_fd, 0);
free(cmd);
return (CMD_RETURN_NORMAL);
}
}
void
cmd_pipe_pane_error_callback(__unused struct bufferevent *bufev,
__unused short what, void *data)
{
struct window_pane *wp = data;
bufferevent_free(wp->pipe_event);
close(wp->pipe_fd);
wp->pipe_fd = -1;
}

78
cmd-previous-window.c Normal file
View File

@@ -0,0 +1,78 @@
/* $Id: cmd-previous-window.c,v 1.16 2009-03-28 14:08:09 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Move to previous window.
*/
void cmd_previous_window_init(struct cmd *, int);
int cmd_previous_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_previous_window_entry = {
"previous-window", "prev",
CMD_TARGET_SESSION_USAGE,
CMD_AFLAG,
cmd_previous_window_init,
cmd_target_parse,
cmd_previous_window_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
void
cmd_previous_window_init(struct cmd *self, int key)
{
struct cmd_target_data *data;
cmd_target_init(self, key);
data = self->data;
if (key == KEYC_ADDESC('p'))
data->flags |= CMD_AFLAG;
}
int
cmd_previous_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct session *s;
int activity;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
activity = 0;
if (data->flags & CMD_AFLAG)
activity = 1;
if (session_previous(s, activity) == 0)
server_redraw_session(s);
else {
ctx->error(ctx, "no previous window");
return (-1);
}
recalculate_sizes();
return (0);
}

View File

@@ -1,334 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "tmux.h"
static enum cmd_retval cmdq_continue_one(struct cmd_q *);
/* Create new command queue. */
struct cmd_q *
cmdq_new(struct client *c)
{
struct cmd_q *cmdq;
cmdq = xcalloc(1, sizeof *cmdq);
cmdq->references = 1;
cmdq->flags = 0;
cmdq->client = c;
cmdq->client_exit = -1;
TAILQ_INIT(&cmdq->queue);
cmdq->item = NULL;
cmdq->cmd = NULL;
cmd_find_clear_state(&cmdq->current, NULL, 0);
cmdq->parent = NULL;
return (cmdq);
}
/* Free command queue */
int
cmdq_free(struct cmd_q *cmdq)
{
if (--cmdq->references != 0) {
if (cmdq->flags & CMD_Q_DEAD)
return (1);
return (0);
}
cmdq_flush(cmdq);
free(cmdq);
return (1);
}
/* Show message from command. */
void
cmdq_print(struct cmd_q *cmdq, const char *fmt, ...)
{
struct client *c = cmdq->client;
struct window *w;
va_list ap;
char *tmp, *msg;
va_start(ap, fmt);
if (c == NULL)
/* nothing */;
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
if (~c->flags & CLIENT_UTF8) {
xvasprintf(&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(c->stdout_data, "\n", 1);
server_client_push_stdout(c);
} else {
w = c->session->curw->window;
if (w->active->mode != &window_copy_mode) {
window_pane_reset_mode(w->active);
window_pane_set_mode(w->active, &window_copy_mode);
window_copy_init_for_output(w->active);
}
window_copy_vadd(w->active, fmt, ap);
}
va_end(ap);
}
/* Show error from command. */
void
cmdq_error(struct cmd_q *cmdq, const char *fmt, ...)
{
struct client *c = cmdq->client;
struct cmd *cmd = cmdq->cmd;
va_list ap;
char *msg;
size_t msglen;
char *tmp;
va_start(ap, fmt);
msglen = xvasprintf(&msg, fmt, ap);
va_end(ap);
if (c == NULL)
cfg_add_cause("%s:%u: %s", cmd->file, cmd->line, msg);
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
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, "\n", 1);
server_client_push_stderr(c);
c->retval = 1;
} else {
*msg = toupper((u_char) *msg);
status_message_set(c, "%s", msg);
}
free(msg);
}
/* Print a guard line. */
void
cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags)
{
struct client *c = cmdq->client;
if (c == NULL || !(c->flags & CLIENT_CONTROL))
return;
evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
(long) cmdq->time, cmdq->number, flags);
server_client_push_stdout(c);
}
/* Add command list to queue and begin processing if needed. */
void
cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m)
{
cmdq_append(cmdq, cmdlist, m);
if (cmdq->item == NULL) {
cmdq->cmd = NULL;
cmdq_continue(cmdq);
}
}
/* Add command list to queue. */
void
cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m)
{
struct cmd_q_item *item;
item = xcalloc(1, sizeof *item);
item->cmdlist = cmdlist;
TAILQ_INSERT_TAIL(&cmdq->queue, item, qentry);
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;
const char *name = cmd->entry->name;
struct session *s;
struct hooks *hooks;
enum cmd_retval retval;
char *tmp;
int flags = !!(cmd->flags & CMD_CONTROL);
tmp = cmd_print(cmd);
log_debug("cmdq %p: %s", cmdq, tmp);
free(tmp);
cmdq->time = time(NULL);
cmdq->number++;
if (~cmdq->flags & CMD_Q_REENTRY)
cmdq_guard(cmdq, "begin", flags);
if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0)
goto error;
if (~cmdq->flags & CMD_Q_NOHOOKS) {
s = NULL;
if (cmdq->state.tflag.s != NULL)
s = cmdq->state.tflag.s;
else if (cmdq->state.sflag.s != NULL)
s = cmdq->state.sflag.s;
else if (cmdq->state.c != NULL)
s = cmdq->state.c->session;
if (s != NULL)
hooks = s->hooks;
else
hooks = global_hooks;
if (~cmdq->flags & CMD_Q_REENTRY) {
cmdq->flags |= CMD_Q_REENTRY;
if (hooks_wait(hooks, cmdq, NULL,
"before-%s", name) == 0)
return (CMD_RETURN_WAIT);
if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0)
goto error;
}
} else
hooks = NULL;
cmdq->flags &= ~CMD_Q_REENTRY;
retval = cmd->entry->exec(cmd, cmdq);
if (retval == CMD_RETURN_ERROR)
goto error;
if (hooks != NULL && hooks_wait(hooks, cmdq, NULL,
"after-%s", name) == 0)
retval = CMD_RETURN_WAIT;
cmdq_guard(cmdq, "end", flags);
return (retval);
error:
cmdq_guard(cmdq, "error", flags);
cmdq->flags &= ~CMD_Q_REENTRY;
return (CMD_RETURN_ERROR);
}
/* Continue processing command queue. Returns 1 if finishes empty. */
int
cmdq_continue(struct cmd_q *cmdq)
{
struct client *c = cmdq->client;
struct cmd_q_item *next;
enum cmd_retval retval;
int empty;
cmdq->references++;
notify_disable();
log_debug("continuing cmdq %p: flags %#x, client %p", cmdq, cmdq->flags,
c);
empty = TAILQ_EMPTY(&cmdq->queue);
if (empty)
goto empty;
/*
* If the command isn't in the middle of running hooks (due to
* CMD_RETURN_WAIT), move onto the next command; otherwise, leave the
* state of the queue as it is.
*/
if (~cmdq->flags & CMD_Q_REENTRY) {
if (cmdq->item == NULL) {
cmdq->item = TAILQ_FIRST(&cmdq->queue);
cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
} else
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
}
do {
while (cmdq->cmd != NULL) {
retval = cmdq_continue_one(cmdq);
if (retval == CMD_RETURN_ERROR)
break;
if (retval == CMD_RETURN_WAIT)
goto out;
if (retval == CMD_RETURN_STOP) {
cmdq_flush(cmdq);
goto empty;
}
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
}
next = TAILQ_NEXT(cmdq->item, qentry);
TAILQ_REMOVE(&cmdq->queue, cmdq->item, qentry);
cmd_list_free(cmdq->item->cmdlist);
free(cmdq->item);
cmdq->item = next;
if (cmdq->item != NULL)
cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
} while (cmdq->item != NULL);
empty:
if (cmdq->client_exit > 0)
cmdq->client->flags |= CLIENT_EXIT;
if (cmdq->emptyfn != NULL)
cmdq->emptyfn(cmdq);
empty = 1;
out:
notify_enable();
cmdq_free(cmdq);
return (empty);
}
/* Flush command queue. */
void
cmdq_flush(struct cmd_q *cmdq)
{
struct cmd_q_item *item, *item1;
TAILQ_FOREACH_SAFE(item, &cmdq->queue, qentry, item1) {
TAILQ_REMOVE(&cmdq->queue, item, qentry);
cmd_list_free(item->cmdlist);
free(item);
}
cmdq->item = NULL;
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-refresh-client.c,v 1.8 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -24,56 +24,31 @@
* Refresh client.
*/
enum cmd_retval cmd_refresh_client_exec(struct cmd *, struct cmd_q *);
int cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client",
.alias = "refresh",
.args = { "C:St:", 0, 0 },
.usage = "[-S] [-C size] " CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_refresh_client_exec
"refresh-client", "refresh",
CMD_TARGET_CLIENT_USAGE,
0,
cmd_target_init,
cmd_target_parse,
cmd_refresh_client_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
enum cmd_retval
cmd_refresh_client_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c = cmdq->state.c;
const char *size;
u_int w, h;
struct cmd_target_data *data = self->data;
struct client *c;
if (args_has(args, 'C')) {
if ((size = args_get(args, 'C')) == NULL) {
cmdq_error(cmdq, "missing size");
return (CMD_RETURN_ERROR);
}
if (sscanf(size, "%u,%u", &w, &h) != 2) {
cmdq_error(cmdq, "bad size argument");
return (CMD_RETURN_ERROR);
}
if (w < PANE_MINIMUM || w > 5000 ||
h < PANE_MINIMUM || h > 5000) {
cmdq_error(cmdq, "size too small or too big");
return (CMD_RETURN_ERROR);
}
if (!(c->flags & CLIENT_CONTROL)) {
cmdq_error(cmdq, "not a control client");
return (CMD_RETURN_ERROR);
}
if (tty_set_size(&c->tty, w, h))
recalculate_sizes();
} else if (args_has(args, 'S')) {
c->flags |= CLIENT_STATUSFORCE;
server_status_client(c);
} else {
c->flags |= CLIENT_STATUSFORCE;
server_redraw_client(c);
}
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
return (CMD_RETURN_NORMAL);
server_redraw_client(c);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-rename-session.c,v 1.15 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -26,45 +26,32 @@
* Change session name.
*/
enum cmd_retval cmd_rename_session_exec(struct cmd *, struct cmd_q *);
int cmd_rename_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_rename_session_entry = {
.name = "rename-session",
.alias = "rename",
.args = { "t:", 1, 1 },
.usage = CMD_TARGET_SESSION_USAGE " new-name",
.tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_rename_session_exec
"rename-session", "rename",
CMD_TARGET_SESSION_USAGE " new-name",
CMD_ARG1,
cmd_target_init,
cmd_target_parse,
cmd_rename_session_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
enum cmd_retval
cmd_rename_session_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s = cmdq->state.tflag.s;
const char *newname;
struct cmd_target_data *data = self->data;
struct session *s;
newname = args->argv[0];
if (!session_check_name(newname)) {
cmdq_error(cmdq, "bad session name: %s", newname);
return (CMD_RETURN_ERROR);
}
if (session_find(newname) != NULL) {
cmdq_error(cmdq, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR);
}
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
RB_REMOVE(sessions, &sessions, s);
free(s->name);
s->name = xstrdup(newname);
RB_INSERT(sessions, &sessions, s);
xfree(s->name);
s->name = xstrdup(data->arg);
server_status_session(s);
notify_session_renamed(s);
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-rename-window.c,v 1.26 2009-01-20 19:35:03 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -26,31 +26,36 @@
* Rename a window.
*/
enum cmd_retval cmd_rename_window_exec(struct cmd *, struct cmd_q *);
int cmd_rename_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_rename_window_entry = {
.name = "rename-window",
.alias = "renamew",
.args = { "t:", 1, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " new-name",
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_rename_window_exec
"rename-window", "renamew",
CMD_TARGET_WINDOW_USAGE " new-name",
CMD_ARG1,
cmd_target_init,
cmd_target_parse,
cmd_rename_window_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
enum cmd_retval
cmd_rename_window_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct winlink *wl = cmdq->state.tflag.wl;
struct cmd_target_data *data = self->data;
struct session *s;
struct winlink *wl;
window_set_name(wl->window, args->argv[0]);
options_set_number(wl->window->options, "automatic-rename", 0);
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
server_status_window(wl->window);
xfree(wl->window->name);
wl->window->name = xstrdup(data->arg);
options_set_number(&wl->window->options, "automatic-rename", 0);
return (CMD_RETURN_NORMAL);
server_status_session(s);
return (0);
}

122
cmd-resize-pane-down.c Normal file
View File

@@ -0,0 +1,122 @@
/* $Id: cmd-resize-pane-down.c,v 1.8 2009-04-02 21:11:52 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Decrease pane size.
*/
void cmd_resize_pane_down_init(struct cmd *, int);
int cmd_resize_pane_down_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_resize_pane_down_entry = {
"resize-pane-down", "resizep-down",
CMD_PANE_WINDOW_USAGE " [adjustment]",
CMD_ARG01,
cmd_resize_pane_down_init,
cmd_pane_parse,
cmd_resize_pane_down_exec,
cmd_pane_send,
cmd_pane_recv,
cmd_pane_free,
cmd_pane_print
};
void
cmd_resize_pane_down_init(struct cmd *self, int key)
{
struct cmd_pane_data *data;
cmd_pane_init(self, key);
data = self->data;
if (key == KEYC_ADDESC(KEYC_DOWN))
data->arg = xstrdup("5");
}
int
cmd_resize_pane_down_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_pane_data *data = self->data;
struct winlink *wl;
const char *errstr;
struct window_pane *wp, *wq;
u_int adjust;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (wl->window->layout != 0) {
ctx->error(ctx, "window not in manual layout");
return (-1);
}
if (data->pane == -1)
wp = wl->window->active;
else {
wp = window_pane_at_index(wl->window, data->pane);
if (wp == NULL) {
ctx->error(ctx, "no pane: %d", data->pane);
return (-1);
}
}
if (data->arg == NULL)
adjust = 1;
else {
adjust = strtonum(data->arg, 1, INT_MAX, &errstr);
if (errstr != NULL) {
ctx->error(ctx, "adjustment %s: %s", errstr, data->arg);
return (-1);
}
}
/*
* If this is not the last window, keep trying to increase size and
* remove it from the next windows. If it is the last, do so on the
* previous window.
*/
if (TAILQ_NEXT(wp, entry) == NULL) {
if (wp == TAILQ_FIRST(&wl->window->panes)) {
/* Only one pane. */
return (0);
}
wp = TAILQ_PREV(wp, window_panes, entry);
}
while (adjust-- > 0) {
wq = wp;
while ((wq = TAILQ_NEXT(wq, entry)) != NULL) {
if (wq->sy > PANE_MINIMUM) {
window_pane_resize(wq, wq->sx, wq->sy - 1);
break;
}
}
if (wq == NULL)
break;
window_pane_resize(wp, wp->sx, wp->sy + 1);
}
window_update_panes(wl->window);
server_redraw_window(wl->window);
return (0);
}

117
cmd-resize-pane-up.c Normal file
View File

@@ -0,0 +1,117 @@
/* $Id: cmd-resize-pane-up.c,v 1.8 2009-04-02 21:11:52 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Increase pane size.
*/
void cmd_resize_pane_up_init(struct cmd *, int);
int cmd_resize_pane_up_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_resize_pane_up_entry = {
"resize-pane-up", "resizep-up",
CMD_PANE_WINDOW_USAGE " [adjustment]",
CMD_ARG01,
cmd_resize_pane_up_init,
cmd_pane_parse,
cmd_resize_pane_up_exec,
cmd_pane_send,
cmd_pane_recv,
cmd_pane_free,
cmd_pane_print
};
void
cmd_resize_pane_up_init(struct cmd *self, int key)
{
struct cmd_pane_data *data;
cmd_pane_init(self, key);
data = self->data;
if (key == KEYC_ADDESC(KEYC_UP))
data->arg = xstrdup("5");
}
int
cmd_resize_pane_up_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_pane_data *data = self->data;
struct winlink *wl;
const char *errstr;
struct window_pane *wp, *wq;
u_int adjust;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (wl->window->layout != 0) {
ctx->error(ctx, "window not in manual layout");
return (-1);
}
if (data->pane == -1)
wp = wl->window->active;
else {
wp = window_pane_at_index(wl->window, data->pane);
if (wp == NULL) {
ctx->error(ctx, "no pane: %d", data->pane);
return (-1);
}
}
if (data->arg == NULL)
adjust = 1;
else {
adjust = strtonum(data->arg, 1, INT_MAX, &errstr);
if (errstr != NULL) {
ctx->error(ctx, "adjustment %s: %s", errstr, data->arg);
return (-1);
}
}
/*
* If this is not the last window, keep trying to reduce size and add
* to the following window. If it is the last, do so on the previous
* window.
*/
wq = TAILQ_NEXT(wp, entry);
if (wq == NULL) {
if (wp == TAILQ_FIRST(&wl->window->panes)) {
/* Only one pane. */
return (0);
}
wq = wp;
wp = TAILQ_PREV(wq, window_panes, entry);
}
while (adjust-- > 0) {
if (wp->sy <= PANE_MINIMUM)
break;
window_pane_resize(wq, wq->sx, wq->sy + 1);
window_pane_resize(wp, wp->sx, wp->sy - 1);
}
window_update_panes(wl->window);
server_redraw_window(wl->window);
return (0);
}

View File

@@ -1,171 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Increase or decrease pane size.
*/
enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmd_q *);
void cmd_resize_pane_mouse_update(struct client *, struct mouse_event *);
const struct cmd_entry cmd_resize_pane_entry = {
.name = "resize-pane",
.alias = "resizep",
.args = { "DLMRt:Ux:y:Z", 0, 1 },
.usage = "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
"[adjustment]",
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_resize_pane_exec
};
enum cmd_retval
cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct window_pane *wp = cmdq->state.tflag.wp;
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;
char *cause;
u_int adjust;
int x, y;
if (args_has(args, 'M')) {
if (cmd_mouse_window(&cmdq->item->mouse, &s) == NULL)
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);
}
if (args_has(args, 'Z')) {
if (w->flags & WINDOW_ZOOMED)
window_unzoom(w);
else
window_zoom(wp);
server_redraw_window(w);
server_status_window(w);
return (CMD_RETURN_NORMAL);
}
server_unzoom_window(w);
if (args->argc == 0)
adjust = 1;
else {
adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(cmdq, "adjustment %s", errstr);
return (CMD_RETURN_ERROR);
}
}
if (args_has(self->args, 'x')) {
x = args_strtonum(self->args, 'x', PANE_MINIMUM, INT_MAX,
&cause);
if (cause != NULL) {
cmdq_error(cmdq, "width %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
}
if (args_has(self->args, 'y')) {
y = args_strtonum(self->args, 'y', PANE_MINIMUM, INT_MAX,
&cause);
if (cause != NULL) {
cmdq_error(cmdq, "height %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
}
if (args_has(self->args, 'L'))
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust);
else if (args_has(self->args, 'R'))
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust);
else if (args_has(self->args, 'U'))
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, -adjust);
else if (args_has(self->args, 'D'))
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust);
server_redraw_window(wl->window);
return (CMD_RETURN_NORMAL);
}
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,97 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2011 Marcel P. Partap <mpartap@gmx.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 <unistd.h>
#include "tmux.h"
/*
* Respawn a pane (restart the command). Kill existing if -k given.
*/
enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_respawn_pane_entry = {
.name = "respawn-pane",
.alias = "respawnp",
.args = { "kt:", 0, -1 },
.usage = "[-k] " CMD_TARGET_PANE_USAGE " [command]",
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_respawn_pane_exec
};
enum cmd_retval
cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl = cmdq->state.tflag.wl;
struct window *w = wl->window;
struct window_pane *wp = cmdq->state.tflag.wp;
struct session *s = cmdq->state.tflag.s;
struct environ *env;
const char *path;
char *cause;
u_int idx;
struct environ_entry *envent;
if (!args_has(self->args, 'k') && wp->fd != -1) {
if (window_pane_index(wp, &idx) != 0)
fatalx("index not found");
cmdq_error(cmdq, "pane still active: %s:%d.%u",
s->name, wl->idx, idx);
return (CMD_RETURN_ERROR);
}
env = environ_create();
environ_copy(global_environ, env);
environ_copy(s->environ, env);
server_fill_environ(s, env);
window_pane_reset_mode(wp);
screen_reinit(&wp->base);
input_init(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(wp, args->argc, args->argv, path, NULL, NULL, env,
s->tio, &cause) != 0) {
cmdq_error(cmdq, "respawn pane failed: %s", cause);
free(cause);
environ_free(env);
return (CMD_RETURN_ERROR);
}
wp->flags |= PANE_REDRAW;
server_status_window(w);
environ_free(env);
return (CMD_RETURN_NORMAL);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-respawn-window.c,v 1.14 2009-03-04 17:24:07 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include "tmux.h"
@@ -27,81 +26,62 @@
* Respawn a window (restart the command). Kill existing if -k given.
*/
enum cmd_retval cmd_respawn_window_exec(struct cmd *, struct cmd_q *);
int cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_respawn_window_entry = {
.name = "respawn-window",
.alias = "respawnw",
.args = { "kt:", 0, -1 },
.usage = "[-k] " CMD_TARGET_WINDOW_USAGE " [command]",
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_respawn_window_exec
"respawn-window", "respawnw",
"[-k] " CMD_TARGET_WINDOW_USAGE " [command]",
CMD_ARG01|CMD_KFLAG,
cmd_target_init,
cmd_target_parse,
cmd_respawn_window_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
enum cmd_retval
cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl;
struct window *w = wl->window;
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct window *w;
struct window_pane *wp;
struct environ *env;
const char *path;
struct session *s;
const char **env;
char *cause;
struct environ_entry *envent;
if (!args_has(self->args, 'k')) {
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
w = wl->window;
if (!(data->flags & CMD_KFLAG)) {
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd == -1)
continue;
cmdq_error(cmdq, "window still active: %s:%d", s->name,
wl->idx);
return (CMD_RETURN_ERROR);
ctx->error(ctx,
"window still active: %s:%d", s->name, wl->idx);
return (-1);
}
}
env = environ_create();
environ_copy(global_environ, env);
environ_copy(s->environ, env);
server_fill_environ(s, env);
env = server_fill_environ(s);
wp = TAILQ_FIRST(&w->panes);
TAILQ_REMOVE(&w->panes, wp, entry);
layout_free(w);
window_destroy_panes(w);
window_destroy_panes(w);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
window_pane_resize(wp, w->sx, w->sy);
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(wp, args->argc, args->argv, path, NULL, NULL, env,
s->tio, &cause) != 0) {
cmdq_error(cmdq, "respawn window failed: %s", cause);
free(cause);
environ_free(env);
server_destroy_pane(wp, 0);
return (CMD_RETURN_ERROR);
if (window_pane_spawn(wp, data->arg, NULL, env, &cause) != 0) {
ctx->error(ctx, "respawn window failed: %s", cause);
xfree(cause);
return (-1);
}
layout_init(w, wp);
window_pane_reset_mode(wp);
screen_reinit(&wp->base);
input_init(wp);
window_set_active_pane(w, wp);
recalculate_sizes();
server_redraw_window(w);
environ_free(env);
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-rotate-window.c,v 1.2 2009-04-21 20:06:46 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -24,85 +24,88 @@
* Rotate the panes in a window.
*/
enum cmd_retval cmd_rotate_window_exec(struct cmd *, struct cmd_q *);
void cmd_rotate_window_init(struct cmd *, int);
int cmd_rotate_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_rotate_window_entry = {
.name = "rotate-window",
.alias = "rotatew",
.args = { "Dt:U", 0, 0 },
.usage = "[-DU] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_rotate_window_exec
"rotate-window", "rotatew",
"[-DU] " CMD_TARGET_WINDOW_USAGE,
CMD_UPPERUFLAG|CMD_UPPERDFLAG,
cmd_rotate_window_init,
cmd_target_parse,
cmd_rotate_window_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
enum cmd_retval
cmd_rotate_window_exec(struct cmd *self, struct cmd_q *cmdq)
void
cmd_rotate_window_init(struct cmd *self, int key)
{
struct winlink *wl = cmdq->state.tflag.wl;
struct window *w = wl->window;
struct cmd_target_data *data;
cmd_target_init(self, key);
data = self->data;
if (key == KEYC_ADDESC('o'))
data->flags |= CMD_UPPERDFLAG;
}
int
cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct window *w;
struct window_pane *wp, *wp2;
struct layout_cell *lc;
u_int sx, sy, xoff, yoff;
if (args_has(self->args, 'D')) {
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
w = wl->window;
if (data->flags & CMD_UPPERDFLAG) {
wp = TAILQ_LAST(&w->panes, window_panes);
TAILQ_REMOVE(&w->panes, wp, entry);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
lc = wp->layout_cell;
xoff = wp->xoff; yoff = wp->yoff;
sx = wp->sx; sy = wp->sy;
TAILQ_FOREACH(wp, &w->panes, entry) {
if ((wp2 = TAILQ_NEXT(wp, entry)) == NULL)
break;
wp->layout_cell = wp2->layout_cell;
if (wp->layout_cell != NULL)
wp->layout_cell->wp = wp;
wp->xoff = wp2->xoff; wp->yoff = wp2->yoff;
window_pane_resize(wp, wp2->sx, wp2->sy);
}
wp->layout_cell = lc;
if (wp->layout_cell != NULL)
wp->layout_cell->wp = wp;
wp->xoff = xoff; wp->yoff = yoff;
window_pane_resize(wp, sx, sy);
if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL)
wp = TAILQ_LAST(&w->panes, window_panes);
window_set_active_pane(w, wp);
server_redraw_window(w);
} else {
wp = TAILQ_FIRST(&w->panes);
TAILQ_REMOVE(&w->panes, wp, entry);
TAILQ_INSERT_TAIL(&w->panes, wp, entry);
lc = wp->layout_cell;
xoff = wp->xoff; yoff = wp->yoff;
sx = wp->sx; sy = wp->sy;
TAILQ_FOREACH_REVERSE(wp, &w->panes, window_panes, entry) {
if ((wp2 = TAILQ_PREV(wp, window_panes, entry)) == NULL)
break;
wp->layout_cell = wp2->layout_cell;
if (wp->layout_cell != NULL)
wp->layout_cell->wp = wp;
wp->xoff = wp2->xoff; wp->yoff = wp2->yoff;
window_pane_resize(wp, wp2->sx, wp2->sy);
}
wp->layout_cell = lc;
if (wp->layout_cell != NULL)
wp->layout_cell->wp = wp;
wp->xoff = xoff; wp->yoff = yoff;
window_pane_resize(wp, sx, sy);
if ((wp = TAILQ_NEXT(w->active, entry)) == NULL)
wp = TAILQ_FIRST(&w->panes);
window_set_active_pane(w, wp);
server_redraw_window(w);
}
return (CMD_RETURN_NORMAL);
layout_refresh(w, 0);
return (0);
}

View File

@@ -1,175 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
* Copyright (c) 2009 Nicholas Marriott <nicm@openbsd.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 <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Runs a command without a window.
*/
enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmd_q *);
void cmd_run_shell_callback(struct job *);
void cmd_run_shell_free(void *);
void cmd_run_shell_print(struct job *, const char *);
const struct cmd_entry cmd_run_shell_entry = {
.name = "run-shell",
.alias = "run",
.args = { "bt:", 1, 1 },
.usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
.tflag = CMD_PANE_CANFAIL,
.flags = 0,
.exec = cmd_run_shell_exec
};
struct cmd_run_shell_data {
char *cmd;
struct cmd_q *cmdq;
int bflag;
int wp_id;
};
void
cmd_run_shell_print(struct job *job, const char *msg)
{
struct cmd_run_shell_data *cdata = job->data;
struct window_pane *wp = NULL;
if (cdata->wp_id != -1)
wp = window_pane_find_by_id(cdata->wp_id);
if (wp == NULL) {
cmdq_print(cdata->cmdq, "%s", msg);
return;
}
if (window_pane_set_mode(wp, &window_copy_mode) == 0)
window_copy_init_for_output(wp);
if (wp->mode == &window_copy_mode)
window_copy_add(wp, "%s", msg);
}
enum cmd_retval
cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct cmd_run_shell_data *cdata;
char *shellcmd;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl;
struct window_pane *wp = cmdq->state.tflag.wp;
struct format_tree *ft;
const char *cwd;
if (cmdq->client != NULL && cmdq->client->session == NULL)
cwd = cmdq->client->cwd;
else if (s != NULL)
cwd = s->cwd;
else
cwd = NULL;
ft = format_create(cmdq, 0);
format_defaults(ft, cmdq->state.c, s, wl, wp);
shellcmd = format_expand(ft, args->argv[0]);
format_free(ft);
cdata = xmalloc(sizeof *cdata);
cdata->cmd = shellcmd;
cdata->bflag = args_has(args, 'b');
cdata->wp_id = wp != NULL ? (int) wp->id : -1;
cdata->cmdq = cmdq;
cmdq->references++;
job_run(shellcmd, s, cwd, cmd_run_shell_callback, cmd_run_shell_free,
cdata);
if (cdata->bflag)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
void
cmd_run_shell_callback(struct job *job)
{
struct cmd_run_shell_data *cdata = job->data;
struct cmd_q *cmdq = cdata->cmdq;
char *cmd, *msg, *line;
size_t size;
int retcode;
u_int lines;
if (cmdq->flags & CMD_Q_DEAD)
return;
cmd = cdata->cmd;
lines = 0;
do {
if ((line = evbuffer_readline(job->event->input)) != NULL) {
cmd_run_shell_print(job, line);
free(line);
lines++;
}
} while (line != NULL);
size = EVBUFFER_LENGTH(job->event->input);
if (size != 0) {
line = xmalloc(size + 1);
memcpy(line, EVBUFFER_DATA(job->event->input), size);
line[size] = '\0';
cmd_run_shell_print(job, line);
lines++;
free(line);
}
msg = NULL;
if (WIFEXITED(job->status)) {
if ((retcode = WEXITSTATUS(job->status)) != 0)
xasprintf(&msg, "'%s' returned %d", cmd, retcode);
} else if (WIFSIGNALED(job->status)) {
retcode = WTERMSIG(job->status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
}
if (msg != NULL)
cmd_run_shell_print(job, msg);
free(msg);
}
void
cmd_run_shell_free(void *data)
{
struct cmd_run_shell_data *cdata = data;
struct cmd_q *cmdq = cdata->cmdq;
if (!cmdq_free(cmdq) && !cdata->bflag)
cmdq_continue(cmdq);
free(cdata->cmd);
free(cdata);
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */
/* $Id: cmd-save-buffer.c,v 1.4 2009-02-08 13:36:40 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -20,149 +20,71 @@
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
/*
* Saves a paste buffer to a file.
* Saves a session paste buffer to a file.
*/
enum cmd_retval cmd_save_buffer_exec(struct cmd *, struct cmd_q *);
int cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_save_buffer_entry = {
.name = "save-buffer",
.alias = "saveb",
.args = { "ab:", 1, 1 },
.usage = "[-a] " CMD_BUFFER_USAGE " path",
.flags = 0,
.exec = cmd_save_buffer_exec
"save-buffer", "saveb",
"[-a] " CMD_BUFFER_SESSION_USAGE " path",
CMD_AFLAG|CMD_ARG1,
cmd_buffer_init,
cmd_buffer_parse,
cmd_save_buffer_exec,
cmd_buffer_send,
cmd_buffer_recv,
cmd_buffer_free,
cmd_buffer_print
};
const struct cmd_entry cmd_show_buffer_entry = {
.name = "show-buffer",
.alias = "showb",
.args = { "b:", 0, 0 },
.usage = CMD_BUFFER_USAGE,
.flags = 0,
.exec = cmd_save_buffer_exec
};
enum cmd_retval
cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c = cmdq->client;
struct session *s;
struct cmd_buffer_data *data = self->data;
struct session *s;
struct paste_buffer *pb;
const char *path, *bufname, *bufdata, *start, *end, *cwd;
const char *flags;
char *msg, *file, resolved[PATH_MAX];
size_t size, used, msglen, bufsize;
mode_t mask;
FILE *f;
if (!args_has(args, 'b')) {
if ((pb = paste_get_top(NULL)) == NULL) {
cmdq_error(cmdq, "no buffers");
return (CMD_RETURN_ERROR);
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (data->buffer == -1) {
if ((pb = paste_get_top(&s->buffers)) == NULL) {
ctx->error(ctx, "no buffers");
return (-1);
}
} else {
bufname = args_get(args, 'b');
pb = paste_get_name(bufname);
if (pb == NULL) {
cmdq_error(cmdq, "no buffer %s", bufname);
return (CMD_RETURN_ERROR);
if ((pb = paste_get_index(&s->buffers, data->buffer)) == NULL) {
ctx->error(ctx, "no buffer %d", data->buffer);
return (-1);
}
}
bufdata = paste_buffer_data(pb, &bufsize);
if (self->entry == &cmd_show_buffer_entry)
path = "-";
mask = umask(S_IRWXG | S_IRWXO);
if (data->flags & CMD_AFLAG)
f = fopen(data->arg, "a");
else
path = args->argv[0];
if (strcmp(path, "-") == 0) {
if (c == NULL) {
cmdq_error(cmdq, "can't write to stdout");
return (CMD_RETURN_ERROR);
}
if (c->session == NULL || (c->flags & CLIENT_CONTROL))
goto do_stdout;
goto do_print;
}
if (c != NULL && c->session == NULL && c->cwd != NULL)
cwd = c->cwd;
else if ((s = c->session) != NULL && s->cwd != NULL)
cwd = s->cwd;
else
cwd = ".";
flags = "wb";
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);
}
f = fopen(resolved, flags);
free(file);
f = fopen(data->arg, "w");
if (f == NULL) {
cmdq_error(cmdq, "%s: %s", resolved, strerror(errno));
return (CMD_RETURN_ERROR);
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1);
}
if (fwrite(bufdata, 1, bufsize, f) != bufsize) {
cmdq_error(cmdq, "%s: write error", resolved);
fclose(f);
return (CMD_RETURN_ERROR);
if (fwrite(pb->data, 1, strlen(pb->data), f) != strlen(pb->data)) {
ctx->error(ctx, "%s: fwrite error", data->arg);
fclose(f);
return (-1);
}
fclose(f);
umask(mask);
return (CMD_RETURN_NORMAL);
do_stdout:
evbuffer_add(c->stdout_data, bufdata, bufsize);
server_client_push_stdout(c);
return (CMD_RETURN_NORMAL);
do_print:
if (bufsize > (INT_MAX / 4) - 1) {
cmdq_error(cmdq, "buffer too big");
return (CMD_RETURN_ERROR);
}
msg = NULL;
used = 0;
while (used != bufsize) {
start = bufdata + used;
end = memchr(start, '\n', bufsize - used);
if (end != NULL)
size = end - start;
else
size = bufsize - used;
msglen = size * 4 + 1;
msg = xrealloc(msg, msglen);
strvisx(msg, start, size, VIS_OCTAL|VIS_TAB);
cmdq_print(cmdq, "%s", msg);
used += size + (end != NULL);
}
free(msg);
return (CMD_RETURN_NORMAL);
return (0);
}

72
cmd-scroll-mode.c Normal file
View File

@@ -0,0 +1,72 @@
/* $Id: cmd-scroll-mode.c,v 1.16 2009-01-27 23:35:44 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Enter scroll mode.
*/
void cmd_scroll_mode_init(struct cmd *, int);
int cmd_scroll_mode_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_scroll_mode_entry = {
"scroll-mode", NULL,
CMD_TARGET_WINDOW_USAGE,
CMD_UFLAG,
cmd_scroll_mode_init,
cmd_target_parse,
cmd_scroll_mode_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
void
cmd_scroll_mode_init(struct cmd *self, int key)
{
struct cmd_target_data *data;
cmd_target_init(self, key);
data = self->data;
switch (key) {
case KEYC_PPAGE:
data->flags |= CMD_UFLAG;
break;
}
}
int
cmd_scroll_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
window_pane_set_mode(wl->window->active, &window_scroll_mode);
if (data->flags & CMD_UFLAG)
window_scroll_pageup(wl->window->active);
return (0);
}

View File

@@ -1,139 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Switch window to selected layout.
*/
enum cmd_retval cmd_select_layout_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_select_layout_entry = {
.name = "select-layout",
.alias = "selectl",
.args = { "nopt:", 0, 1 },
.usage = "[-nop] " CMD_TARGET_WINDOW_USAGE " [layout-name]",
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_select_layout_exec
};
const struct cmd_entry cmd_next_layout_entry = {
.name = "next-layout",
.alias = "nextl",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_select_layout_exec
};
const struct cmd_entry cmd_previous_layout_entry = {
.name = "previous-layout",
.alias = "prevl",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_select_layout_exec
};
enum cmd_retval
cmd_select_layout_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl = cmdq->state.tflag.wl;
struct window *w;
const char *layoutname;
char *oldlayout;
int next, previous, layout;
w = wl->window;
server_unzoom_window(w);
next = self->entry == &cmd_next_layout_entry;
if (args_has(args, 'n'))
next = 1;
previous = self->entry == &cmd_previous_layout_entry;
if (args_has(args, 'p'))
previous = 1;
oldlayout = w->old_layout;
w->old_layout = layout_dump(w->layout_root);
if (next || previous) {
if (next)
layout_set_next(w);
else
layout_set_previous(w);
goto changed;
}
if (!args_has(args, 'o')) {
if (args->argc == 0)
layout = w->lastlayout;
else
layout = layout_set_lookup(args->argv[0]);
if (layout != -1) {
layout_set_select(w, layout);
goto changed;
}
}
if (args->argc != 0)
layoutname = args->argv[0];
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);
goto error;
}
goto changed;
}
free(oldlayout);
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);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-select-pane.c,v 1.4 2009-04-01 21:10:08 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -24,141 +24,46 @@
* Select pane.
*/
enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmd_q *);
int cmd_select_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_select_pane_entry = {
.name = "select-pane",
.alias = "selectp",
.args = { "DdegLlMmP:Rt:U", 0, 0 },
.usage = "[-DdegLlMmRU] [-P style] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_select_pane_exec
"select-pane", "selectp",
CMD_PANE_WINDOW_USAGE,
0,
cmd_pane_init,
cmd_pane_parse,
cmd_select_pane_exec,
cmd_pane_send,
cmd_pane_recv,
cmd_pane_free,
cmd_pane_print
};
const struct cmd_entry cmd_last_pane_entry = {
.name = "last-pane",
.alias = "lastp",
.args = { "det:", 0, 0 },
.usage = "[-de] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_select_pane_exec
};
enum cmd_retval
cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct winlink *wl = cmdq->state.tflag.wl;
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;
struct cmd_pane_data *data = self->data;
struct winlink *wl;
struct window_pane *wp;
if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
if (wl->window->last == NULL) {
cmdq_error(cmdq, "no last pane");
return (CMD_RETURN_ERROR);
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (data->pane == -1)
wp = wl->window->active;
else {
wp = window_pane_at_index(wl->window, data->pane);
if (wp == NULL) {
ctx->error(ctx, "no pane: %d", data->pane);
return (-1);
}
if (args_has(self->args, 'e'))
w->last->flags &= ~PANE_INPUTOFF;
else if (args_has(self->args, 'd'))
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);
}
if (args_has(args, 'm') || args_has(args, 'M')) {
if (args_has(args, 'm') && !window_pane_visible(wp))
return (CMD_RETURN_NORMAL);
lastwp = marked_pane.wp;
if (args_has(args, 'M') || server_is_marked(s, wl, wp))
server_clear_marked();
else
server_set_marked(s, wl, wp);
markedwp = marked_pane.wp;
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);
if (wp->flags & PANE_HIDDEN) {
ctx->error(ctx, "pane %d is hidden", data->pane);
return (-1);
}
window_set_active_pane(wl->window, wp);
layout_refresh(wl->window, 1);
if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
if (args_has(args, 'P')) {
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 (0);
}

93
cmd-select-prompt.c Normal file
View File

@@ -0,0 +1,93 @@
/* $Id: cmd-select-prompt.c,v 1.7 2009-02-13 18:57:55 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Prompt for window index and select it.
*/
int cmd_select_prompt_exec(struct cmd *, struct cmd_ctx *);
int cmd_select_prompt_callback(void *, const char *);
const struct cmd_entry cmd_select_prompt_entry = {
"select-prompt", NULL,
CMD_TARGET_CLIENT_USAGE,
0,
cmd_target_init,
cmd_target_parse,
cmd_select_prompt_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
int
cmd_select_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct client *c;
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
if (c->prompt_string != NULL)
return (0);
status_prompt_set(c, "index ", cmd_select_prompt_callback, c, 0);
return (0);
}
int
cmd_select_prompt_callback(void *data, const char *s)
{
struct client *c = data;
const char *errstr;
char msg[128];
u_int idx;
if (s == NULL)
return (0);
idx = strtonum(s, 0, UINT_MAX, &errstr);
if (errstr != NULL) {
xsnprintf(msg, sizeof msg, "Index %s: %s", errstr, s);
status_message_set(c, msg);
return (0);
}
if (winlink_find_by_index(&c->session->windows, idx) == NULL) {
xsnprintf(msg, sizeof msg,
"Window not found: %s:%d", c->session->name, idx);
status_message_set(c, msg);
return (0);
}
if (session_select(c->session, idx) == 0)
server_redraw_session(c->session);
recalculate_sizes();
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-select-window.c,v 1.21 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -26,112 +26,46 @@
* Select window by index.
*/
enum cmd_retval cmd_select_window_exec(struct cmd *, struct cmd_q *);
void cmd_select_window_init(struct cmd *, int);
int cmd_select_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_select_window_entry = {
.name = "select-window",
.alias = "selectw",
.args = { "lnpTt:", 0, 0 },
.usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_select_window_exec
"select-window", "selectw",
CMD_TARGET_WINDOW_USAGE,
0,
cmd_select_window_init,
cmd_target_parse,
cmd_select_window_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
const struct cmd_entry cmd_next_window_entry = {
.name = "next-window",
.alias = "next",
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_select_window_exec
};
const struct cmd_entry cmd_previous_window_entry = {
.name = "previous-window",
.alias = "prev",
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_select_window_exec
};
const struct cmd_entry cmd_last_window_entry = {
.name = "last-window",
.alias = "last",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE,
.tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_select_window_exec
};
enum cmd_retval
cmd_select_window_exec(struct cmd *self, struct cmd_q *cmdq)
void
cmd_select_window_init(struct cmd *self, int key)
{
struct winlink *wl = cmdq->state.tflag.wl;
struct session *s = cmdq->state.tflag.s;
int next, previous, last, activity;
struct cmd_target_data *data;
next = self->entry == &cmd_next_window_entry;
if (args_has(self->args, 'n'))
next = 1;
previous = self->entry == &cmd_previous_window_entry;
if (args_has(self->args, 'p'))
previous = 1;
last = self->entry == &cmd_last_window_entry;
if (args_has(self->args, 'l'))
last = 1;
cmd_target_init(self, key);
data = self->data;
if (next || previous || last) {
activity = args_has(self->args, 'a');
if (next) {
if (session_next(s, activity) != 0) {
cmdq_error(cmdq, "no next window");
return (CMD_RETURN_ERROR);
}
} else if (previous) {
if (session_previous(s, activity) != 0) {
cmdq_error(cmdq, "no previous window");
return (CMD_RETURN_ERROR);
}
} else {
if (session_last(s) != 0) {
cmdq_error(cmdq, "no last window");
return (CMD_RETURN_ERROR);
}
}
xasprintf(&data->target, ":%d", key - '0');
}
int
cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct session *s;
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
if (session_select(s, wl->idx) == 0)
server_redraw_session(s);
} else {
/*
* If -T and select-window is invoked on same window as
* current, switch to previous window.
*/
if (args_has(self->args, 'T') && wl == s->curw) {
if (session_last(s) != 0) {
cmdq_error(cmdq, "no last window");
return (-1);
}
server_redraw_session(s);
} else if (session_select(s, wl->idx) == 0)
server_redraw_session(s);
}
recalculate_sizes();
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-send-keys.c,v 1.18 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -19,7 +19,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -27,81 +26,159 @@
* Send keys to client.
*/
enum cmd_retval cmd_send_keys_exec(struct cmd *, struct cmd_q *);
int cmd_send_keys_parse(struct cmd *, int, char **, char **);
int cmd_send_keys_exec(struct cmd *, struct cmd_ctx *);
void cmd_send_keys_send(struct cmd *, struct buffer *);
void cmd_send_keys_recv(struct cmd *, struct buffer *);
void cmd_send_keys_free(struct cmd *);
size_t cmd_send_keys_print(struct cmd *, char *, size_t);
struct cmd_send_keys_data {
char *target;
int idx;
u_int nkeys;
int *keys;
};
const struct cmd_entry cmd_send_keys_entry = {
.name = "send-keys",
.alias = "send",
.args = { "lRMt:", 0, -1 },
.usage = "[-lRM] " CMD_TARGET_PANE_USAGE " key ...",
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_send_keys_exec
"send-keys", "send",
"[-t target-window] key ...",
0,
NULL,
cmd_send_keys_parse,
cmd_send_keys_exec,
cmd_send_keys_send,
cmd_send_keys_recv,
cmd_send_keys_free,
cmd_send_keys_print
};
const struct cmd_entry cmd_send_prefix_entry = {
.name = "send-prefix",
.alias = NULL,
.args = { "2t:", 0, 0 },
.usage = "[-2] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_send_keys_exec
};
enum cmd_retval
cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_send_keys_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct args *args = self->args;
struct window_pane *wp = cmdq->state.tflag.wp;
struct session *s = cmdq->state.tflag.s;
struct mouse_event *m = &cmdq->item->mouse;
const u_char *keystr;
int i, literal;
key_code key;
struct cmd_send_keys_data *data;
int opt, key;
char *s;
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);
}
window_pane_key(wp, NULL, s, m->key, m);
return (CMD_RETURN_NORMAL);
}
self->data = data = xmalloc(sizeof *data);
data->target = NULL;
data->idx = -1;
data->nkeys = 0;
data->keys = NULL;
if (self->entry == &cmd_send_prefix_entry) {
if (args_has(args, '2'))
key = options_get_number(s->options, "prefix2");
else
key = options_get_number(s->options, "prefix");
window_pane_key(wp, NULL, s, key, NULL);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'R'))
input_reset(wp, 1);
for (i = 0; i < args->argc; i++) {
literal = args_has(args, 'l');
if (!literal) {
key = key_string_lookup_string(args->argv[i]);
if (key != KEYC_NONE && key != KEYC_UNKNOWN)
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);
while ((opt = getopt(argc, argv, "t:")) != -1) {
switch (opt) {
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (argc == 0)
goto usage;
return (CMD_RETURN_NORMAL);
while (argc-- != 0) {
if ((key = key_string_lookup_string(*argv)) != KEYC_NONE) {
data->keys = xrealloc(
data->keys, data->nkeys + 1, sizeof *data->keys);
data->keys[data->nkeys++] = key;
} else {
for (s = *argv; *s != '\0'; s++) {
data->keys = xrealloc(data->keys,
data->nkeys + 1, sizeof *data->keys);
data->keys[data->nkeys++] = *s;
}
}
argv++;
}
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
int
cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_send_keys_data *data = self->data;
struct winlink *wl;
u_int i;
if (data == NULL)
return (-1);
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
for (i = 0; i < data->nkeys; i++) {
window_pane_key(
wl->window->active, ctx->curclient, data->keys[i]);
}
return (0);
}
void
cmd_send_keys_send(struct cmd *self, struct buffer *b)
{
struct cmd_send_keys_data *data = self->data;
buffer_write(b, data, sizeof *data);
cmd_send_string(b, data->target);
buffer_write(b, data->keys, data->nkeys * sizeof *data->keys);
}
void
cmd_send_keys_recv(struct cmd *self, struct buffer *b)
{
struct cmd_send_keys_data *data;
self->data = data = xmalloc(sizeof *data);
buffer_read(b, data, sizeof *data);
data->target = cmd_recv_string(b);
data->keys = xcalloc(data->nkeys, sizeof *data->keys);
buffer_read(b, data->keys, data->nkeys * sizeof *data->keys);
}
void
cmd_send_keys_free(struct cmd *self)
{
struct cmd_send_keys_data *data = self->data;
if (data->target != NULL)
xfree(data->target);
xfree(data);
}
size_t
cmd_send_keys_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_send_keys_data *data = self->data;
size_t off = 0;
u_int i;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
if (off < len && data->idx != -1)
off += xsnprintf(buf + off, len - off, " -i %d", data->idx);
for (i = 0; i < data->nkeys; i++) {
if (off >= len)
break;
off += xsnprintf(buf + off,
len - off, " %s", key_string_lookup_key(data->keys[i]));
}
return (off);
}

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

@@ -0,0 +1,57 @@
/* $Id: cmd-send-prefix.c,v 1.23 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Send prefix key as a key.
*/
int cmd_send_prefix_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_send_prefix_entry = {
"send-prefix", NULL,
CMD_TARGET_WINDOW_USAGE,
0,
cmd_target_init,
cmd_target_parse,
cmd_send_prefix_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
int
cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct session *s;
struct winlink *wl;
int key;
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
key = options_get_number(&s->options, "prefix");
window_pane_key(wl->window->active, ctx->curclient, key);
return (0);
}

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

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

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-set-buffer.c,v 1.7 2009-01-25 18:51:28 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -19,105 +19,46 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Add, set, append to or delete a paste buffer.
* Add or set a session paste buffer.
*/
enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmd_q *);
int cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_set_buffer_entry = {
.name = "set-buffer",
.alias = "setb",
.args = { "ab:n:", 0, 1 },
.usage = "[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data",
.flags = 0,
.exec = cmd_set_buffer_exec
"set-buffer", "setb",
CMD_BUFFER_SESSION_USAGE " data",
CMD_ARG1,
cmd_buffer_init,
cmd_buffer_parse,
cmd_set_buffer_exec,
cmd_buffer_send,
cmd_buffer_recv,
cmd_buffer_free,
cmd_buffer_print
};
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
cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct paste_buffer *pb;
char *bufdata, *cause;
const char *bufname, *olddata;
size_t bufsize, newsize;
struct cmd_buffer_data *data = self->data;
struct session *s;
u_int limit;
bufname = args_get(args, 'b');
if (bufname == NULL)
pb = NULL;
else
pb = paste_get_name(bufname);
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (self->entry == &cmd_delete_buffer_entry) {
if (pb == NULL)
pb = paste_get_top(&bufname);
if (pb == NULL) {
cmdq_error(cmdq, "no buffer");
return (CMD_RETURN_ERROR);
}
paste_free(pb);
return (CMD_RETURN_NORMAL);
limit = options_get_number(&s->options, "buffer-limit");
if (data->buffer == -1) {
paste_add(&s->buffers, xstrdup(data->arg), limit);
return (0);
}
if (args_has(args, 'n')) {
if (pb == NULL)
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);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
if (paste_replace(&s->buffers, data->buffer, xstrdup(data->arg)) != 0) {
ctx->error(ctx, "no buffer %d", data->buffer);
return (-1);
}
if (args->argc != 1) {
cmdq_error(cmdq, "no data specified");
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_NORMAL);
return (0);
}

View File

@@ -1,102 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Set an environment variable.
*/
enum cmd_retval cmd_set_environment_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_set_environment_entry = {
.name = "set-environment",
.alias = "setenv",
.args = { "grt:u", 1, 2 },
.usage = "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
.tflag = CMD_SESSION_CANFAIL,
.flags = 0,
.exec = cmd_set_environment_exec
};
enum cmd_retval
cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct environ *env;
const char *name, *value, *target;
name = args->argv[0];
if (*name == '\0') {
cmdq_error(cmdq, "empty variable name");
return (CMD_RETURN_ERROR);
}
if (strchr(name, '=') != NULL) {
cmdq_error(cmdq, "variable name contains =");
return (CMD_RETURN_ERROR);
}
if (args->argc < 2)
value = NULL;
else
value = args->argv[1];
if (args_has(self->args, 'g'))
env = global_environ;
else {
if (cmdq->state.tflag.s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(cmdq, "no such session: %s", target);
else
cmdq_error(cmdq, "no current session");
return (CMD_RETURN_ERROR);
}
env = cmdq->state.tflag.s->environ;
}
if (args_has(self->args, 'u')) {
if (value != NULL) {
cmdq_error(cmdq, "can't specify a value with -u");
return (CMD_RETURN_ERROR);
}
environ_unset(env, name);
} else if (args_has(self->args, 'r')) {
if (value != NULL) {
cmdq_error(cmdq, "can't specify a value with -r");
return (CMD_RETURN_ERROR);
}
environ_clear(env, name);
} else {
if (value == NULL) {
cmdq_error(cmdq, "no value specified");
return (CMD_RETURN_ERROR);
}
environ_set(env, name, "%s", value);
}
return (CMD_RETURN_NORMAL);
}

View File

@@ -1,129 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Set or show global or session hooks.
*/
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_CANFAIL,
.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, *target;
if (args_has(args, 'g'))
hooks = global_hooks;
else {
if (cmdq->state.tflag.s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(cmdq, "no such session: %s", target);
else
cmdq_error(cmdq, "no current session");
return (CMD_RETURN_ERROR);
}
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,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-set-option.c,v 1.60 2009-03-21 12:44:06 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* 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
@@ -27,515 +27,143 @@
* Set an option.
*/
enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmd_q *);
enum cmd_retval cmd_set_option_user(struct cmd *, struct cmd_q *,
const char *, const char *);
int cmd_set_option_unset(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
int cmd_set_option_set(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_string(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_number(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_key(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_colour(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_attributes(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_flag(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_style(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
int cmd_set_option_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_set_option_entry = {
.name = "set-option",
.alias = "set",
.args = { "agoqst:uw", 1, 2 },
.usage = "[-agosquw] [-t target-window] option [value]",
.tflag = CMD_WINDOW_CANFAIL,
.flags = 0,
.exec = cmd_set_option_exec
"set-option", "set",
CMD_OPTION_SESSION_USAGE,
CMD_GFLAG|CMD_UFLAG,
NULL,
cmd_option_parse,
cmd_set_option_exec,
cmd_option_send,
cmd_option_recv,
cmd_option_free,
cmd_option_print
};
const struct cmd_entry cmd_set_window_option_entry = {
.name = "set-window-option",
.alias = "setw",
.args = { "agoqt:u", 1, 2 },
.usage = "[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
.tflag = CMD_WINDOW_CANFAIL,
.flags = 0,
.exec = cmd_set_option_exec
const char *set_option_status_keys_list[] = {
"emacs", "vi", NULL
};
const char *set_option_bell_action_list[] = {
"none", "any", "current", NULL
};
const struct set_option_entry set_option_table[NSETOPTION] = {
{ "bell-action", SET_OPTION_CHOICE, 0, 0, set_option_bell_action_list },
{ "buffer-limit", SET_OPTION_NUMBER, 1, INT_MAX, NULL },
{ "default-command", SET_OPTION_STRING, 0, 0, NULL },
{ "default-path", SET_OPTION_STRING, 0, 0, NULL },
{ "display-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL },
{ "history-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "lock-after-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "message-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "message-bg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "message-fg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "prefix", SET_OPTION_KEY, 0, 0, NULL },
{ "repeat-time", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL },
{ "set-remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL },
{ "set-titles", SET_OPTION_FLAG, 0, 0, NULL },
{ "status", SET_OPTION_FLAG, 0, 0, NULL },
{ "status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "status-bg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "status-fg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "status-interval", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "status-keys", SET_OPTION_CHOICE, 0, 0, set_option_status_keys_list },
{ "status-left", SET_OPTION_STRING, 0, 0, NULL },
{ "status-left-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL },
{ "status-right", SET_OPTION_STRING, 0, 0, NULL },
{ "status-right-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL },
};
enum cmd_retval
cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq)
int
cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl;
struct window *w;
struct client *c;
const struct options_table_entry *oe;
struct options *oo;
const char *optstr, *valstr, *target;
struct cmd_option_data *data = self->data;
struct session *s;
struct client *c;
struct options *oo;
const struct set_option_entry *entry;
u_int i;
/* Get the option name and value. */
optstr = args->argv[0];
if (*optstr == '\0') {
cmdq_error(cmdq, "invalid option");
return (CMD_RETURN_ERROR);
if (data->flags & CMD_GFLAG)
oo = &global_options;
else {
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
oo = &s->options;
}
if (args->argc < 2)
valstr = NULL;
else
valstr = args->argv[1];
/* Is this a user option? */
if (*optstr == '@')
return (cmd_set_option_user(self, cmdq, optstr, valstr));
if (*data->option == '\0') {
ctx->error(ctx, "invalid option");
return (-1);
}
/* Find the option entry, try each table. */
oe = NULL;
if (options_table_find(optstr, &oe) != 0) {
if (!args_has(args, 'q')) {
cmdq_error(cmdq, "ambiguous option: %s", optstr);
return (CMD_RETURN_ERROR);
entry = NULL;
for (i = 0; i < NSETOPTION; i++) {
if (strncmp(set_option_table[i].name,
data->option, strlen(data->option)) != 0)
continue;
if (entry != NULL) {
ctx->error(ctx, "ambiguous option: %s", data->option);
return (-1);
}
return (CMD_RETURN_NORMAL);
entry = &set_option_table[i];
/* Bail now if an exact match. */
if (strcmp(entry->name, data->option) == 0)
break;
}
if (oe == NULL) {
if (!args_has(args, 'q')) {
cmdq_error(cmdq, "unknown option: %s", optstr);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
if (entry == NULL) {
ctx->error(ctx, "unknown option: %s", data->option);
return (-1);
}
/* 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'))
oo = global_w_options;
else if (wl == NULL) {
target = args_get(args, 't');
if (target != NULL) {
cmdq_error(cmdq, "no such window: %s",
target);
} else
cmdq_error(cmdq, "no current window");
return (CMD_RETURN_ERROR);
} else
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) {
target = args_get(args, 't');
if (target != NULL) {
cmdq_error(cmdq, "no such session: %s",
target);
} else
cmdq_error(cmdq, "no current session");
return (CMD_RETURN_ERROR);
} else
oo = s->options;
if (data->flags & CMD_UFLAG) {
if (data->flags & CMD_GFLAG) {
ctx->error(ctx,
"can't unset global option: %s", entry->name);
return (-1);
}
if (data->value != NULL) {
ctx->error(ctx,
"value passed to unset option: %s", entry->name);
return (-1);
}
options_remove(oo, entry->name);
ctx->info(ctx, "unset option: %s", entry->name);
} else {
cmdq_error(cmdq, "unknown table");
return (CMD_RETURN_ERROR);
}
/* Unset or set the option. */
if (args_has(args, 'u')) {
if (cmd_set_option_unset(self, cmdq, oe, oo, valstr) != 0)
return (CMD_RETURN_ERROR);
} else {
if (args_has(args, 'o') && options_find1(oo, optstr) != NULL) {
if (!args_has(args, 'q')) {
cmdq_error(cmdq, "already set: %s", optstr);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
if (cmd_set_option_set(self, cmdq, oe, oo, valstr) != 0)
return (CMD_RETURN_ERROR);
}
/* Start or stop timers if necessary. */
if (strcmp(oe->name, "automatic-rename") == 0) {
RB_FOREACH(w, windows, &windows) {
if (options_get_number(w->options, "automatic-rename"))
w->active->flags |= PANE_CHANGED;
switch (entry->type) {
case SET_OPTION_STRING:
set_option_string(ctx, oo, entry, data->value);
break;
case SET_OPTION_NUMBER:
set_option_number(ctx, oo, entry, data->value);
break;
case SET_OPTION_KEY:
set_option_key(ctx, oo, entry, data->value);
break;
case SET_OPTION_COLOUR:
set_option_colour(ctx, oo, entry, data->value);
break;
case SET_OPTION_ATTRIBUTES:
set_option_attributes(ctx, oo, entry, data->value);
break;
case SET_OPTION_FLAG:
set_option_flag(ctx, oo, entry, data->value);
break;
case SET_OPTION_CHOICE:
set_option_choice(ctx, oo, entry, data->value);
break;
}
}
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();
if (strcmp(oe->name, "window-style") == 0 ||
strcmp(oe->name, "window-active-style") == 0) {
RB_FOREACH(w, windows, &windows)
w->flags |= WINDOW_STYLECHANGED;
}
/* When the pane-border-status option has been changed, resize panes. */
if (strcmp(oe->name, "pane-border-status") == 0) {
RB_FOREACH(w, windows, &windows)
layout_fix_panes(w, w->sx, w->sy);
}
/* Update sizes and redraw. May not need it but meh. */
recalculate_sizes();
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != NULL)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c != NULL && c->session != NULL)
server_redraw_client(c);
}
return (CMD_RETURN_NORMAL);
}
/* Set user option. */
enum cmd_retval
cmd_set_option_user(struct cmd *self, struct cmd_q *cmdq, const char *optstr,
const char *valstr)
{
struct args *args = self->args;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl;
struct options *oo;
struct options_entry *o;
if (args_has(args, 's'))
oo = global_options;
else if (args_has(self->args, 'w') ||
self->entry == &cmd_set_window_option_entry) {
if (args_has(self->args, 'g'))
oo = global_w_options;
else
oo = wl->window->options;
} else {
if (args_has(self->args, 'g'))
oo = global_s_options;
else
oo = s->options;
}
if (args_has(args, 'u')) {
if (options_find1(oo, optstr) == NULL) {
if (!args_has(args, 'q')) {
cmdq_error(cmdq, "unknown option: %s", optstr);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
if (valstr != NULL) {
cmdq_error(cmdq, "value passed to unset option: %s",
optstr);
return (CMD_RETURN_ERROR);
}
options_remove(oo, optstr);
} else {
o = options_find1(oo, optstr);
if (args_has(args, 'o') && o != NULL) {
if (!args_has(args, 'q')) {
cmdq_error(cmdq, "already set: %s", optstr);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
if (valstr == NULL) {
cmdq_error(cmdq, "empty value");
return (CMD_RETURN_ERROR);
}
if (o != NULL && args_has(args, 'a'))
options_set_string(oo, optstr, "%s%s", o->str, valstr);
else
options_set_string(oo, optstr, "%s", valstr);
}
return (CMD_RETURN_NORMAL);
}
/* Unset an option. */
int
cmd_set_option_unset(struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
struct args *args = self->args;
if (value != NULL) {
cmdq_error(cmdq, "value passed to unset option: %s", oe->name);
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);
return (0);
}
/* Set an option. */
int
cmd_set_option_set(struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
struct options_entry *o;
switch (oe->type) {
case OPTIONS_TABLE_FLAG:
case OPTIONS_TABLE_CHOICE:
break;
default:
if (value == NULL) {
cmdq_error(cmdq, "empty value");
return (-1);
}
}
o = NULL;
switch (oe->type) {
case OPTIONS_TABLE_STRING:
o = cmd_set_option_string(self, cmdq, oe, oo, value);
break;
case OPTIONS_TABLE_NUMBER:
o = cmd_set_option_number(self, cmdq, oe, oo, value);
break;
case OPTIONS_TABLE_KEY:
o = cmd_set_option_key(self, cmdq, oe, oo, value);
break;
case OPTIONS_TABLE_COLOUR:
o = cmd_set_option_colour(self, cmdq, oe, oo, value);
if (o != NULL)
style_update_new(oo, o->name, oe->style);
break;
case OPTIONS_TABLE_ATTRIBUTES:
o = cmd_set_option_attributes(self, cmdq, oe, oo, value);
if (o != NULL)
style_update_new(oo, o->name, oe->style);
break;
case OPTIONS_TABLE_FLAG:
o = cmd_set_option_flag(self, cmdq, oe, oo, value);
break;
case OPTIONS_TABLE_CHOICE:
o = cmd_set_option_choice(self, cmdq, oe, oo, value);
break;
case OPTIONS_TABLE_STYLE:
o = cmd_set_option_style(self, cmdq, oe, oo, value);
break;
}
if (o == NULL)
return (-1);
return (0);
}
/* Set a string option. */
struct options_entry *
cmd_set_option_string(struct cmd *self, __unused 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;
char *oldval, *newval;
if (args_has(args, 'a')) {
oldval = options_get_string(oo, oe->name);
xasprintf(&newval, "%s%s", oldval, value);
} else
newval = xstrdup(value);
o = options_set_string(oo, oe->name, "%s", newval);
free(newval);
return (o);
}
/* Set a number option. */
struct options_entry *
cmd_set_option_number(__unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
long long ll;
const char *errstr;
ll = strtonum(value, oe->minimum, oe->maximum, &errstr);
if (errstr != NULL) {
cmdq_error(cmdq, "value is %s: %s", errstr, value);
return (NULL);
}
return (options_set_number(oo, oe->name, ll));
}
/* Set a key option. */
struct options_entry *
cmd_set_option_key(__unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
key_code key;
key = key_string_lookup_string(value);
if (key == KEYC_UNKNOWN) {
cmdq_error(cmdq, "bad key: %s", value);
return (NULL);
}
return (options_set_number(oo, oe->name, key));
}
/* Set a colour option. */
struct options_entry *
cmd_set_option_colour(__unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
int colour;
if ((colour = colour_fromstring(value)) == -1) {
cmdq_error(cmdq, "bad colour: %s", value);
return (NULL);
}
return (options_set_number(oo, oe->name, colour));
}
/* Set an attributes option. */
struct options_entry *
cmd_set_option_attributes(__unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
int attr;
if ((attr = attributes_fromstring(value)) == -1) {
cmdq_error(cmdq, "bad attributes: %s", value);
return (NULL);
}
return (options_set_number(oo, oe->name, attr));
}
/* Set a flag option. */
struct options_entry *
cmd_set_option_flag(__unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
int flag;
if (value == NULL || *value == '\0')
flag = !options_get_number(oo, oe->name);
else {
if ((value[0] == '1' && value[1] == '\0') ||
strcasecmp(value, "on") == 0 ||
strcasecmp(value, "yes") == 0)
flag = 1;
else if ((value[0] == '0' && value[1] == '\0') ||
strcasecmp(value, "off") == 0 ||
strcasecmp(value, "no") == 0)
flag = 0;
else {
cmdq_error(cmdq, "bad value: %s", value);
return (NULL);
}
}
return (options_set_number(oo, oe->name, flag));
}
/* Set a choice option. */
struct options_entry *
cmd_set_option_choice(__unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
const char **choicep;
int n, choice = -1;
if (value == NULL) {
choice = options_get_number(oo, oe->name);
if (choice < 2)
choice = !choice;
} else {
n = 0;
for (choicep = oe->choices; *choicep != NULL; choicep++) {
n++;
if (strncmp(*choicep, value, strlen(value)) != 0)
continue;
if (choice != -1) {
cmdq_error(cmdq, "ambiguous value: %s", value);
return (NULL);
}
choice = n - 1;
}
if (choice == -1) {
cmdq_error(cmdq, "unknown value: %s", value);
return (NULL);
}
}
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);
}

169
cmd-set-password.c Normal file
View File

@@ -0,0 +1,169 @@
/* $Id: cmd-set-password.c,v 1.3 2009-01-19 18:23:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>
#include "tmux.h"
/*
* Set server password.
*/
int cmd_set_password_parse(struct cmd *, int, char **, char **);
int cmd_set_password_exec(struct cmd *, struct cmd_ctx *);
void cmd_set_password_send(struct cmd *, struct buffer *);
void cmd_set_password_recv(struct cmd *, struct buffer *);
void cmd_set_password_free(struct cmd *);
void cmd_set_password_init(struct cmd *, int);
size_t cmd_set_password_print(struct cmd *, char *, size_t);
struct cmd_set_password_data {
char *password;
int flag_encrypted;
};
const struct cmd_entry cmd_set_password_entry = {
"set-password", "pass",
"[-c] password",
0,
cmd_set_password_init,
cmd_set_password_parse,
cmd_set_password_exec,
cmd_set_password_send,
cmd_set_password_recv,
cmd_set_password_free,
cmd_set_password_print
};
void
cmd_set_password_init(struct cmd *self, unused int arg)
{
struct cmd_set_password_data *data;
self->data = data = xmalloc(sizeof *data);
data->password = NULL;
data->flag_encrypted = 0;
}
int
cmd_set_password_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_set_password_data *data;
int opt;
char *out;
self->entry->init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "c")) != -1) {
switch (opt) {
case 'c':
data->flag_encrypted = 1;
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (argc != 1)
goto usage;
if (!data->flag_encrypted) {
if ((out = crypt(argv[0], "$1")) != NULL)
data->password = xstrdup(out);
} else
data->password = xstrdup(argv[0]);
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
int
cmd_set_password_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_set_password_data *data = self->data;
if (data->password == NULL) {
ctx->error(ctx, "failed to encrypt password");
return (-1);
}
if (server_password != NULL)
xfree(server_password);
if (*data->password == '\0')
server_password = NULL;
else
server_password = xstrdup(data->password);
log_debug("pw now %s", server_password);
return (0);
}
void
cmd_set_password_send(struct cmd *self, struct buffer *b)
{
struct cmd_set_password_data *data = self->data;
buffer_write(b, data, sizeof *data);
cmd_send_string(b, data->password);
}
void
cmd_set_password_recv(struct cmd *self, struct buffer *b)
{
struct cmd_set_password_data *data;
self->data = data = xmalloc(sizeof *data);
buffer_read(b, data, sizeof *data);
data->password = cmd_recv_string(b);
}
void
cmd_set_password_free(struct cmd *self)
{
struct cmd_set_password_data *data = self->data;
if (data->password != NULL)
xfree(data->password);
xfree(data);
}
size_t
cmd_set_password_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_set_password_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->flag_encrypted)
off += xsnprintf(buf + off, len - off, " -c");
if (off < len && data->password != NULL)
off += xsnprintf(buf + off, len - off, " password");
return (off);
}

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