1 Commits
2.4 ... 1.6

Author SHA1 Message Date
Tiago Cunha
88c831af6e Tag 1.6 release. 2012-01-23 12:59:12 +00:00
233 changed files with 19142 additions and 35239 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

463
CHANGES
View File

@@ -1,457 +1,3 @@
CHANGES FROM 2.3 to 2.4 20 April 2017
Incompatible Changes
====================
* Key tables have undergone major changes. Mode key tables are no longer
separate from the main key tables. All mode key tables have been removed,
together with the -t flag to bind-key and unbind-key.
The emacs-edit, vi-edit, emacs-choose and vi-choose tables have been replaced
by fixed key bindings in the command prompt and choose modes. The mode-keys
and status-keys options remain.
The emacs-copy and vi-copy tables have been replaced by the copy-mode and
copy-mode-vi tables. Commands are sent using the -X and -N flags to
send-keys. So the following:
bind -temacs-copy C-Up scroll-up
bind -temacs-copy -R5 WheelUpPane scroll-up
Becomes:
bind -Tcopy-mode C-Up send -X scroll-up
bind -Tcopy-mode WheelUpPane send -N5 -X scroll-up
This changes allows the full command parser (including command sequences) and
command set to be used - for example, the normal command prompt with editing
and history is now used for searching, jumping, and so on instead of a custom
one. The default C-r binding is now:
bind -Tcopy-mode C-r command-prompt -p'search up' "send -X search-backward '%%'"
There are also some new commmands available with send -X, such as
copy-pipe-and-cancel.
* set-remain-on-exit has gone -- can be achieved with hooks instead.
* Hooks: before hooks have been removed and only a selection of commands now
have after hooks (they are no longer automatic). Additional hooks have been
added.
* The xterm-keys option now defaults to on.
Normal Changes
==============
* Support for mouse double and triple clicks.
* BCE (Background Colour Erase) is now supported.
* All occurrences of a search string in copy mode are now highlighted;
additionally, the number of search results is displayed. The highlighting
updates interactively with the default emacs key bindings (incremental
search).
* source-file now understands glob patterns.
* Formats now have simple comparisons:
#{==:a,b}
#{!=:a,b}
* There are the following new formats:
- #{version} -- the tmux server version;
- #{client_termtype} -- the terminal type of the client;
- #{client_name} -- the name of a client;
- #{client_written} -- the number of bytes written to the client.
* The configuration file now accepts %if/%endif conditional blocks which are
processed when it is parsed; the argument is a format string (useful with the
new format comparison options).
* detach-client now has -E to execute a command replacing the client instead of
exiting.
* Add support for custom command aliases, this is an array option which
contains items of the form "alias=command". This is consulted when an
unknown command is parsed.
* break-pane now has -n to specify the new window name.
* OSC 52 support has been added for programs inside tmux to set a tmux buffer.
* The mouse "all event" mode (1003) is now supported.
* Palette setting is now possible (OSC 4 and 104).
* Strikethrough support (a recent terminfo is required).
* Grouped sessions can now be named (new -t).
* terminal-overrides and update-environment are now array options (the previous
set -ag syntax should work without change).
* There have been substantial performance improvements.
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 pane borders.
* Support for hooks on commands: 'after' and 'before' hooks.
* 'source-file' understands '-q' to suppress 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 now 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 CHANGES FROM 1.5 TO 1.6, 23 January 2012
* Extend the mode-mouse option to add a third choice which means the mouse * Extend the mode-mouse option to add a third choice which means the mouse
@@ -1119,7 +665,7 @@ The list of older changes is below.
* -u flag to scroll-mode and copy-mode to start scrolled one page * -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. 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: * 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 containing: bright, dim, underscore, blink, reverse, hidden, italics, for
example: example:
@@ -2142,3 +1688,10 @@ The list of older changes is below.
emacs) that don't require scrolling regions (ESC[r) mostly work fine emacs) that don't require scrolling regions (ESC[r) mostly work fine
(including mutt, emacs). No status bar yet and no key remapping or other (including mutt, emacs). No status bar yet and no key remapping or other
customisation. customisation.
$Id$
LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr
LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms
LocalWords: dstidx srcname srcidx winlink lsw nabc sabc Exp Tiago Cunha dch
LocalWords: setw Chisnall renamew merdely eg Maier newname selectw neww Gass

View File

@@ -1,33 +0,0 @@
When reporting issues:
YOU MUST INCLUDE THE TMUX VERSION
DO NOT OPEN AN ISSUE THAT DOES NOT MENTION THE TMUX VERSION
Please also include:
- your platform (Linux, OS X, or whatever);
- a brief description of the problem with steps to reproduce;
- a minimal tmux config, if you can't reproduce without a config;
- your terminal, and $TERM inside and outside of tmux;
- logs from tmux (see below);
- at most one or two screenshots, if helpful.
This should include at least the output of:
$ uname -sp && tmux -V && echo $TERM
Please do not report bugs (crashes, incorrect behaviour) without reproducing on
a tmux built from Git master.
Note that TERM inside tmux must be a variant of screen or tmux (for example:
screen or screen-256color, tmux or tmux-256color). Please ensure this is the
case before opening an issue.
To run tmux without a config and get logs, run:
tmux -Ltest kill-server
tmux -vvvv -Ltest -f/dev/null new
Then reproduce the problem, exit tmux, and attach the tmux-server-*.log file
from the current directory to the issue.

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.

207
FAQ
View File

@@ -95,6 +95,9 @@ aware of are (bearing in mind I haven't used screen for a few years now):
- screen has builtin serial and telnet support; this is bloat and is unlikely - screen has builtin serial and telnet support; this is bloat and is unlikely
to be added to tmux. to be added to tmux.
- screen has support for updating utmp. Nobody has really come up with a clean,
portable way to do this without making tmux setuid or setgid yet.
- Environment handling is different. - Environment handling is different.
- tmux tends to be more demanding on the terminal so tends to show up terminal - tmux tends to be more demanding on the terminal so tends to show up terminal
@@ -104,12 +107,8 @@ aware of are (bearing in mind I haven't used screen for a few years now):
* I found a bug! What do I do? * I found a bug! What do I do?
Check the latest version of tmux from Git to see if the problem is still Please send bug reports by email to nicm@users.sourceforge.net or
reproducible. Sometimes the length of time between releases means a lot of tmux-users@lists.sourceforge.net. Please include as much of the following
fixes can be sitting in Git and the problem might already be fixed.
Please send bug reports by email to nicholas.marriott@gmail.com or
tmux-users@googlegroups.com. Please include as much of the following
information as possible: information as possible:
- the version of tmux you are running; - the version of tmux you are running;
@@ -123,7 +122,7 @@ information as possible:
* Why doesn't tmux do $x? * 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 terminal description inside tmux? It sucks.
@@ -239,31 +238,6 @@ would be welcome.
vim users may also want to set the "ttyfast" option inside tmux. vim users may also want to set the "ttyfast" option inside tmux.
* How do I make ctrl and shift arrow keys work in emacs?
The terminal-init-screen function in term/screen.el is called for new frames,
but it doesn't configure any function keys.
If the tmux xterm-keys option is on, it is enough to define the same keys as
xterm. Add the following to init.el or .emacs to do this:
(defadvice terminal-init-screen
;; The advice is named `tmux', and is run before `terminal-init-screen' runs.
(before tmux activate)
;; Docstring. This describes the advice and is made available inside emacs;
;; for example when doing C-h f terminal-init-screen RET
"Apply xterm keymap, allowing use of keys passed through tmux."
;; This is the elisp code that is run before `terminal-init-screen'.
(if (getenv "TMUX")
(let ((map (copy-keymap xterm-function-map)))
(set-keymap-parent map (keymap-parent input-decode-map))
(set-keymap-parent input-decode-map map))))
And ensure .tmux.conf contains "set -g xterm-keys on".
Alternatively, the screen.el file can be copied to the load path and
customized.
* Why doesn't elinks set the window title inside tmux? * Why doesn't elinks set the window title inside tmux?
There isn't a way to detect if a terminal supports setting the window title, so There isn't a way to detect if a terminal supports setting the window title, so
@@ -352,111 +326,88 @@ lock(1) or vlock(1)) by using the following:
bind x set lock-command '/usr/bin/vlock' \; lock-client \; set lock-command 'tput civis && read -s -n1' bind x set lock-command '/usr/bin/vlock' \; lock-client \; set lock-command 'tput civis && read -s -n1'
* I don't see italics! Or less and vim show italics and reverse the wrong way round! * How can I open a new window in the same directory as the current window?
GNU screen does not support italics and the "screen" terminfo description uses One option is to just run "TMUX= tmux" in the window. However, this only works if no
the italics escape sequence incorrectly. command is running, so that you can input the command.
As of tmux 2.1, if default-terminal is set to "screen" or matches "screen-*", A workaround is to let tmux know about the current path through an environment
tmux will behave like screen and italics will be disabled. variable. To do so, use the following command:
To enable italics, create a new terminfo entry called "tmux" (some platforms [ -n "$TMUX" ] && tmux setenv TMUXPWD_$(tmux display -p "#I") $PWD
may already have this, you can check with "infocmp tmux"):
$ cat <<EOF|tic -x - Which sets TMUXPWD_i (where i is the number of the current window) to the path
tmux|tmux terminal multiplexer, of the current directory. This command can be added to PS1, for example:
ritm=\E[23m, rmso=\E[27m, sitm=\E[3m, smso=\E[7m, Ms@,
use=xterm+tmux, use=screen,
tmux-256color|tmux with 256 colors, PS1='$([ -n "$TMUX" ] && tmux setenv TMUXPWD_$(tmux display -p "#I") $PWD)\h$ '
use=xterm+256setaf, use=tmux,
EOF When a new window is created, the shell should be asked to change
$ directory. You can define a new binding (for example, if using GNU bash):
bind-key C-c run-shell 'tmux neww "cd $(tmux display -p "\$TMUXPWD_#I"); exec bash"'
This solution will work even if a command is currently running in the terminal,
but it will not work from a window that has just been swapped with another
because TMUXPWD_i will not be updated after a swap. However, once a new prompt
is displayed, TMUXPWD_i is updated properly.
* tmux doesn't start with "daemon failed"
tmux shows something similar to this when started:
fatal: server_start: daemon failed: No such file or directory
fatal: main_dispatch: imsg_read failed
A possible reason is that /dev/null is not a character device or is otherwise
inaccessible.
Check with:
file /dev/null
ls -l /dev/null
If it is not a character device or has incorrect permissions, it can typically
be recreated with:
cd /dev && rm null && ./MAKEDEV null
* vim displays reverse video instead of italics, while less displays italics
(or just regular text) instead of reverse. What's wrong?
Screen's terminfo description lacks italics mode and has standout mode in its
place, but using the same escape sequence that urxvt uses for italics. This
means applications (like vim) looking for italics will not find it and might
turn to reverse in its place, while applications (like less) asking for
standout will end up with italics instead of reverse. To make applications
aware that tmux supports italics and to use a proper escape sequence for
standout, you'll need to create a new terminfo file with modified sgr, smso,
rmso, sitm and ritm entries:
$ mkdir $HOME/.terminfo/
$ screen_terminfo="screen"
$ infocmp "$screen_terminfo" | sed \
-e 's/^screen[^|]*|[^,]*,/screen-it|screen with italics support,/' \
-e 's/%?%p1%t;3%/%?%p1%t;7%/' \
-e 's/smso=[^,]*,/smso=\\E[7m,/' \
-e 's/rmso=[^,]*,/rmso=\\E[27m,/' \
-e '$s/$/ sitm=\\E[3m, ritm=\\E[23m,/' > /tmp/screen.terminfo
$ tic /tmp/screen.terminfo
And tell tmux to use it in ~/.tmux.conf: And tell tmux to use it in ~/.tmux.conf:
set -g default-terminal "tmux" set -g default-terminal "screen-it"
If using urxvt, make sure you have an italics capable font enabled. for If your terminal supports 256 colors, use:
example, add to ~/.Xdefaults:
$ screen_terminfo="screen-256color"
instead of "screen". See the FAQ entry about 256 colors support for more info.
Also note that tmux will still display reverse video on terminals that do not
support italics.
If your urxvt cannot display italics at all, make sure you have an italics
capable font enabled, for example, add to ~/.Xdefaults:
urxvt.italicFont: xft:Bitstream Vera Sans Mono:italic:autohint=true urxvt.italicFont: xft:Bitstream Vera Sans Mono:italic:autohint=true
* How can I make tmux use my terminal's scrollback buffer? $Id$
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, look at the pbcopy(1) and pbpaste(1) commands.
* Why don't some commands work inside tmux on OS X?
Apple requires some undocumented, unsupported fiddling to allow commands that
interact with the GUI to work. Neither tmux itself nor most shells do this, so
an external program is required. This can be found here:
https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard
Affected commands may include say(1), pbcopy(1), pbpaste(1) and ssh(1).
* Why do I see dots around a session when I attach to it?
tmux limits the size of the window to the smallest attached session. If
it didn't do this then it would be impossible to see the entire window.
The dots mark the size of the window tmux can display.
To avoid this, detach all other clients when attaching:
$ tmux attach -d
Or from inside tmux by detaching individual clients with C-b D or all
using:
C-b : attach -d

View File

@@ -1 +0,0 @@
Please read https://raw.githubusercontent.com/tmux/tmux/master/CONTRIBUTING

View File

@@ -1,92 +1,94 @@
# Makefile.am # $Id$
# Obvious program stuff. # Obvious program stuff.
bin_PROGRAMS = tmux bin_PROGRAMS = tmux
CLEANFILES = tmux.1.mdoc tmux.1.man dist_man1_MANS = tmux.1
# Distribution tarball options. # Distribution tarball options.
EXTRA_DIST = \ EXTRA_DIST = \
CHANGES FAQ README TODO COPYING example_tmux.conf compat/*.[ch] \ CHANGES FAQ NOTES TODO examples compat \
osdep-*.c mdoc2man.awk tmux.1 array.h compat.h tmux.h osdep-*.c
dist-hook: dist-hook:
grep "^#enable_debug=" configure grep "^#found_debug=" configure
find $(distdir) -name .svn -type d|xargs rm -Rf
# Preprocessor flags. # Preprocessor flags.
AM_CPPFLAGS += @XOPEN_DEFINES@ -DTMUX_CONF="\"$(sysconfdir)/tmux.conf\"" CPPFLAGS += @XOPEN_DEFINES@
# Additional object files. # glibc as usual does things ass-backwards and hides useful things by default,
LDADD = $(LIBOBJS) # so everyone has to add this.
if IS_GLIBC
# Set flags for gcc. CFLAGS += -D_GNU_SOURCE
if IS_GCC endif
AM_CFLAGS += -std=gnu99 -O2
if IS_DEBUG # Set flags for gcc. gcc4 whines abouts silly stuff so it needs slightly
AM_CFLAGS += -g # different flags.
AM_CFLAGS += -Wno-long-long -Wall -W -Wformat=2 if IS_GCC
AM_CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations CFLAGS += -std=c99
AM_CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare if IS_DEBUG
AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align CFLAGS += -g -ggdb -O0
AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes CFLAGS += -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
AM_CFLAGS += -Wno-unused-result CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
AM_CPPFLAGS += -DDEBUG CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
CPPFLAGS += -DDEBUG
endif
if IS_GCC4
CPPFLAGS += -iquote. -I/usr/local/include
if IS_DEBUG
CFLAGS += -Wno-pointer-sign
endif
else
CPPFLAGS += -I. -I- -I/usr/local/include
endif endif
AM_CPPFLAGS += -iquote.
endif endif
# Set flags for Solaris. # Set flags for Solaris.
if IS_SUNOS if IS_SUNOS
if IS_GCC CPPFLAGS += -D_XPG4_2 -D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS
AM_CPPFLAGS += -D_XPG6
else
AM_CPPFLAGS += -D_XPG4_2
endif
endif endif
# Set flags for Sun CC. # Set flags for Sun CC.
if IS_SUNCC if IS_SUNCC
AM_CFLAGS += -erroff=E_EMPTY_DECLARATION CFLAGS += -erroff=E_EMPTY_DECLARATION
endif
# Set _LINUX_SOURCE_COMPAT for AIX for malloc(0).
if IS_AIX
AM_CPPFLAGS += -D_LINUX_SOURCE_COMPAT=1
endif
# Set flags for NetBSD.
if IS_NETBSD
AM_CPPFLAGS += -D_OPENBSD_SOURCE
endif endif
# List of sources. # List of sources.
dist_tmux_SOURCES = \ dist_tmux_SOURCES = \
alerts.c \
arguments.c \ arguments.c \
attributes.c \ attributes.c \
cfg.c \ cfg.c \
client.c \ client.c \
clock.c \
cmd-attach-session.c \ cmd-attach-session.c \
cmd-bind-key.c \ cmd-bind-key.c \
cmd-break-pane.c \ cmd-break-pane.c \
cmd-capture-pane.c \ cmd-capture-pane.c \
cmd-choose-buffer.c \ cmd-choose-buffer.c \
cmd-choose-client.c \ cmd-choose-client.c \
cmd-choose-tree.c \ cmd-choose-session.c \
cmd-choose-window.c \
cmd-clear-history.c \
cmd-clock-mode.c \
cmd-command-prompt.c \ cmd-command-prompt.c \
cmd-confirm-before.c \ cmd-confirm-before.c \
cmd-copy-mode.c \ cmd-copy-mode.c \
cmd-delete-buffer.c \
cmd-detach-client.c \ cmd-detach-client.c \
cmd-display-message.c \ cmd-display-message.c \
cmd-display-panes.c \ cmd-display-panes.c \
cmd-find-window.c \ cmd-find-window.c \
cmd-find.c \ cmd-has-session.c \
cmd-if-shell.c \ cmd-if-shell.c \
cmd-join-pane.c \ cmd-join-pane.c \
cmd-kill-pane.c \ cmd-kill-pane.c \
cmd-kill-server.c \ cmd-kill-server.c \
cmd-kill-session.c \ cmd-kill-session.c \
cmd-kill-window.c \ cmd-kill-window.c \
cmd-link-window.c \
cmd-list-buffers.c \ cmd-list-buffers.c \
cmd-list-clients.c \ cmd-list-clients.c \
cmd-list-commands.c \
cmd-list-keys.c \ cmd-list-keys.c \
cmd-list-panes.c \ cmd-list-panes.c \
cmd-list-sessions.c \ cmd-list-sessions.c \
@@ -99,7 +101,6 @@ dist_tmux_SOURCES = \
cmd-new-window.c \ cmd-new-window.c \
cmd-paste-buffer.c \ cmd-paste-buffer.c \
cmd-pipe-pane.c \ cmd-pipe-pane.c \
cmd-queue.c \
cmd-refresh-client.c \ cmd-refresh-client.c \
cmd-rename-session.c \ cmd-rename-session.c \
cmd-rename-window.c \ cmd-rename-window.c \
@@ -113,31 +114,32 @@ dist_tmux_SOURCES = \
cmd-select-pane.c \ cmd-select-pane.c \
cmd-select-window.c \ cmd-select-window.c \
cmd-send-keys.c \ cmd-send-keys.c \
cmd-send-prefix.c \
cmd-server-info.c \
cmd-set-buffer.c \ cmd-set-buffer.c \
cmd-set-environment.c \ cmd-set-environment.c \
cmd-set-hook.c \
cmd-set-option.c \ cmd-set-option.c \
cmd-show-buffer.c \
cmd-show-environment.c \ cmd-show-environment.c \
cmd-show-messages.c \ cmd-show-messages.c \
cmd-show-options.c \ cmd-show-options.c \
cmd-source-file.c \ cmd-source-file.c \
cmd-split-window.c \ cmd-split-window.c \
cmd-start-server.c \
cmd-string.c \ cmd-string.c \
cmd-suspend-client.c \
cmd-swap-pane.c \ cmd-swap-pane.c \
cmd-swap-window.c \ cmd-swap-window.c \
cmd-switch-client.c \ cmd-switch-client.c \
cmd-unbind-key.c \ cmd-unbind-key.c \
cmd-wait-for.c \ cmd-unlink-window.c \
cmd.c \ cmd.c \
colour.c \ colour.c \
compat.h \
control-notify.c \
control.c \
environ.c \ environ.c \
format.c \ format.c \
grid-utf8.c \
grid-view.c \ grid-view.c \
grid.c \ grid.c \
hooks.c \
input-keys.c \ input-keys.c \
input.c \ input.c \
job.c \ job.c \
@@ -147,26 +149,23 @@ dist_tmux_SOURCES = \
layout-set.c \ layout-set.c \
layout.c \ layout.c \
log.c \ log.c \
mode-key.c \
names.c \ names.c \
notify.c \
options-table.c \ options-table.c \
options.c \ options.c \
paste.c \ paste.c \
proc.c \
pty.c \
resize.c \ resize.c \
screen-redraw.c \ screen-redraw.c \
screen-write.c \ screen-write.c \
screen.c \ screen.c \
server-client.c \ server-client.c \
server-fn.c \ server-fn.c \
server-window.c \
server.c \ server.c \
session.c \ session.c \
signal.c \ signal.c \
status.c \ status.c \
style.c \
tmux.c \ tmux.c \
tmux.h \
tty-acs.c \ tty-acs.c \
tty-keys.c \ tty-keys.c \
tty-term.c \ tty-term.c \
@@ -177,29 +176,67 @@ dist_tmux_SOURCES = \
window-copy.c \ window-copy.c \
window.c \ window.c \
xmalloc.c \ xmalloc.c \
xmalloc.h \
xterm-keys.c xterm-keys.c
nodist_tmux_SOURCES = osdep-@PLATFORM@.c nodist_tmux_SOURCES = osdep-@PLATFORM@.c
# Add compat file for forkpty. # Pile in all the compat/ stuff that is needed.
if NEED_FORKPTY if NO_FORKPTY
nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c
endif endif
if NO_IMSG
# Add compat file for utf8proc. nodist_tmux_SOURCES += compat/imsg.c compat/imsg-buffer.c
if HAVE_UTF8PROC endif
nodist_tmux_SOURCES += compat/utf8proc.c if NO_CLOSEFROM
nodist_tmux_SOURCES += compat/closefrom.c
endif
if NO_DAEMON
nodist_tmux_SOURCES += compat/daemon.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_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 endif
# Install tmux.1 in the right format. # Update SF web site.
install-exec-hook: upload-index.html: update-index.html
if test x@MANFORMAT@ = xmdoc; then \ scp www/index.html www/main.css www/images/*.png \
sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1 \ ${USER},tmux@web.sf.net:/home/groups/t/tm/tmux/htdocs
>$(srcdir)/tmux.1.mdoc; \ rm -f www/index.html www/images/small-*
else \
sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1| \ update-index.html:
$(AWK) -f$(srcdir)/mdoc2man.awk >$(srcdir)/tmux.1.man; \ (cd www/images && \
fi rm -f small-* && \
$(mkdir_p) $(DESTDIR)$(mandir)/man1 for i in *.png; do \
$(INSTALL_DATA) $(srcdir)/tmux.1.@MANFORMAT@ \ convert "$$i" -resize 200x150 "small-$$i"; \
$(DESTDIR)$(mandir)/man1/tmux.1 done \
)
sed "s/%%VERSION%%/${VERSION}/g" www/index.html.in >www/index.html

82
NOTES Normal file
View File

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

73
README
View File

@@ -1,73 +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
It also depends on ncurses, available from:
http://invisible-island.net/ncurses/
To build and install tmux from a release tarball, use:
$ ./configure && make
$ sudo make install
tmux can use the utempter library to update utmp(5), if it is installed - run
configure with --enable-utempter to enable 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/ericpruitt/tmux.vim
https://raw.githubusercontent.com/ericpruitt/tmux.vim/master/vim/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 "enable_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 "enable_debug=yes" to
create a debug build by default.

264
TODO
View File

@@ -1,122 +1,144 @@
- command bits and pieces: - implicitly add exec to the commands for new windows (switch to disable it)?
* allow multiple targets: fnmatch for -t/-c, for example detach all - bring back detach-session to detach all clients on a session?
clients with -t* - allow fnmatch for -c, so that you can, eg, detach all clients
* add -c for new-session like new-window - garbage collect window history (100 lines at a time?) if it hasn't been used
* ' and " should be parsed the same (eg "\e" vs '\e') in config in $x time
and command prompt - flags to centre screen in window
* last-pane across sessions - activity/bell should be per-window not per-link? what if it is cur win in
* resize-pane -p to match split-window -p session not being watched?
* flag to wait-for to have a timeout and/or to stop waiting when the - use a better termcap internally instead of screen, perhaps xterm
client gets a signal - should be able to move to a hidden pane and it would be moved into view. pane
number in status line/top-right would be cool for this
- make command sequences more usable - support other mouse modes (highlight etc) and use it in copy mode
* don't require space after ; - set-remain-on-exit is a bit of a hack, some way to do it generically?
* options for error handling: && and ||? - clear window title on exit
- would be nice to be able to use "--" to mark start of command w/ neww etc
- options bits and pieces: to avoid quoting
* way to set socket path from config file - make command sequences more usable: don't require space after ;, handle
errors better
- format improvements: - attach should have a flag to create session if it doesn't exist
* option to quote format (#{q:session_name}) - choice and more mode would be better per client than per window?
* some way to pad # stuff with spaces - hooks to which commands may be attached, for example: tmux add-hook
* formats to show if a window is linked into multiple sessions, into "new-session" if-shell "[ -e $HOME/.tmux-session.conf ]" source-file
multiple attached sessions, and is the active window in multiple $HOME/.tmux-session.conf
attached sessions? - get it passing all the vttest tests that don't require resizing the terminal
- way to set socket path from config file
- choose mode improvements: - what about utmp etc? can tmux update it like screen? setgid?
* choose-pane command (augment choose-tree to do this?)
* flag to choose-* for sort order
* 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: - warts on current naming:
* display-time but message-fg/bg/attr - display-time but message-fg/bg/attr
* list-* vs show-* - list-* vs show-*
- server-info
- copy/paste improvements: - up-pane/down-pane/swap-pane -U/swap-pane -D vs next-*/previous-*
* paste w/o trailing whitespace - split-window -> split-pane??
* command to toggle selection not to move it in copy-mode - a way for force-width/height to apply to only one pane (how?)
* regex searching - command to list what is actually running in each window with command line,
* searching in copy mode should unwrap lines, so if you search for "foobar" pid (need some adaption of the osdep code)
then it should be found even if it is now "foo\nbar" (if the WRAP flag - support for bce
is set on the line) - some way to force a screen to use the entire terminal even if it is forced
* capture-pane option to preserve spaces but not join lines to be smaller by other clients. pan smaller terminal? (like screen F)
* improve word and line selection in copy mode (for example when dragging -- idea of a "view" onto a window, need base x/y offsets for redraw
it should select by word. compare how xterm works. GitHub issue 682) - handle resize better in copy mode
- way to copy stuff that is off screen due to resize
- layout stuff - commands should be able to succeed or fail and have || or && for command
* way to tag a layout as a number/name lists
* maybe keep last layout + size around and if size reverts just put it - some way to KEEP a command running continually and just use its LAST line of
back output
* revamp layouts: they are too complicated, should be more closely - UTF-8 to a non-UTF-8 terminal should not be able to balls up
integrated, should support hints, layout sets should just be a the terminal - www/ruby-addressable; make regress
special case of custom layouts, and we should support panes that are - support esc-esc to quit in modes
not attached to a cell at all. this could be the time to introduce - fix ctrl+F1-F4 output. to what?
panelink to replace layout_cell - better utf8 support: window names, prompt input, message display
* way to set hints/limits about pane size for resizing - session history for client and last-session command
* panning over window (window larger than visible) - option to change status line colour when current window is in a mode?
* a mode where one application can cross two panes (ie x|y, width = - option to move copy mode indicator into status line
COLUMNS/2 but height = ROWS * 2) - list-buffer/show-buffer should display UTF-8
* separate active panes for different clients - selection behaviour closer to vi in vi mode
- live update: server started with -U connects to server, requests sessions and
- code cleanup windows, receives fds
* instead of separate window and session options, just one master - command to show a tree of sessions-windows-panes (active marked with *)
options list with each option having a type (window or session), then - sort out inheriting config from shell on new sessions/windows:
options on window, on session, and global. for window options we look should pick up default-path/termios/etc from client if possible,
window->session->global, and for session we look session->global. else leave empty/default
problem: what about windows in multiple sessions? there are contexts - link panes into multiple windows
where we do not know which session, or where multiple choices makes - bells should be passed between sessions with visual-bell etc
no sense... could at least have one global list for all types of - use screen-256color when started on 256 colour terminal??
global options and keep separate window,session lists - if-shell/run-shell should block further command execution in the same command
* the way pane, window, session destroy is handled is too complicated sequence until its shell exits, to allow them to be used from the config file
and the distinction between session.c, window.c and server-fn.c - better session sharing: create-socket command to create socket somewhere (-r
functions is not clear. could we just have kill_pane(), flag for readonly)
kill_window(), unlink_window(), kill_session() that fix up all data - multiline status line (no?)
structures (flagging sessions as dead) and return a value to say - flag for absolute pane size to resize-pane
whether clients need to be checked for dead sessions? sort of like - sanity check input to socket
session_detach now but more so. or some other scheme to make it - support title stack, both internally and externally
simpler and clearer? also would be nice to remove/rename server-fn.c http://docs.freebsd.org/cgi/getmsg.cgi?fetch=1149299+0+archive/2010/freebsd-questions/20100207.freebsd-questions
* more readable way to work out the various things commands need to - command to show status line information briefly when it is off
know about the client, notably: - some way to pad # stuff with spaces, #!2T maybe
- is this the config file? (cmdq->c == NULL) - a binding to "scroll down and exit at bottom" copy mode
- is this a command client? (cmdq->c != NULL && - some way to pass keystrokes in copy mode through to underlying window
cmdq->c->session == NULL) - last window update time and # replacement for it for display-message
- is this a control client? - find-window across sessions - other ways to make session handling easier?
- can i do stdin or stdout to this client? - ' and " should be parsed the same (eg "\e" vs '\e') in config and command
or even guarantee that cmdq->c != NULL and provide a better way to prompt?
tell when in the config file - then we use cmdq->c if we need a - command to toggle selection not to move it in copy-mode
client w/o a session else cmd_current_client - why are alerts per-winlink? try per window?
- audit of escape sequence support vs xterm
- miscellaneous - support binding keys to mouse (mouse-select-pane -> mouse-keys or something,
* way to keep a job running just read its last line of output for #() mouse click == select-pane -t %%, mouse scroll up == copy-mode)
* link panes into multiple windows - something for -t "last window in session" so a session can be used as a stack
* live update: server started with -U connects to server, requests - synchronous commands - client sends cmd and blocks, neww/splitw saves client
sessions and windows, receives file descriptors ptr then when program inside died, sends MSG_SOMETHING with wait status to
* there are inconsistencies in what we get from old shell and what client
comes from config for new sessions and windows. likewise, panes and - documentation improvements - rlpowell's tutorial - build instructions
jobs and run-shell and lock command all start with slightly different - bind commands to key sequences? -- make it so ALL keys go through a table,
environments first an implicit table in which C-b is the only default binding to a
* multiline status line? separate command prompt and status line? command that says "next key from $othertable" and so on. means -n can
* automatic pane logging go away as well
* marks in history, automatically add (move?) one when pane is changed - monitor, bell etc should monitor /all/ panes in the window not just one
* this doesn't work, need pane reference count probably: - a history of commands that can be reversed (reverse member of each command,
bind -n DoubleClick3Status confirm-before -p "kill-window #I? (y/n)" kill-window and a buffer) info() when changing to same window
- way to add dest for break-pane; maybe some easier way to unbreak-pane
- hooks - case insensitive searching
* more hooks for various things - option to move status line to top
* finish after hooks for special commands - configurable borders and empty space filler for when panes < window?
* multiple hooks with the same name? - mouse-select-pane will screw up with !MODE_MOUSE_STANDARD (it sets the
* finish hooks for notifys flag on w/o checking the others before calling tty_update_mode)
* for session_closed, if no sessions at all, perhaps fake up a temporary one - multiple keys could be done with tables, ie have prefixes go and instead
bind -n ^A prefix-table "default"
where prefix-table sets command lookup table and sets prefix flag, then next
key is looked up in that table
- pass shell commands as argv rather than strings, allow them to be specified
in commands without quotes
- a command to choose from a generic list, so you can do eg
choose-list -l Abc,Moo,Blah "run-shell 'sh /my/choose/script %%'"
- numeric prefix in copy mode should be paste buffer for C-w
- named buffers and allow gaps in the stack
- get rid of separate UTF-8 cell stuff: add 1 byte to cell and store BMP as
uint16_t+3 bits of flags. anything <=0xffff is Unicode, higher are used to
build tree of combined characters/non-BMP (LRU dropped when full)
- entry in FAQ about what to do when someone does mkdir /tmp/tmux-1000
- show size under pane number in display-panes mode
- monitor-activity is broken in several ways with multiple clients
- monitor-activity should be more powerful (eg set a region)
- maybe a way to put pane names instead of window names in status line
- support for borderless panes
- run-shell/if-shell should support status_replace stuff
- wait-pane command or another way to make it synchronous/wait for command to
finish
- last-pane across sessions
- attach should take a pane and select it as well as attaching
- should default-path be a window option?
- option to put status line at top (why?)
- panes should have names like windows
- command-prompt doesn't work if made read-only. why?
- option to quote format eg #{session_name:quoted}
- formats need to be used for much much more stuff!
- formats need conditions for >0 (for #P)
- flags to find-window to select what is searched (title, name, content, history)
- fetch full command line on !Linux, and add option to strip prefixes
such as "sh " "/bin/sh " etc etc
- synchronize-windows option
- possibly support rxvt-unicode extended mouse input (1015)
- append to buffer in copy mode
* We need a tmux terminfo entry to document the extensions we are using in
upstream terminfo. Must NOT change (only add or remove) anything from
TERM=screen so we can fallback!

322
alerts.c
View File

@@ -1,322 +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 <stdlib.h>
#include "tmux.h"
static int alerts_fired;
static void alerts_timer(int, short, void *);
static int alerts_enabled(struct window *, int);
static void alerts_callback(int, short, void *);
static void alerts_reset(struct window *);
static int alerts_check_all(struct window *);
static int alerts_check_bell(struct window *);
static int alerts_check_activity(struct window *);
static int alerts_check_silence(struct window *);
static void printflike(2, 3) alerts_set_message(struct session *, const char *,
...);
static void alerts_ring_bell(struct session *);
static TAILQ_HEAD(, window) alerts_list = TAILQ_HEAD_INITIALIZER(alerts_list);
static 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);
}
static void
alerts_callback(__unused int fd, __unused short events, __unused void *arg)
{
struct window *w, *w1;
int alerts;
TAILQ_FOREACH_SAFE(w, &alerts_list, alerts_entry, w1) {
alerts = alerts_check_all(w);
log_debug("@%u alerts check, alerts %#x", w->id, alerts);
w->alerts_queued = 0;
TAILQ_REMOVE(&alerts_list, w, alerts_entry);
w->flags &= ~WINDOW_ALERTFLAGS;
window_remove_ref(w);
}
alerts_fired = 0;
}
static int
alerts_check_all(struct window *w)
{
int alerts;
alerts = alerts_check_bell(w);
alerts |= alerts_check_activity(w);
alerts |= alerts_check_silence(w);
return (alerts);
}
void
alerts_check_session(struct session *s)
{
struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows)
alerts_check_all(wl->window);
}
static 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);
}
static 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 (!w->alerts_queued) {
w->alerts_queued = 1;
TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
w->references++;
}
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;
}
}
static int
alerts_check_bell(struct window *w)
{
struct window *ws;
struct winlink *wl;
struct session *s;
struct client *c;
int action, visual;
if (~w->flags & WINDOW_BELL)
return (0);
TAILQ_FOREACH(wl, &w->winlinks, wentry)
wl->session->flags &= ~SESSION_ALERTED;
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
if (wl->flags & WINLINK_BELL)
continue;
s = wl->session;
if (s->curw != wl) {
wl->flags |= WINLINK_BELL;
notify_winlink("alert-bell", s, wl);
}
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
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;
ws = c->session->curw->window;
if (action == BELL_CURRENT && ws != w)
action = BELL_NONE;
if (action == BELL_OTHER && ws != w)
action = BELL_NONE;
if (!visual) {
if (action != BELL_NONE)
tty_putcode(&c->tty, TTYC_BEL);
continue;
}
if (action == BELL_CURRENT)
status_message_set(c, "Bell in current window");
else if (action != BELL_NONE) {
status_message_set(c, "Bell in window %d",
wl->idx);
}
}
}
return (WINDOW_BELL);
}
static int
alerts_check_activity(struct window *w)
{
struct winlink *wl;
struct session *s;
if (~w->flags & WINDOW_ACTIVITY)
return (0);
if (!options_get_number(w->options, "monitor-activity"))
return (0);
TAILQ_FOREACH(wl, &w->winlinks, wentry)
wl->session->flags &= ~SESSION_ALERTED;
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
if (wl->flags & WINLINK_ACTIVITY)
continue;
s = wl->session;
if (s->curw == wl)
continue;
wl->flags |= WINLINK_ACTIVITY;
notify_winlink("alert-activity", s, wl);
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
if (options_get_number(s->options, "bell-on-alert"))
alerts_ring_bell(s);
if (options_get_number(s->options, "visual-activity"))
alerts_set_message(s, "Activity in window %d", wl->idx);
}
return (WINDOW_ACTIVITY);
}
static int
alerts_check_silence(struct window *w)
{
struct winlink *wl;
struct session *s;
if (~w->flags & WINDOW_SILENCE)
return (0);
if (!options_get_number(w->options, "monitor-silence"))
return (0);
TAILQ_FOREACH(wl, &w->winlinks, wentry)
wl->session->flags &= ~SESSION_ALERTED;
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
if (wl->flags & WINLINK_SILENCE)
continue;
s = wl->session;
if (s->curw == wl)
continue;
wl->flags |= WINLINK_SILENCE;
notify_winlink("alert-silence", s, wl);
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
if (options_get_number(s->options, "bell-on-alert"))
alerts_ring_bell(s);
if (!options_get_number(s->options, "visual-silence"))
alerts_set_message(s, "Silence in window %d", wl->idx);
}
return (WINDOW_SILENCE);
}
static void
alerts_set_message(struct session *s, const char *fmt, ...)
{
struct client *c;
va_list ap;
char *message;
va_start(ap, fmt);
xvasprintf(&message, fmt, ap);
va_end(ap);
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == s)
status_message_set(c, "%s", message);
}
free(message);
}
static void
alerts_ring_bell(struct session *s)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == s && !(c->flags & CLIENT_CONTROL))
tty_putcode(&c->tty, TTYC_BEL);
}
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com> * Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -20,41 +20,33 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
/* /* Create an arguments set with no flags. */
* Manipulate command arguments. struct args *
*/ args_create(int argc, ...)
struct args_entry {
u_char flag;
char *value;
RB_ENTRY(args_entry) entry;
};
static void args_set(struct args *, u_char, const char *);
static struct args_entry *args_find(struct args *, u_char);
static int args_cmp(struct args_entry *, struct args_entry *);
RB_GENERATE_STATIC(args_tree, args_entry, entry, args_cmp);
/* Arguments tree comparison function. */
static int
args_cmp(struct args_entry *a1, struct args_entry *a2)
{ {
return (a1->flag - a2->flag); struct args *args;
} va_list ap;
int i;
/* Find a flag in the arguments tree. */ args = xcalloc(1, sizeof *args);
static struct args_entry * if ((args->flags = bit_alloc(SCHAR_MAX)) == NULL)
args_find(struct args *args, u_char ch) fatal("bit_alloc failed");
{
struct args_entry entry;
entry.flag = ch; args->argc = argc;
return (RB_FIND(args_tree, &args->tree, &entry)); 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);
} }
/* Parse an argv and argc into a new argument set. */ /* Parse an argv and argc into a new argument set. */
@@ -62,21 +54,31 @@ struct args *
args_parse(const char *template, int argc, char **argv) args_parse(const char *template, int argc, char **argv)
{ {
struct args *args; struct args *args;
char *ptr;
int opt; int opt;
args = xcalloc(1, sizeof *args); args = xcalloc(1, sizeof *args);
if ((args->flags = bit_alloc(SCHAR_MAX)) == NULL)
fatal("bit_alloc failed");
optreset = 1; optreset = 1;
optind = 1; optind = 1;
while ((opt = getopt(argc, argv, template)) != -1) { while ((opt = getopt(argc, argv, template)) != -1) {
if (opt < 0) if (opt < 0 || opt >= SCHAR_MAX)
continue; continue;
if (opt == '?' || strchr(template, opt) == NULL) { if (opt == '?' || (ptr = strchr(template, opt)) == NULL) {
args_free(args); xfree(args->flags);
xfree(args);
return (NULL); return (NULL);
} }
args_set(args, opt, optarg);
bit_set(args->flags, opt);
if (ptr[1] == ':') {
if (args->values[opt] != NULL)
xfree(args->values[opt]);
args->values[opt] = xstrdup(optarg);
}
} }
argc -= optind; argc -= optind;
argv += optind; argv += optind;
@@ -91,155 +93,125 @@ args_parse(const char *template, int argc, char **argv)
void void
args_free(struct args *args) args_free(struct args *args)
{ {
struct args_entry *entry; u_int i;
struct args_entry *entry1;
cmd_free_argv(args->argc, args->argv); cmd_free_argv(args->argc, args->argv);
RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) { for (i = 0; i < SCHAR_MAX; i++) {
RB_REMOVE(args_tree, &args->tree, entry); if (args->values[i] != NULL)
free(entry->value); xfree(args->values[i]);
free(entry);
} }
free(args); xfree(args->flags);
} xfree(args);
/* 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. */ /* Print a set of arguments. */
char * size_t
args_print(struct args *args) args_print(struct args *args, char *buf, size_t len)
{ {
size_t len; size_t off;
char *buf, *escaped; int i;
int i, flags; const char *quotes;
struct args_entry *entry;
static const char quoted[] = " #\"';$";
len = 1; /* There must be at least one byte at the start. */
buf = xcalloc(1, len); if (len == 0)
return (0);
off = 0;
/* Process the flags first. */ /* Process the flags first. */
RB_FOREACH(entry, args_tree, &args->tree) { buf[off++] = '-';
if (entry->value != NULL) for (i = 0; i < SCHAR_MAX; i++) {
if (!bit_test(args->flags, i) || args->values[i] != NULL)
continue; continue;
if (*buf == '\0') if (off == len - 1) {
args_print_add(&buf, &len, "-"); buf[off] = '\0';
args_print_add(&buf, &len, "%c", entry->flag); return (len);
}
buf[off++] = i;
buf[off] = '\0';
} }
if (off == 1)
buf[--off] = '\0';
/* Then the flags with arguments. */ /* Then the flags with arguments. */
RB_FOREACH(entry, args_tree, &args->tree) { for (i = 0; i < SCHAR_MAX; i++) {
if (entry->value == NULL) if (!bit_test(args->flags, i) || args->values[i] == NULL)
continue; continue;
if (*buf != '\0') if (off >= len) {
args_print_add(&buf, &len, " -%c ", entry->flag); /* snprintf will have zero terminated. */
else return (len);
args_print_add(&buf, &len, "-%c ", entry->flag); }
flags = VIS_OCTAL|VIS_TAB|VIS_NL; if (strchr(args->values[i], ' ') != NULL)
if (entry->value[strcspn(entry->value, quoted)] != '\0') quotes = "\"";
flags |= VIS_DQ;
utf8_stravis(&escaped, entry->value, flags);
if (flags & VIS_DQ)
args_print_add(&buf, &len, "\"%s\"", escaped);
else else
args_print_add(&buf, &len, "%s", escaped); quotes = "";
free(escaped); off += xsnprintf(buf + off, len - off, "%s-%c %s%s%s",
off != 0 ? " " : "", i, quotes, args->values[i], quotes);
} }
/* And finally the argument vector. */ /* And finally the argument vector. */
for (i = 0; i < args->argc; i++) { for (i = 0; i < args->argc; i++) {
if (*buf != '\0') if (off >= len) {
args_print_add(&buf, &len, " "); /* snprintf will have zero terminated. */
return (len);
}
flags = VIS_OCTAL|VIS_TAB|VIS_NL; if (strchr(args->argv[i], ' ') != NULL)
if (args->argv[i][strcspn(args->argv[i], quoted)] != '\0') quotes = "\"";
flags |= VIS_DQ;
utf8_stravis(&escaped, args->argv[i], flags);
if (flags & VIS_DQ)
args_print_add(&buf, &len, "\"%s\"", escaped);
else else
args_print_add(&buf, &len, "%s", escaped); quotes = "";
free(escaped); off += xsnprintf(buf + off, len - off, "%s%s%s%s",
off != 0 ? " " : "", quotes, args->argv[i], quotes);
} }
return (buf); return (off);
} }
/* Return if an argument is present. */ /* Return if an argument is present. */
int int
args_has(struct args *args, u_char ch) args_has(struct args *args, u_char ch)
{ {
return (args_find(args, ch) == NULL ? 0 : 1); return (bit_test(args->flags, ch));
} }
/* Set argument value in the arguments tree. */ /* Set argument value. */
static void void
args_set(struct args *args, u_char ch, const char *value) args_set(struct args *args, u_char ch, const char *value)
{ {
struct args_entry *entry; if (args->values[ch] != NULL)
xfree(args->values[ch]);
/* Replace existing argument. */
if ((entry = args_find(args, ch)) != NULL) {
free(entry->value);
entry->value = NULL;
} else {
entry = xcalloc(1, sizeof *entry);
entry->flag = ch;
RB_INSERT(args_tree, &args->tree, entry);
}
if (value != NULL) if (value != NULL)
entry->value = xstrdup(value); args->values[ch] = xstrdup(value);
else
args->values[ch] = NULL;
bit_set(args->flags, ch);
} }
/* Get argument value. Will be NULL if it isn't present. */ /* Get argument value. Will be NULL if it isn't present. */
const char * const char *
args_get(struct args *args, u_char ch) args_get(struct args *args, u_char ch)
{ {
struct args_entry *entry; return (args->values[ch]);
if ((entry = args_find(args, ch)) == NULL)
return (NULL);
return (entry->value);
} }
/* Convert an argument value to a number. */ /* Convert an argument value to a number. */
long long long long
args_strtonum(struct args *args, u_char ch, long long minval, long long maxval, args_strtonum(struct args *args,
char **cause) u_char ch, long long minval, long long maxval, char **cause)
{ {
const char *errstr; const char *errstr;
long long ll; long long ll;
struct args_entry *entry;
if ((entry = args_find(args, ch)) == NULL) { if (!args_has(args, ch)) {
*cause = xstrdup("missing"); *cause = xstrdup("missing");
return (0); return (0);
} }
ll = strtonum(entry->value, minval, maxval, &errstr); ll = strtonum(args->values[ch], minval, maxval, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
*cause = xstrdup(errstr); *cause = xstrdup(errstr);
return (0); return (0);

121
array.h Normal file
View File

@@ -0,0 +1,121 @@
/* $Id$ */
/*
* 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_INITIALIZER { NULL, 0, 0 }
#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) (((void *) (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$ */
/* /*
* Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org> * Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org>
@@ -23,25 +23,30 @@
#include "tmux.h" #include "tmux.h"
const char * const char *
attributes_tostring(int attr) attributes_tostring(u_char attr)
{ {
static char buf[128]; static char buf[128];
size_t len;
if (attr == 0) if (attr == 0)
return ("none"); return ("none");
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s", buf[0] = '\0';
(attr & GRID_ATTR_BRIGHT) ? "bright," : "", if (attr & GRID_ATTR_BRIGHT)
(attr & GRID_ATTR_DIM) ? "dim," : "", strlcat(buf, "bright,", sizeof (buf));
(attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "", if (attr & GRID_ATTR_DIM)
(attr & GRID_ATTR_BLINK)? "blink," : "", strlcat(buf, "dim,", sizeof (buf));
(attr & GRID_ATTR_REVERSE) ? "reverse," : "", if (attr & GRID_ATTR_UNDERSCORE)
(attr & GRID_ATTR_HIDDEN) ? "hidden," : "", strlcat(buf, "underscore,", sizeof (buf));
(attr & GRID_ATTR_ITALICS) ? "italics," : "", if (attr & GRID_ATTR_BLINK)
(attr & GRID_ATTR_STRIKETHROUGH) ? "strikethrough," : ""); strlcat(buf, "blink,", sizeof (buf));
if (len > 0) if (attr & GRID_ATTR_REVERSE)
buf[len - 1] = '\0'; strlcat(buf, "reverse,", sizeof (buf));
if (attr & GRID_ATTR_HIDDEN)
strlcat(buf, "hidden,", sizeof (buf));
if (attr & GRID_ATTR_ITALICS)
strlcat(buf, "italics,", sizeof (buf));
if (*buf != '\0')
*(strrchr(buf, ',')) = '\0';
return (buf); return (buf);
} }
@@ -50,7 +55,7 @@ int
attributes_fromstring(const char *str) attributes_fromstring(const char *str)
{ {
const char delimiters[] = " ,|"; const char delimiters[] = " ,|";
int attr; u_char attr;
size_t end; size_t end;
if (*str == '\0' || strcspn(str, delimiters) == 0) if (*str == '\0' || strcspn(str, delimiters) == 0)
@@ -79,8 +84,6 @@ attributes_fromstring(const char *str)
attr |= GRID_ATTR_HIDDEN; attr |= GRID_ATTR_HIDDEN;
else if (end == 7 && strncasecmp(str, "italics", end) == 0) else if (end == 7 && strncasecmp(str, "italics", end) == 0)
attr |= GRID_ATTR_ITALICS; attr |= GRID_ATTR_ITALICS;
else if (end == 13 && strncasecmp(str, "strikethrough", end) == 0)
attr |= GRID_ATTR_STRIKETHROUGH;
else else
return (-1); return (-1);
str += end + strspn(str + end, delimiters); str += end + strspn(str + end, delimiters);

7
autogen.sh Executable file → Normal file
View File

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

270
cfg.c
View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -17,204 +17,146 @@
*/ */
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
static char *cfg_file; /*
int cfg_finished; * Config file parser. Pretty quick and simple, each line is parsed into a
static char **cfg_causes; * argv array and executed as a command.
static u_int cfg_ncauses; */
struct client *cfg_client;
static enum cmd_retval void printflike2 cfg_print(struct cmd_ctx *, const char *, ...);
cfg_done(__unused struct cmdq_item *item, __unused void *data) void printflike2 cfg_error(struct cmd_ctx *, const char *, ...);
char *cfg_cause;
int cfg_finished;
struct causelist cfg_causes = ARRAY_INITIALIZER;
/* ARGSUSED */
void printflike2
cfg_print(unused struct cmd_ctx *ctx, unused const char *fmt, ...)
{ {
if (cfg_finished)
return (CMD_RETURN_NORMAL);
cfg_finished = 1;
if (!RB_EMPTY(&sessions))
cfg_show_causes(RB_MIN(sessions, &sessions));
if (cfg_client != NULL)
server_client_unref(cfg_client);
return (CMD_RETURN_NORMAL);
} }
void /* ARGSUSED */
set_cfg_file(const char *path) void printflike2
cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...)
{ {
free(cfg_file); va_list ap;
cfg_file = xstrdup(path);
va_start(ap, fmt);
xvasprintf(&cfg_cause, fmt, ap);
va_end(ap);
} }
void void printflike2
start_cfg(void) cfg_add_cause(struct causelist *causes, const char *fmt, ...)
{ {
const char *home; char *cause;
int quiet = 0; va_list ap;
cfg_client = TAILQ_FIRST(&clients); va_start(ap, fmt);
if (cfg_client != NULL) xvasprintf(&cause, fmt, ap);
cfg_client->references++; va_end(ap);
load_cfg(TMUX_CONF, cfg_client, NULL, 1); ARRAY_ADD(causes, cause);
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_client, NULL, quiet);
cmdq_append(cfg_client, cmdq_get_callback(cfg_done, NULL));
} }
/*
* Load configuration file. Returns -1 for an error with a list of messages in
* causes. Note that causes must be initialised by the caller!
*/
int int
load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet) load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)
{ {
FILE *f; FILE *f;
const char delim[3] = { '\\', '\\', '\0' }; u_int n;
u_int found = 0; char *buf, *line, *cause;
size_t line = 0; size_t len;
char *buf, *cause1, *p, *q, *s; struct cmd_list *cmdlist;
struct cmd_list *cmdlist; struct cmd_ctx ctx;
struct cmdq_item *new_item; int retval;
int condition = 0;
struct format_tree *ft;
log_debug("loading %s", path);
if ((f = fopen(path, "rb")) == NULL) { if ((f = fopen(path, "rb")) == NULL) {
if (errno == ENOENT && quiet) cfg_add_cause(causes, "%s: %s", path, strerror(errno));
return (0);
cfg_add_cause("%s: %s", path, strerror(errno));
return (-1); return (-1);
} }
n = 0;
while ((buf = fparseln(f, NULL, &line, delim, 0)) != NULL) { line = NULL;
log_debug("%s: %s", path, buf); retval = 0;
while ((buf = fgetln(f, &len))) {
if (buf[len - 1] == '\n')
len--;
p = buf; if (line != NULL)
while (isspace((u_char)*p)) line = xrealloc(line, 1, strlen(line) + len + 1);
p++; else {
if (*p == '\0') { line = xmalloc(len + 1);
free(buf); *line = '\0';
}
/* Append buffer to line. strncat will terminate. */
strncat(line, buf, len);
n++;
/* Continuation: get next line? */
len = strlen(line);
if (len > 0 && line[len - 1] == '\\') {
line[len - 1] = '\0';
continue; continue;
} }
q = p + strlen(p) - 1; buf = line;
while (q != p && isspace((u_char)*q)) line = NULL;
*q-- = '\0';
if (condition != 0 && strcmp(p, "%endif") == 0) { if (cmd_string_parse(buf, &cmdlist, &cause) != 0) {
condition = 0; xfree(buf);
continue; if (cause == NULL)
}
if (strncmp(p, "%if ", 4) == 0) {
if (condition != 0) {
cfg_add_cause("%s:%zu: nested %%if", path,
line);
continue; continue;
} cfg_add_cause(causes, "%s: %u: %s", path, n, cause);
ft = format_create(NULL, FORMAT_NONE, FORMAT_NOJOBS); xfree(cause);
s = p + 3;
while (isspace((u_char)*s))
s++;
s = format_expand(ft, s);
if (*s != '\0' && (s[0] != '0' || s[1] != '\0'))
condition = 1;
else
condition = -1;
free(s);
format_free(ft);
continue; continue;
} } else
if (condition == -1) xfree(buf);
continue;
cmdlist = cmd_string_parse(p, path, line, &cause1);
if (cmdlist == NULL) {
free(buf);
if (cause1 == NULL)
continue;
cfg_add_cause("%s:%zu: %s", path, line, cause1);
free(cause1);
continue;
}
free(buf);
if (cmdlist == NULL) if (cmdlist == NULL)
continue; continue;
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0); cfg_cause = NULL;
if (item != NULL)
cmdq_insert_after(item, new_item);
else
cmdq_append(c, new_item);
cmd_list_free(cmdlist);
found++; if (ctxin == NULL) {
ctx.msgdata = NULL;
ctx.curclient = NULL;
ctx.cmdclient = NULL;
} else {
ctx.msgdata = ctxin->msgdata;
ctx.curclient = ctxin->curclient;
ctx.cmdclient = ctxin->cmdclient;
}
ctx.error = cfg_error;
ctx.print = cfg_print;
ctx.info = cfg_print;
cfg_cause = NULL;
if (cmd_list_exec(cmdlist, &ctx) == 1)
retval = 1;
cmd_list_free(cmdlist);
if (cfg_cause != NULL) {
cfg_add_cause(
causes, "%s: %d: %s", path, n, cfg_cause);
xfree(cfg_cause);
}
}
if (line != NULL) {
cfg_add_cause(causes,
"%s: %d: line continuation at end of file", path, n);
xfree(line);
} }
fclose(f); fclose(f);
return (found); return (retval);
}
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 cmdq_item *item)
{
u_int i;
for (i = 0; i < cfg_ncauses; i++) {
cmdq_print(item, "%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;
} }

870
client.c

File diff suppressed because it is too large Load Diff

159
clock.c Normal file
View File

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

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,133 +18,97 @@
#include <sys/types.h> #include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Attach existing session to the current terminal. * Attach existing session to the current terminal.
*/ */
static enum cmd_retval cmd_attach_session_exec(struct cmd *, int cmd_attach_session_exec(struct cmd *, struct cmd_ctx *);
struct cmdq_item *);
const struct cmd_entry cmd_attach_session_entry = { const struct cmd_entry cmd_attach_session_entry = {
.name = "attach-session", "attach-session", "attach",
.alias = "attach", "drt:", 0, 0,
"[-dr] " CMD_TARGET_SESSION_USAGE,
.args = { "c:dErt:", 0, 0 }, CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON,
.usage = "[-dEr] [-c working-directory] " CMD_TARGET_SESSION_USAGE, NULL,
NULL,
.tflag = CMD_SESSION_WITHPANE, cmd_attach_session_exec
.flags = CMD_STARTSERVER,
.exec = cmd_attach_session_exec
}; };
enum cmd_retval int
cmd_attach_session(struct cmdq_item *item, int dflag, int rflag, cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
const char *cflag, int Eflag)
{
struct session *s = item->state.tflag.s;
struct client *c = item->client, *c_loop;
struct winlink *wl = item->state.tflag.wl;
struct window_pane *wp = item->state.tflag.wp;
char *cause;
if (RB_EMPTY(&sessions)) {
cmdq_error(item, "no sessions");
return (CMD_RETURN_ERROR);
}
if (c == NULL)
return (CMD_RETURN_NORMAL);
if (server_client_check_nested(c)) {
cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force");
return (CMD_RETURN_ERROR);
}
if (wl != NULL) {
if (wp != NULL)
window_set_active_pane(wp->window, wp);
session_set_current(s, wl);
}
if (cflag != NULL) {
free((void *)s->cwd);
s->cwd = format_single(item, cflag, c, s, wl, wp);
}
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)
environ_update(s->options, c->environ, s->environ);
c->session = s;
if (!item->repeat)
server_client_set_key_table(c, NULL);
status_timer_start(c);
notify_client("client-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(item, "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)
environ_update(s->options, c->environ, s->environ);
c->session = s;
server_client_set_key_table(c, NULL);
status_timer_start(c);
notify_client("client-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);
notify_client("client-attached", c);
c->flags |= CLIENT_ATTACHED;
}
recalculate_sizes();
alerts_check_session(s);
server_update_socket();
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_attach_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s;
struct client *c;
const char *update;
char *overrides, *cause;
u_int i;
return (cmd_attach_session(item, args_has(args, 'd'), if (RB_EMPTY(&sessions)) {
args_has(args, 'r'), args_get(args, 'c'), args_has(args, 'E'))); ctx->error(ctx, "no sessions");
return (-1);
}
if ((s = cmd_find_session(ctx, args_get(args, 't'), 1)) == NULL)
return (-1);
if (ctx->cmdclient == NULL && ctx->curclient == NULL)
return (0);
if (ctx->cmdclient == NULL) {
if (args_has(self->args, 'd')) {
/*
* Can't use server_write_session in case attaching to
* the same session as currently attached to.
*/
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != s)
continue;
if (c == ctx->curclient)
continue;
server_write_client(c, MSG_DETACH, NULL, 0);
}
}
ctx->curclient->session = s;
session_update_activity(s);
server_redraw_client(ctx->curclient);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
} else {
if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) {
ctx->error(ctx, "not a terminal");
return (-1);
}
overrides =
options_get_string(&s->options, "terminal-overrides");
if (tty_open(&ctx->cmdclient->tty, overrides, &cause) != 0) {
ctx->error(ctx, "terminal open failed: %s", cause);
xfree(cause);
return (-1);
}
if (args_has(self->args, 'r'))
ctx->cmdclient->flags |= CLIENT_READONLY;
if (args_has(self->args, 'd'))
server_write_session(s, MSG_DETACH, NULL, 0);
ctx->cmdclient->session = s;
session_update_activity(s);
server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
update = options_get_string(&s->options, "update-environment");
environ_update(update, &ctx->cmdclient->environ, &s->environ);
server_redraw_client(ctx->cmdclient);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
}
recalculate_sizes();
server_update_socket();
return (1); /* 1 means don't tell command client to exit */
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,59 +18,103 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Bind a key to a command. * Bind a key to a command, this recurses through cmd_*.
*/ */
static enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmdq_item *); int cmd_bind_key_check(struct args *);
int cmd_bind_key_exec(struct cmd *, struct cmd_ctx *);
int cmd_bind_key_table(struct cmd *, struct cmd_ctx *, int);
const struct cmd_entry cmd_bind_key_entry = { const struct cmd_entry cmd_bind_key_entry = {
.name = "bind-key", "bind-key", "bind",
.alias = "bind", "cnrt:", 1, -1,
"[-cnr] [-t key-table] key command [arguments]",
.args = { "cnrT:", 2, -1 }, 0,
.usage = "[-cnr] [-T key-table] key " NULL,
"command [arguments]", cmd_bind_key_check,
cmd_bind_key_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_bind_key_exec
}; };
static enum cmd_retval int
cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item) cmd_bind_key_check(struct args *args)
{
if (args_has(args, 't')) {
if (args->argc != 2)
return (-1);
} else {
if (args->argc < 2)
return (-1);
}
return (0);
}
int
cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
char *cause; char *cause;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
key_code key; int key;
const char *tablename;
key = key_string_lookup_string(args->argv[0]); key = key_string_lookup_string(args->argv[0]);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) { if (key == KEYC_NONE) {
cmdq_error(item, "unknown key: %s", args->argv[0]); ctx->error(ctx, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR); return (-1);
} }
if (args_has(args, 'T')) if (args_has(args, 't'))
tablename = args_get(args, 'T'); return (cmd_bind_key_table(self, ctx, key));
else if (args_has(args, 'n'))
tablename = "root";
else
tablename = "prefix";
cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0, cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, &cause);
&cause);
if (cmdlist == NULL) { if (cmdlist == NULL) {
cmdq_error(item, "%s", cause); ctx->error(ctx, "%s", cause);
free(cause); xfree(cause);
return (CMD_RETURN_ERROR); return (-1);
} }
key_bindings_add(tablename, key, args_has(args, 'r'), cmdlist); if (!args_has(args, 'n'))
return (CMD_RETURN_NORMAL); key |= KEYC_PREFIX;
key_bindings_add(key, args_has(args, 'r'), cmdlist);
return (0);
}
int
cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
{
struct args *args = self->args;
const char *tablename;
const struct mode_key_table *mtab;
struct mode_key_binding *mbind, mtmp;
enum mode_key_cmd cmd;
tablename = args_get(args, 't');
if ((mtab = mode_key_findtable(tablename)) == NULL) {
ctx->error(ctx, "unknown key table: %s", tablename);
return (-1);
}
cmd = mode_key_fromstring(mtab->cmdstr, args->argv[1]);
if (cmd == MODEKEY_NONE) {
ctx->error(ctx, "unknown command: %s", args->argv[1]);
return (-1);
}
mtmp.key = key;
mtmp.mode = !!args_has(args, 'c');
if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) {
mbind->cmd = cmd;
return (0);
}
mbind = xmalloc(sizeof *mbind);
mbind->key = mtmp.key;
mbind->mode = mtmp.mode;
mbind->cmd = cmd;
RB_INSERT(mode_key_tree, mtab->tree, mbind);
return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -26,89 +26,64 @@
* Break pane off into a window. * Break pane off into a window.
*/ */
#define BREAK_PANE_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" int cmd_break_pane_exec(struct cmd *, struct cmd_ctx *);
static enum cmd_retval cmd_break_pane_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_break_pane_entry = { const struct cmd_entry cmd_break_pane_entry = {
.name = "break-pane", "break-pane", "breakp",
.alias = "breakp", "dt:", 0, 0,
"[-d] " CMD_TARGET_PANE_USAGE,
.args = { "dPF:n:s:t:", 0, 0 }, 0,
.usage = "[-dP] [-F format] [-n window-name] [-s src-pane] [-t dst-window]", NULL,
NULL,
.sflag = CMD_PANE, cmd_break_pane_exec
.tflag = CMD_WINDOW_INDEX,
.flags = 0,
.exec = cmd_break_pane_exec
}; };
static enum cmd_retval int
cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct winlink *wl;
struct winlink *wl = item->state.sflag.wl; struct session *s;
struct session *src_s = item->state.sflag.s; struct window_pane *wp;
struct session *dst_s = item->state.tflag.s; struct window *w;
struct window_pane *wp = item->state.sflag.wp; char *cause;
struct window *w = wl->window; int base_idx;
char *name, *cause;
int idx = item->state.tflag.idx;
const char *template;
char *cp;
if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) { if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL)
cmdq_error(item, "index %d already in use", idx); return (-1);
return (CMD_RETURN_ERROR);
if (window_count_panes(wl->window) == 1) {
ctx->error(ctx, "can't break with only one pane");
return (-1);
} }
if (window_count_panes(w) == 1) { w = wl->window;
cmdq_error(item, "can't break with only one pane");
return (CMD_RETURN_ERROR);
}
server_unzoom_window(w);
TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_REMOVE(&w->panes, wp, entry);
window_lost_pane(w, wp); if (wp == w->active) {
w->active = w->last;
w->last = NULL;
if (w->active == NULL) {
w->active = TAILQ_PREV(wp, window_panes, entry);
if (w->active == NULL)
w->active = TAILQ_NEXT(wp, entry);
}
} else if (wp == w->last)
w->last = NULL;
layout_close_pane(wp); layout_close_pane(wp);
w = wp->window = window_create(dst_s->sx, dst_s->sy); w = wp->window = window_create1(s->sx, s->sy);
TAILQ_INSERT_HEAD(&w->panes, wp, entry); TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp; w->active = wp;
w->name = default_window_name(w);
layout_init(w);
if (!args_has(args, 'n')) { base_idx = options_get_number(&s->options, "base-index");
name = default_window_name(w); wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */
window_set_name(w, name);
free(name);
} else {
window_set_name(w, args_get(args, 'n'));
options_set_number(w->options, "automatic-rename", 0);
}
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')) if (!args_has(self->args, 'd'))
session_select(dst_s, wl->idx); session_select(s, wl->idx);
server_redraw_session(src_s); server_redraw_session(s);
if (src_s != dst_s) server_status_session_group(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')) { return (0);
if ((template = args_get(args, 'F')) == NULL)
template = BREAK_PANE_TEMPLATE;
cp = format_single(item, template, c, dst_s, wl, wp);
cmdq_print(item, "%s", cp);
free(cp);
}
return (CMD_RETURN_NORMAL);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Jonathan Alvarado <radobobo@users.sourceforge.net> * Copyright (c) 2009 Jonathan Alvarado <radobobo@users.sourceforge.net>
@@ -24,142 +24,62 @@
#include "tmux.h" #include "tmux.h"
/* /*
* Write the entire contents of a pane to a buffer or stdout. * Write the entire contents of a pane to a buffer.
*/ */
static enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmdq_item *); int cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *);
static char *cmd_capture_pane_append(char *, size_t *, char *, size_t);
static char *cmd_capture_pane_pending(struct args *, struct window_pane *,
size_t *);
static char *cmd_capture_pane_history(struct args *, struct cmdq_item *,
struct window_pane *, size_t *);
const struct cmd_entry cmd_capture_pane_entry = { const struct cmd_entry cmd_capture_pane_entry = {
.name = "capture-pane", "capture-pane", "capturep",
.alias = "capturep", "b:E:S:t:", 0, 0,
"[-b buffer-index] [-E end-line] [-S start-line] [-t target-pane]",
.args = { "ab:CeE:JpPqS:t:", 0, 0 }, 0,
.usage = "[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] " NULL,
"[-S start-line]" CMD_TARGET_PANE_USAGE, NULL,
cmd_capture_pane_exec
.tflag = CMD_PANE,
.flags = CMD_AFTERHOOK,
.exec = cmd_capture_pane_exec
}; };
const struct cmd_entry cmd_clear_history_entry = { int
.name = "clear-history", cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
.alias = "clearhist",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.flags = CMD_AFTERHOOK,
.exec = cmd_capture_pane_exec
};
static 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);
}
static 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] >= ' ' && 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);
}
static char *
cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
struct window_pane *wp, size_t *len)
{ {
struct args *args = self->args;
struct window_pane *wp;
char *buf, *line, *cause;
struct screen *s;
struct grid *gd; struct grid *gd;
const struct grid_line *gl; int buffer, n;
struct grid_cell *gc = NULL; u_int i, limit, top, bottom, tmp;
int n, with_codes, escape_c0, join_lines; size_t len, linelen;
u_int i, sx, top, bottom, tmp;
char *cause, *buf, *line;
const char *Sflag, *Eflag;
size_t linelen;
sx = screen_size_x(&wp->base); if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
if (args_has(args, 'a')) { return (-1);
gd = wp->saved_grid; s = &wp->base;
if (gd == NULL) { gd = s->grid;
if (!args_has(args, 'q')) {
cmdq_error(item, "no alternate screen");
return (NULL);
}
return (xstrdup(""));
}
} else
gd = wp->base.grid;
Sflag = args_get(args, 'S'); buf = NULL;
if (Sflag != NULL && strcmp(Sflag, "-") == 0) len = 0;
n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause);
if (cause != NULL) {
top = gd->hsize;
xfree(cause);
} else if (n < 0 && (u_int) -n > gd->hsize)
top = 0; top = 0;
else { else
n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause); top = gd->hsize + n;
if (cause != NULL) { if (top > gd->hsize + gd->sy - 1)
top = gd->hsize; top = gd->hsize + gd->sy - 1;
free(cause);
} else if (n < 0 && (u_int) -n > gd->hsize)
top = 0;
else
top = gd->hsize + n;
if (top > gd->hsize + gd->sy - 1)
top = gd->hsize + gd->sy - 1;
}
Eflag = args_get(args, 'E'); n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause);
if (Eflag != NULL && strcmp(Eflag, "-") == 0) if (cause != NULL) {
bottom = gd->hsize + gd->sy - 1;
xfree(cause);
} else if (n < 0 && (u_int) -n > gd->hsize)
bottom = 0;
else
bottom = gd->hsize + n;
if (bottom > gd->hsize + gd->sy - 1)
bottom = gd->hsize + gd->sy - 1; bottom = gd->hsize + gd->sy - 1;
else {
n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause);
if (cause != NULL) {
bottom = gd->hsize + gd->sy - 1;
free(cause);
} else if (n < 0 && (u_int) -n > gd->hsize)
bottom = 0;
else
bottom = gd->hsize + n;
if (bottom > gd->hsize + gd->sy - 1)
bottom = gd->hsize + gd->sy - 1;
}
if (bottom < top) { if (bottom < top) {
tmp = bottom; tmp = bottom;
@@ -167,77 +87,38 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
top = tmp; top = tmp;
} }
with_codes = args_has(args, 'e');
escape_c0 = args_has(args, 'C');
join_lines = args_has(args, 'J');
buf = NULL;
for (i = top; i <= bottom; i++) { for (i = top; i <= bottom; i++) {
line = grid_string_cells(gd, 0, i, sx, &gc, with_codes, line = grid_string_cells(s->grid, 0, i, screen_size_x(s));
escape_c0, !join_lines); linelen = strlen(line);
linelen = strlen(line);
buf = cmd_capture_pane_append(buf, len, line, linelen); buf = xrealloc(buf, 1, len + linelen + 1);
memcpy(buf + len, line, linelen);
len += linelen;
buf[len++] = '\n';
gl = grid_peek_line(gd, i); xfree(line);
if (!join_lines || !(gl->flags & GRID_LINE_WRAPPED))
buf[(*len)++] = '\n';
free(line);
} }
return (buf);
} limit = options_get_number(&global_options, "buffer-limit");
static enum cmd_retval if (!args_has(args, 'b')) {
cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item) paste_add(&global_buffers, buf, len, limit);
{ return (0);
struct args *args = self->args; }
struct client *c;
struct window_pane *wp = item->state.tflag.wp; buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
char *buf, *cause; if (cause != NULL) {
const char *bufname; ctx->error(ctx, "buffer %s", cause);
size_t len; xfree(buf);
xfree(cause);
if (self->entry == &cmd_clear_history_entry) { return (-1);
if (wp->mode == &window_copy_mode) }
window_pane_reset_mode(wp);
grid_clear_history(wp->base.grid); if (paste_replace(&global_buffers, buffer, buf, len) != 0) {
return (CMD_RETURN_NORMAL); ctx->error(ctx, "no buffer %d", buffer);
} xfree(buf);
return (-1);
len = 0; }
if (args_has(args, 'P'))
buf = cmd_capture_pane_pending(args, wp, &len); return (0);
else
buf = cmd_capture_pane_history(args, item, wp, &len);
if (buf == NULL)
return (CMD_RETURN_ERROR);
if (args_has(args, 'p')) {
c = item->client;
if (c == NULL ||
(c->session != NULL && !(c->flags & CLIENT_CONTROL))) {
cmdq_error(item, "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(item, "%s", cause);
free(cause);
free(buf);
return (CMD_RETURN_ERROR);
}
}
return (CMD_RETURN_NORMAL);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com> * Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -19,7 +19,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h> #include <ctype.h>
#include <stdlib.h>
#include "tmux.h" #include "tmux.h"
@@ -27,75 +26,118 @@
* Enter choice mode to choose a buffer. * Enter choice mode to choose a buffer.
*/ */
#define CHOOSE_BUFFER_TEMPLATE \ int cmd_choose_buffer_exec(struct cmd *, struct cmd_ctx *);
"#{buffer_name}: #{buffer_size} bytes: #{buffer_sample}"
static enum cmd_retval cmd_choose_buffer_exec(struct cmd *, void cmd_choose_buffer_callback(void *, int);
struct cmdq_item *); void cmd_choose_buffer_free(void *);
const struct cmd_entry cmd_choose_buffer_entry = { const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer", "choose-buffer", NULL,
.alias = NULL, "t:", 0, 1,
CMD_TARGET_WINDOW_USAGE " [template]",
.args = { "F:t:", 0, 1 }, 0,
.usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]", NULL,
NULL,
.tflag = CMD_WINDOW, cmd_choose_buffer_exec
.flags = 0,
.exec = cmd_choose_buffer_exec
}; };
static enum cmd_retval struct cmd_choose_buffer_data {
cmd_choose_buffer_exec(struct cmd *self, struct cmdq_item *item) struct client *client;
char *template;
};
int
cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct cmd_choose_buffer_data *cdata;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl;
struct window_choose_data *cdata;
struct paste_buffer *pb; struct paste_buffer *pb;
char *action, *action_data;
const char *template;
u_int idx; u_int idx;
char *tmp;
if (c == NULL) { if (ctx->curclient == NULL) {
cmdq_error(item, "no client available"); ctx->error(ctx, "must be run interactively");
return (CMD_RETURN_ERROR); return (-1);
} }
if ((template = args_get(args, 'F')) == NULL) if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
template = CHOOSE_BUFFER_TEMPLATE; return (-1);
if (paste_get_top(NULL) == NULL) if (paste_get_top(&global_buffers) == NULL)
return (CMD_RETURN_NORMAL); return (0);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (CMD_RETURN_NORMAL); return (0);
if (args->argc != 0)
action = xstrdup(args->argv[0]);
else
action = xstrdup("paste-buffer -b '%%'");
idx = 0; idx = 0;
pb = NULL; while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) {
while ((pb = paste_walk(pb)) != NULL) { tmp = paste_print(pb, 50);
cdata = window_choose_data_create(TREE_OTHER, c, c->session); window_choose_add(wl->window->active, idx - 1,
cdata->idx = idx; "%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp);
xfree(tmp);
cdata->ft_template = xstrdup(template);
format_defaults_paste_buffer(cdata->ft, pb);
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); cdata = xmalloc(sizeof *cdata);
if (args->argc != 0)
cdata->template = xstrdup(args->argv[0]);
else
cdata->template = xstrdup("paste-buffer -b '%%'");
cdata->client = ctx->curclient;
cdata->client->references++;
return (CMD_RETURN_NORMAL); window_choose_ready(wl->window->active,
0, cmd_choose_buffer_callback, cmd_choose_buffer_free, cdata);
return (0);
}
void
cmd_choose_buffer_callback(void *data, int idx)
{
struct cmd_choose_buffer_data *cdata = data;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *template, *cause, tmp[16];
if (idx == -1)
return;
if (cdata->client->flags & CLIENT_DEAD)
return;
xsnprintf(tmp, sizeof tmp, "%u", idx);
template = cmd_template_replace(cdata->template, tmp, 1);
if (cmd_string_parse(template, &cmdlist, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(cdata->client, "%s", cause);
xfree(cause);
}
xfree(template);
return;
}
xfree(template);
ctx.msgdata = NULL;
ctx.curclient = cdata->client;
ctx.error = key_bindings_error;
ctx.print = key_bindings_print;
ctx.info = key_bindings_info;
ctx.cmdclient = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist);
}
void
cmd_choose_buffer_free(void *data)
{
struct cmd_choose_buffer_data *cdata = data;
cdata->client->references--;
xfree(cdata->template);
xfree(cdata);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -19,7 +19,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h> #include <ctype.h>
#include <stdlib.h>
#include "tmux.h" #include "tmux.h"
@@ -27,109 +26,128 @@
* Enter choice mode to choose a client. * Enter choice mode to choose a client.
*/ */
#define CHOOSE_CLIENT_TEMPLATE \ int cmd_choose_client_exec(struct cmd *, struct cmd_ctx *);
"#{client_name}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}]" \
"#{?client_utf8, (utf8),}#{?client_readonly, (ro),} " \
"(last used #{t:client_activity})"
static enum cmd_retval cmd_choose_client_exec(struct cmd *, void cmd_choose_client_callback(void *, int);
struct cmdq_item *); void cmd_choose_client_free(void *);
static void cmd_choose_client_callback(struct window_choose_data *);
const struct cmd_entry cmd_choose_client_entry = { const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client", "choose-client", NULL,
.alias = NULL, "t:", 0, 1,
CMD_TARGET_WINDOW_USAGE " [template]",
.args = { "F:t:", 0, 1 }, 0,
.usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]", NULL,
NULL,
.tflag = CMD_WINDOW, cmd_choose_client_exec
.flags = 0,
.exec = cmd_choose_client_exec
}; };
struct cmd_choose_client_data { struct cmd_choose_client_data {
struct client *client; struct client *client;
char *template;
}; };
static enum cmd_retval int
cmd_choose_client_exec(struct cmd *self, struct cmdq_item *item) cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct cmd_choose_client_data *cdata;
struct client *c1; struct winlink *wl;
struct window_choose_data *cdata; struct client *c;
struct winlink *wl = item->state.tflag.wl; u_int i, idx, cur;
const char *template;
char *action;
u_int idx, cur;
if (c == NULL) { if (ctx->curclient == NULL) {
cmdq_error(item, "no client available"); ctx->error(ctx, "must be run interactively");
return (CMD_RETURN_ERROR); return (-1);
} }
if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
return (-1);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (CMD_RETURN_NORMAL); return (0);
if ((template = args_get(args, 'F')) == NULL)
template = CHOOSE_CLIENT_TEMPLATE;
if (args->argc != 0)
action = xstrdup(args->argv[0]);
else
action = xstrdup("detach-client -t '%%'");
cur = idx = 0; cur = idx = 0;
TAILQ_FOREACH(c1, &clients, entry) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
if (c1->session == NULL) c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
continue; continue;
if (c1 == item->client) if (c == ctx->curclient)
cur = idx; 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->name, 1);
window_choose_add(wl->window->active, cdata);
idx++; idx++;
window_choose_add(wl->window->active, i,
"%s: %s [%ux%u %s]%s%s", c->tty.path,
c->session->name, c->tty.sx, c->tty.sy,
c->tty.termname,
c->tty.flags & TTY_UTF8 ? " (utf8)" : "",
c->flags & CLIENT_READONLY ? " (ro)" : "");
} }
free(action);
window_choose_ready(wl->window->active, cur, cdata = xmalloc(sizeof *cdata);
cmd_choose_client_callback); if (args->argc != 0)
cdata->template = xstrdup(args->argv[0]);
else
cdata->template = xstrdup("detach-client -t '%%'");
cdata->client = ctx->curclient;
cdata->client->references++;
return (CMD_RETURN_NORMAL); window_choose_ready(wl->window->active,
cur, cmd_choose_client_callback, cmd_choose_client_free, cdata);
return (0);
} }
static void void
cmd_choose_client_callback(struct window_choose_data *cdata) cmd_choose_client_callback(void *data, int idx)
{ {
struct client *c; struct cmd_choose_client_data *cdata = data;
u_int idx; struct client *c;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *template, *cause;
if (cdata == NULL) if (idx == -1)
return; return;
if (cdata->start_client->flags & CLIENT_DEAD) if (cdata->client->flags & CLIENT_DEAD)
return; return;
idx = 0; if ((u_int) idx > ARRAY_LENGTH(&clients) - 1)
TAILQ_FOREACH(c, &clients, entry) { return;
if (idx == cdata->idx) c = ARRAY_ITEM(&clients, idx);
break;
idx++;
}
if (c == NULL || c->session == NULL) if (c == NULL || c->session == NULL)
return; return;
template = cmd_template_replace(cdata->template, c->tty.path, 1);
window_choose_data_run(cdata); if (cmd_string_parse(template, &cmdlist, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(c, "%s", cause);
xfree(cause);
}
xfree(template);
return;
}
xfree(template);
ctx.msgdata = NULL;
ctx.curclient = cdata->client;
ctx.error = key_bindings_error;
ctx.print = key_bindings_print;
ctx.info = key_bindings_info;
ctx.cmdclient = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist);
}
void
cmd_choose_client_free(void *data)
{
struct cmd_choose_client_data *cdata = data;
cdata->client->references--;
xfree(cdata->template);
xfree(cdata);
} }

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

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

View File

@@ -1,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}\""
static enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmdq_item *);
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
};
static enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->state.c;
struct winlink *wl = item->state.tflag.wl, *wm;
struct session *s = item->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(item, "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);
}

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

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

View File

@@ -1,5 +1,7 @@
/* $Id$ */
/* /*
* Copyright (c) 2016 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -16,37 +18,37 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdarg.h> #include "tmux.h"
#include <string.h>
#include "compat.h" /*
* Clear pane history.
*/
#if defined(HAVE_PRCTL) && defined(HAVE_PR_SET_NAME) int cmd_clear_history_exec(struct cmd *, struct cmd_ctx *);
#include <sys/prctl.h> const struct cmd_entry cmd_clear_history_entry = {
"clear-history", "clearhist",
"t:", 0, 0,
CMD_TARGET_PANE_USAGE,
0,
NULL,
NULL,
cmd_clear_history_exec
};
void int
setproctitle(const char *fmt, ...) cmd_clear_history_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
char title[16], name[16], *cp; struct args *args = self->args;
va_list ap; struct window_pane *wp;
int used; struct grid *gd;
va_start(ap, fmt); if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
vsnprintf(title, sizeof title, fmt, ap); return (-1);
va_end(ap); gd = wp->base.grid;
used = snprintf(name, sizeof name, "%s: %s", getprogname(), title); grid_move_lines(gd, 0, gd->hsize, gd->sy);
if (used >= (int)sizeof name) { gd->hsize = 0;
cp = strrchr(name, ' ');
if (cp != NULL) return (0);
*cp = '\0';
}
prctl(PR_SET_NAME, name);
} }
#else
void
setproctitle(__unused const char *fmt, ...)
{
}
#endif

View File

@@ -1,5 +1,7 @@
/* $Id$ */
/* /*
* Copyright (c) 2017 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -16,40 +18,34 @@
#include <sys/types.h> #include <sys/types.h>
#include <glob.h> #include "tmux.h"
#include <unistd.h>
#include "compat.h" /*
* Enter clock mode.
*/
void fatal(const char *, ...); int cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *);
void fatalx(const char *, ...);
const struct cmd_entry cmd_clock_mode_entry = {
"clock-mode", NULL,
"t:", 0, 0,
CMD_TARGET_PANE_USAGE,
0,
NULL,
NULL,
cmd_clock_mode_exec
};
#ifdef HAVE_PROC_PID
int int
getdtablecount(void) cmd_clock_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
char path[PATH_MAX]; struct args *args = self->args;
glob_t g; struct window_pane *wp;
int n;
if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
return (-1);
window_pane_set_mode(wp, &window_clock_mode);
if (snprintf(path, sizeof path, "/proc/%ld/fd/*", (long)getpid()) < 0)
fatal("snprintf overflow");
switch (glob(path, 0, NULL, &g)) {
case GLOB_NOMATCH:
return (0);
case 0:
break;
default:
fatal("glob(\"%s\") failed", path);
}
n = g.gl_pathc;
globfree(&g);
return (n);
}
#else
int
getdtablecount(void)
{
return (0); return (0);
} }
#endif

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -19,7 +19,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h> #include <ctype.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
@@ -29,64 +28,85 @@
* Prompt for command in client. * Prompt for command in client.
*/ */
static enum cmd_retval cmd_command_prompt_exec(struct cmd *, void cmd_command_prompt_key_binding(struct cmd *, int);
struct cmdq_item *); int cmd_command_prompt_check(struct args *);
int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *);
static int cmd_command_prompt_callback(void *, const char *, int); int cmd_command_prompt_callback(void *, const char *);
static void cmd_command_prompt_free(void *); void cmd_command_prompt_free(void *);
const struct cmd_entry cmd_command_prompt_entry = { const struct cmd_entry cmd_command_prompt_entry = {
.name = "command-prompt", "command-prompt", NULL,
.alias = NULL, "I:p:t:", 0, 1,
"[-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " [template]",
.args = { "1iI:Np:t:", 0, 1 }, 0,
.usage = "[-1Ni] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " " cmd_command_prompt_key_binding,
"[template]", NULL,
cmd_command_prompt_exec
.tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_command_prompt_exec
}; };
struct cmd_command_prompt_cdata { struct cmd_command_prompt_cdata {
struct client *c; struct client *c;
int flags;
char *inputs; char *inputs;
char *next_input; char *next_input;
char *prompts;
char *next_prompt; char *next_prompt;
char *prompts;
char *template; char *template;
int idx; int idx;
}; };
static enum cmd_retval void
cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item) cmd_command_prompt_key_binding(struct cmd *self, int key)
{
switch (key) {
case '$':
self->args = args_create(1, "rename-session '%%'");
args_set(self->args, 'I', "#S");
break;
case ',':
self->args = args_create(1, "rename-window '%%'");
args_set(self->args, 'I', "#W");
break;
case '.':
self->args = args_create(1, "move-window -t '%%'");
break;
case 'f':
self->args = args_create(1, "find-window '%%'");
break;
case '\'':
self->args = args_create(1, "select-window -t ':%%'");
args_set(self->args, 'p', "index");
break;
default:
self->args = args_create(0);
break;
}
}
int
cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
const char *inputs, *prompts; const char *inputs, *prompts;
struct cmd_command_prompt_cdata *cdata; struct cmd_command_prompt_cdata *cdata;
struct client *c = item->state.c; struct client *c;
char *prompt, *ptr, *input = NULL; char *prompt, *ptr, *input = NULL;
size_t n; size_t n;
if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
return (-1);
if (c->prompt_string != NULL) if (c->prompt_string != NULL)
return (CMD_RETURN_NORMAL); return (0);
cdata = xcalloc(1, sizeof *cdata); cdata = xmalloc(sizeof *cdata);
cdata->c = c; cdata->c = c;
cdata->idx = 1;
cdata->inputs = NULL; cdata->inputs = NULL;
cdata->next_input = NULL; cdata->next_input = NULL;
cdata->prompts = NULL;
cdata->next_prompt = NULL; cdata->next_prompt = NULL;
cdata->prompts = NULL;
cdata->template = NULL; cdata->template = NULL;
cdata->idx = 1;
if (args->argc != 0) if (args->argc != 0)
cdata->template = xstrdup(args->argv[0]); cdata->template = xstrdup(args->argv[0]);
@@ -116,94 +136,80 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
input = strsep(&cdata->next_input, ","); input = strsep(&cdata->next_input, ",");
} }
if (args_has(args, '1'))
cdata->flags |= PROMPT_SINGLE;
else if (args_has(args, 'N'))
cdata->flags |= PROMPT_NUMERIC;
else if (args_has(args, 'i'))
cdata->flags |= PROMPT_INCREMENTAL;
status_prompt_set(c, prompt, input, cmd_command_prompt_callback, status_prompt_set(c, prompt, input, cmd_command_prompt_callback,
cmd_command_prompt_free, cdata, cdata->flags); cmd_command_prompt_free, cdata, 0);
free(prompt); xfree(prompt);
return (CMD_RETURN_NORMAL); return (0);
} }
static enum cmd_retval int
cmd_command_prompt_error(struct cmdq_item *item, void *data) cmd_command_prompt_callback(void *data, const char *s)
{
char *error = data;
cmdq_error(item, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static int
cmd_command_prompt_callback(void *data, const char *s, int done)
{ {
struct cmd_command_prompt_cdata *cdata = data; struct cmd_command_prompt_cdata *cdata = data;
struct client *c = cdata->c; struct client *c = cdata->c;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmdq_item *new_item; struct cmd_ctx ctx;
char *cause, *new_template, *prompt, *ptr; char *cause, *new_template, *prompt, *ptr;
char *input = NULL; char *input = NULL;
if (s == NULL) if (s == NULL)
return (0); return (0);
if (done && (cdata->flags & PROMPT_INCREMENTAL))
return (0);
new_template = cmd_template_replace(cdata->template, s, cdata->idx); new_template = cmd_template_replace(cdata->template, s, cdata->idx);
if (done) { xfree(cdata->template);
free(cdata->template); cdata->template = new_template;
cdata->template = new_template;
}
/* /*
* Check if there are more prompts; if so, get its respective input * Check if there are more prompts; if so, get its respective input
* and update the prompt data. * and update the prompt data.
*/ */
if (done && (ptr = strsep(&cdata->next_prompt, ",")) != NULL) { if ((ptr = strsep(&cdata->next_prompt, ",")) != NULL) {
xasprintf(&prompt, "%s ", ptr); xasprintf(&prompt, "%s ", ptr);
input = strsep(&cdata->next_input, ","); input = strsep(&cdata->next_input, ",");
status_prompt_update(c, prompt, input); status_prompt_update(c, prompt, input);
free(prompt); xfree(prompt);
cdata->idx++; cdata->idx++;
return (1); return (1);
} }
cmdlist = cmd_string_parse(new_template, NULL, 0, &cause); if (cmd_string_parse(new_template, &cmdlist, &cause) != 0) {
if (cmdlist == NULL) {
if (cause != NULL) { if (cause != NULL) {
new_item = cmdq_get_callback(cmd_command_prompt_error, *cause = toupper((u_char) *cause);
cause); status_message_set(c, "%s", cause);
} else xfree(cause);
new_item = NULL; }
} else { return (0);
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist);
} }
if (new_item != NULL) ctx.msgdata = NULL;
cmdq_append(c, new_item); ctx.curclient = c;
if (!done) ctx.error = key_bindings_error;
free(new_template); ctx.print = key_bindings_print;
if (c->prompt_callbackfn != (void *)&cmd_command_prompt_callback) 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)
return (1); return (1);
return (0); return (0);
} }
static void void
cmd_command_prompt_free(void *data) cmd_command_prompt_free(void *data)
{ {
struct cmd_command_prompt_cdata *cdata = data; struct cmd_command_prompt_cdata *cdata = data;
free(cdata->inputs); if (cdata->inputs != NULL)
free(cdata->prompts); xfree(cdata->inputs);
free(cdata->template); if (cdata->prompts != NULL)
free(cdata); xfree(cdata->prompts);
if (cdata->template != NULL)
xfree(cdata->template);
xfree(cdata);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -16,10 +16,7 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <sys/types.h>
#include <ctype.h> #include <ctype.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -28,116 +25,126 @@
* Asks for confirmation before executing a command. * Asks for confirmation before executing a command.
*/ */
static enum cmd_retval cmd_confirm_before_exec(struct cmd *, void cmd_confirm_before_key_binding(struct cmd *, int);
struct cmdq_item *); int cmd_confirm_before_exec(struct cmd *, struct cmd_ctx *);
static int cmd_confirm_before_callback(void *, const char *, int); int cmd_confirm_before_callback(void *, const char *);
static void cmd_confirm_before_free(void *); void cmd_confirm_before_free(void *);
const struct cmd_entry cmd_confirm_before_entry = { const struct cmd_entry cmd_confirm_before_entry = {
.name = "confirm-before", "confirm-before", "confirm",
.alias = "confirm", "p:t:", 1, 1,
"[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
.args = { "p:t:", 1, 1 }, 0,
.usage = "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command", cmd_confirm_before_key_binding,
NULL,
.tflag = CMD_CLIENT, cmd_confirm_before_exec
.flags = 0,
.exec = cmd_confirm_before_exec
}; };
struct cmd_confirm_before_data { struct cmd_confirm_before_data {
struct client *c;
char *cmd; char *cmd;
struct client *client;
}; };
static enum cmd_retval void
cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item) cmd_confirm_before_key_binding(struct cmd *self, int key)
{
switch (key) {
case '&':
self->args = args_create(1, "kill-window");
args_set(self->args, 'p', "kill-window #W? (y/n)");
break;
case 'x':
self->args = args_create(1, "kill-pane");
args_set(self->args, 'p', "kill-pane #P? (y/n)");
break;
default:
self->args = args_create(0);
break;
}
}
int
cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_confirm_before_data *cdata; struct cmd_confirm_before_data *cdata;
struct client *c = item->state.c; struct client *c;
char *cmd, *copy, *new_prompt, *ptr; char *cmd, *copy, *new_prompt, *ptr;
const char *prompt; const char *prompt;
if (ctx->curclient == NULL) {
ctx->error(ctx, "must be run interactively");
return (-1);
}
if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
return (-1);
if ((prompt = args_get(args, 'p')) != NULL) if ((prompt = args_get(args, 'p')) != NULL)
xasprintf(&new_prompt, "%s ", prompt); xasprintf(&new_prompt, "%s ", prompt);
else { else {
ptr = copy = xstrdup(args->argv[0]); ptr = copy = xstrdup(args->argv[0]);
cmd = strsep(&ptr, " \t"); cmd = strsep(&ptr, " \t");
xasprintf(&new_prompt, "Confirm '%s'? (y/n) ", cmd); xasprintf(&new_prompt, "Confirm '%s'? (y/n) ", cmd);
free(copy); xfree(copy);
} }
cdata = xmalloc(sizeof *cdata); cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(args->argv[0]); cdata->cmd = xstrdup(args->argv[0]);
cdata->c = c;
cdata->client = c; status_prompt_set(cdata->c, new_prompt, NULL,
cdata->client->references++;
status_prompt_set(c, new_prompt, NULL,
cmd_confirm_before_callback, cmd_confirm_before_free, cdata, cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
PROMPT_SINGLE); PROMPT_SINGLE);
free(new_prompt); xfree(new_prompt);
return (CMD_RETURN_NORMAL); return (1);
} }
static enum cmd_retval int
cmd_confirm_before_error(struct cmdq_item *item, void *data) cmd_confirm_before_callback(void *data, const char *s)
{
char *error = data;
cmdq_error(item, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static int
cmd_confirm_before_callback(void *data, const char *s, __unused int done)
{ {
struct cmd_confirm_before_data *cdata = data; struct cmd_confirm_before_data *cdata = data;
struct client *c = cdata->client; struct client *c = cdata->c;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmdq_item *new_item; struct cmd_ctx ctx;
char *cause; char *cause;
if (c->flags & CLIENT_DEAD)
return (0);
if (s == NULL || *s == '\0') if (s == NULL || *s == '\0')
return (0); return (0);
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0') if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
return (0); return (0);
cmdlist = cmd_string_parse(cdata->cmd, NULL, 0, &cause); if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) {
if (cmdlist == NULL) {
if (cause != NULL) { if (cause != NULL) {
new_item = cmdq_get_callback(cmd_confirm_before_error, *cause = toupper((u_char) *cause);
cause); status_message_set(c, "%s", cause);
} else xfree(cause);
new_item = NULL; }
} else { return (0);
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist);
} }
if (new_item != NULL) ctx.msgdata = NULL;
cmdq_append(c, new_item); 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);
return (0); return (0);
} }
static void void
cmd_confirm_before_free(void *data) cmd_confirm_before_free(void *data)
{ {
struct cmd_confirm_before_data *cdata = data; struct cmd_confirm_before_data *cdata = data;
struct client *c = cdata->client;
server_client_unref(c); if (cdata->cmd != NULL)
xfree(cdata->cmd);
free(cdata->cmd); xfree(cdata);
free(cdata);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -21,69 +21,44 @@
#include "tmux.h" #include "tmux.h"
/* /*
* Enter copy or clock mode. * Enter copy mode.
*/ */
static enum cmd_retval cmd_copy_mode_exec(struct cmd *, struct cmdq_item *); void cmd_copy_mode_key_binding(struct cmd *, int);
int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_copy_mode_entry = { const struct cmd_entry cmd_copy_mode_entry = {
.name = "copy-mode", "copy-mode", NULL,
.alias = NULL, "t:u", 0, 0,
"[-u] " CMD_TARGET_PANE_USAGE,
.args = { "Met:u", 0, 0 }, 0,
.usage = "[-Mu] " CMD_TARGET_PANE_USAGE, cmd_copy_mode_key_binding,
NULL,
.tflag = CMD_PANE, cmd_copy_mode_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_copy_mode_exec
}; };
const struct cmd_entry cmd_clock_mode_entry = { void
.name = "clock-mode", cmd_copy_mode_key_binding(struct cmd *self, int key)
.alias = NULL, {
self->args = args_create(0);
if (key == KEYC_PPAGE)
args_set(self->args, 'u', NULL);
}
.args = { "t:", 0, 0 }, int
.usage = CMD_TARGET_PANE_USAGE, cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
.tflag = CMD_PANE,
.flags = CMD_AFTERHOOK,
.exec = cmd_copy_mode_exec
};
static enum cmd_retval
cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->client; struct window_pane *wp;
struct session *s;
struct window_pane *wp = item->state.tflag.wp;
if (args_has(args, 'M')) { if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
if ((wp = cmd_mouse_pane(&item->mouse, &s, NULL)) == NULL) return (-1);
return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
}
if (self->entry == &cmd_clock_mode_entry) { if (window_pane_set_mode(wp, &window_copy_mode) != 0)
window_pane_set_mode(wp, &window_clock_mode); return (0);
return (CMD_RETURN_NORMAL); window_copy_init_from_pane(wp);
}
if (wp->mode != &window_copy_mode) {
if (window_pane_set_mode(wp, &window_copy_mode) != 0)
return (CMD_RETURN_NORMAL);
window_copy_init_from_pane(wp, 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, &item->mouse);
}
if (wp->mode == &window_copy_mode && args_has(self->args, 'u')) if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
window_copy_pageup(wp, 0); window_copy_pageup(wp);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,5 +1,7 @@
/* $Id$ */
/* /*
* Copyright (c) 2016 Joshua Rubin <joshua@rubixconsulting.com> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -16,51 +18,49 @@
#include <sys/types.h> #include <sys/types.h>
#include <utf8proc.h> #include <stdlib.h>
#include "compat.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",
"b:", 0, 0,
CMD_BUFFER_USAGE,
0,
NULL,
NULL,
cmd_delete_buffer_exec
};
int int
utf8proc_wcwidth(wchar_t wc) cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
int cat; struct args *args = self->args;
char *cause;
int buffer;
cat = utf8proc_category(wc); if (!args_has(args, 'b')) {
if (cat == UTF8PROC_CATEGORY_CO) { paste_free_top(&global_buffers);
/* return (0);
* The private use category is where powerline and similar
* codepoints are stored, they have "ambiguous" width - use 1.
*/
return (1);
} }
return (utf8proc_charwidth(wc));
}
int buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
utf8proc_mbtowc(wchar_t *pwc, const char *s, size_t n) if (cause != NULL) {
{ ctx->error(ctx, "buffer %s", cause);
utf8proc_ssize_t slen; xfree(cause);
if (s == NULL)
return (0);
/*
* *pwc == -1 indicates invalid codepoint
* slen < 0 indicates an error
*/
slen = utf8proc_iterate(s, n, pwc);
if (*pwc == (wchar_t)-1 || slen < 0)
return (-1); return (-1);
return (slen); }
}
int if (paste_free_index(&global_buffers, buffer) != 0) {
utf8proc_wctomb(char *s, wchar_t wc) ctx->error(ctx, "no buffer %d", buffer);
{
if (s == NULL)
return (0);
if (!utf8proc_codepoint_valid(wc))
return (-1); return (-1);
return (utf8proc_encode_char(wc, s)); }
return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,60 +18,32 @@
#include <sys/types.h> #include <sys/types.h>
#include <string.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Detach a client. * Detach a client.
*/ */
static enum cmd_retval cmd_detach_client_exec(struct cmd *, int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *);
struct cmdq_item *);
const struct cmd_entry cmd_detach_client_entry = { const struct cmd_entry cmd_detach_client_entry = {
.name = "detach-client", "detach-client", "detach",
.alias = "detach", "s:t:P", 0, 0,
"[-P] [-s target-session] " CMD_TARGET_CLIENT_USAGE,
.args = { "aE:s:t:P", 0, 0 }, CMD_READONLY,
.usage = "[-aP] [-E shell-command] " NULL,
"[-s target-session] " CMD_TARGET_CLIENT_USAGE, NULL,
cmd_detach_client_exec
.sflag = CMD_SESSION,
.tflag = CMD_CLIENT,
.flags = CMD_READONLY,
.exec = cmd_detach_client_exec
}; };
const struct cmd_entry cmd_suspend_client_entry = { int
.name = "suspend-client", cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx)
.alias = "suspendc",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE,
.tflag = CMD_CLIENT,
.flags = 0,
.exec = cmd_detach_client_exec
};
static enum cmd_retval
cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c, *cloop; struct client *c;
struct session *s; struct session *s;
enum msgtype msgtype; enum msgtype msgtype;
const char *cmd = args_get(args, 'E'); u_int i;
if (self->entry == &cmd_suspend_client_entry) {
tty_stop_tty(&c->tty);
c->flags |= CLIENT_SUSPENDED;
proc_send(c->peer, MSG_SUSPEND, -1, NULL, 0);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'P')) if (args_has(args, 'P'))
msgtype = MSG_DETACHKILL; msgtype = MSG_DETACHKILL;
@@ -79,33 +51,22 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
msgtype = MSG_DETACH; msgtype = MSG_DETACH;
if (args_has(args, 's')) { if (args_has(args, 's')) {
s = item->state.sflag.s; s = cmd_find_session(ctx, args_get(args, 's'), 0);
TAILQ_FOREACH(cloop, &clients, entry) { if (s == NULL)
if (cloop->session == s) { return (-1);
if (cmd != NULL)
server_client_exec(cloop, cmd); for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
else c = ARRAY_ITEM(&clients, i);
server_client_detach(cloop, msgtype); if (c != NULL && c->session == s)
} server_write_client(c, msgtype, NULL, 0);
} }
return (CMD_RETURN_STOP); } else {
c = cmd_find_client(ctx, args_get(args, 't'));
if (c == NULL)
return (-1);
server_write_client(c, msgtype, NULL, 0);
} }
if (args_has(args, 'a')) { return (0);
TAILQ_FOREACH(cloop, &clients, entry) {
if (cloop->session != NULL && cloop != c) {
if (cmd != NULL)
server_client_exec(cloop, cmd);
else
server_client_detach(cloop, msgtype);
}
}
return (CMD_RETURN_NORMAL);
}
if (cmd != NULL)
server_client_exec(c, cmd);
else
server_client_detach(c, msgtype);
return (CMD_RETURN_STOP);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <time.h> #include <time.h>
#include "tmux.h" #include "tmux.h"
@@ -27,63 +26,53 @@
* Displays a message in the status line. * Displays a message in the status line.
*/ */
#define DISPLAY_MESSAGE_TEMPLATE \ int cmd_display_message_exec(struct cmd *, struct cmd_ctx *);
"[#{session_name}] #{window_index}:" \
"#{window_name}, current pane #{pane_index} " \
"- (%H:%M %d-%b-%y)"
static enum cmd_retval cmd_display_message_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_display_message_entry = { const struct cmd_entry cmd_display_message_entry = {
.name = "display-message", "display-message", "display",
.alias = "display", "c:pt:", 0, 1,
"[-p] [-c target-client] [-t target-pane] [message]",
.args = { "c:pt:F:", 0, 1 }, 0,
.usage = "[-p] [-c target-client] [-F format] " NULL,
CMD_TARGET_PANE_USAGE " [message]", NULL,
cmd_display_message_exec
.cflag = CMD_CLIENT_CANFAIL,
.tflag = CMD_PANE,
.flags = CMD_AFTERHOOK,
.exec = cmd_display_message_exec
}; };
static enum cmd_retval int
cmd_display_message_exec(struct cmd *self, struct cmdq_item *item) cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct client *c;
struct session *s = item->state.tflag.s; struct session *s;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl;
struct window_pane *wp = item->state.tflag.wp; struct window_pane *wp;
const char *template; const char *template;
char *msg; char *msg;
struct format_tree *ft;
if (args_has(args, 'F') && args->argc != 0) { if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL)
cmdq_error(item, "only one of -F or argument must be given"); return (-1);
return (CMD_RETURN_ERROR);
if (args_has(args, 't') != 0) {
wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp);
if (wl == NULL)
return (-1);
} else {
s = NULL;
wl = NULL;
wp = NULL;
} }
template = args_get(args, 'F'); if (args->argc == 0)
if (args->argc != 0) template = "[#S] #I:#W, current pane #P - (%H:%M %d-%b-%y)";
else
template = args->argv[0]; template = args->argv[0];
if (template == NULL)
template = DISPLAY_MESSAGE_TEMPLATE;
ft = format_create(item, FORMAT_NONE, 0); msg = status_replace(c, s, wl, wp, template, time(NULL), 0);
format_defaults(ft, c, s, wl, wp);
msg = format_expand_time(ft, template, time(NULL));
if (args_has(self->args, 'p')) if (args_has(self->args, 'p'))
cmdq_print(item, "%s", msg); ctx->print(ctx, "%s", msg);
else if (c != NULL) else
status_message_set(c, "%s", msg); status_message_set(c, "%s", msg);
free(msg); xfree(msg);
format_free(ft); return (0);
return (CMD_RETURN_NORMAL);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,98 +18,34 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Display panes on a client. * Display panes on a client.
*/ */
static enum cmd_retval cmd_display_panes_exec(struct cmd *, int cmd_display_panes_exec(struct cmd *, struct cmd_ctx *);
struct cmdq_item *);
static void cmd_display_panes_callback(struct client *,
struct window_pane *);
const struct cmd_entry cmd_display_panes_entry = { const struct cmd_entry cmd_display_panes_entry = {
.name = "display-panes", "display-panes", "displayp",
.alias = "displayp", "t:", 0, 0,
CMD_TARGET_CLIENT_USAGE,
.args = { "t:", 0, 1 }, 0,
.usage = CMD_TARGET_CLIENT_USAGE, NULL,
NULL,
.tflag = CMD_CLIENT, cmd_display_panes_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_display_panes_exec
}; };
static enum cmd_retval int
cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item) cmd_display_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct client *c;
if (c->identify_callback != NULL) if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
return (CMD_RETURN_NORMAL); return (-1);
c->identify_callback = cmd_display_panes_callback; server_set_identify(c);
if (args->argc != 0)
c->identify_callback_data = xstrdup(args->argv[0]);
else
c->identify_callback_data = xstrdup("select-pane -t '%%'");
server_client_set_identify(c); return (0);
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_display_panes_error(struct cmdq_item *item, void *data)
{
char *error = data;
cmdq_error(item, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static void
cmd_display_panes_callback(struct client *c, struct window_pane *wp)
{
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
char *template, *cmd, *expanded, *cause;
template = c->identify_callback_data;
if (wp == NULL)
goto out;
xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(template, expanded, 1);
cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);
if (cmdlist == NULL) {
if (cause != NULL) {
new_item = cmdq_get_callback(cmd_display_panes_error,
cause);
} else
new_item = NULL;
} else {
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist);
}
if (new_item != NULL)
cmdq_append(c, new_item);
free(cmd);
free(expanded);
out:
free(c->identify_callback_data);
c->identify_callback_data = NULL;
c->identify_callback = NULL;
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -19,7 +19,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <fnmatch.h> #include <fnmatch.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -28,156 +27,94 @@
* Find window containing text. * Find window containing text.
*/ */
#define FIND_WINDOW_TEMPLATE \ int cmd_find_window_exec(struct cmd *, struct cmd_ctx *);
"#{window_index}: #{window_name} " \
"[#{window_width}x#{window_height}] " \
"(#{window_panes} panes) #{window_find_matches}"
static enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmdq_item *); void cmd_find_window_callback(void *, int);
void cmd_find_window_free(void *);
static void cmd_find_window_callback(struct window_choose_data *);
/* Flags for determining matching behavior. */
#define CMD_FIND_WINDOW_BY_TITLE 0x1
#define CMD_FIND_WINDOW_BY_CONTENT 0x2
#define CMD_FIND_WINDOW_BY_NAME 0x4
#define CMD_FIND_WINDOW_ALL \
(CMD_FIND_WINDOW_BY_TITLE | \
CMD_FIND_WINDOW_BY_CONTENT | \
CMD_FIND_WINDOW_BY_NAME)
const struct cmd_entry cmd_find_window_entry = { const struct cmd_entry cmd_find_window_entry = {
.name = "find-window", "find-window", "findw",
.alias = "findw", "t:", 1, 1,
CMD_TARGET_WINDOW_USAGE " match-string",
.args = { "F:CNt:T", 1, 4 }, 0,
.usage = "[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string", NULL,
NULL,
.tflag = CMD_WINDOW, cmd_find_window_exec
.flags = 0,
.exec = cmd_find_window_exec
}; };
struct cmd_find_window_data { struct cmd_find_window_data {
struct winlink *wl; struct session *session;
char *list_ctx;
u_int pane_id;
TAILQ_ENTRY(cmd_find_window_data) entry;
}; };
TAILQ_HEAD(cmd_find_window_list, cmd_find_window_data);
static u_int cmd_find_window_match_flags(struct args *); int
static void cmd_find_window_match(struct cmd_find_window_list *, int, cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
struct winlink *, const char *, const char *);
static u_int
cmd_find_window_match_flags(struct args *args)
{
u_int match_flags = 0;
/* Turn on flags based on the options. */
if (args_has(args, 'T'))
match_flags |= CMD_FIND_WINDOW_BY_TITLE;
if (args_has(args, 'C'))
match_flags |= CMD_FIND_WINDOW_BY_CONTENT;
if (args_has(args, 'N'))
match_flags |= CMD_FIND_WINDOW_BY_NAME;
/* If none of the flags were set, default to matching anything. */
if (match_flags == 0)
match_flags = CMD_FIND_WINDOW_ALL;
return (match_flags);
}
static 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 window_pane *wp;
u_int i, line;
char *sres;
find_data = xcalloc(1, sizeof *find_data);
i = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
i++;
if ((match_flags & CMD_FIND_WINDOW_BY_NAME) &&
fnmatch(searchstr, wl->window->name, 0) == 0) {
find_data->list_ctx = xstrdup("");
break;
}
if ((match_flags & CMD_FIND_WINDOW_BY_TITLE) &&
fnmatch(searchstr, wp->base.title, 0) == 0) {
xasprintf(&find_data->list_ctx,
"pane %u title: \"%s\"", i - 1, wp->base.title);
break;
}
if (match_flags & CMD_FIND_WINDOW_BY_CONTENT &&
(sres = window_pane_search(wp, str, &line)) != NULL) {
xasprintf(&find_data->list_ctx,
"pane %u line %u: \"%s\"", i - 1, line + 1, sres);
free(sres);
break;
}
}
if (find_data->list_ctx != NULL) {
find_data->wl = wl;
find_data->pane_id = i - 1;
TAILQ_INSERT_TAIL(find_list, find_data, entry);
} else
free(find_data);
}
static enum cmd_retval
cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct cmd_find_window_data *cdata;
struct window_choose_data *cdata; struct session *s;
struct session *s = item->state.tflag.s; struct winlink *wl, *wm;
struct winlink *wl = item->state.tflag.wl, *wm; struct window *w;
struct cmd_find_window_list find_list; struct window_pane *wp;
struct cmd_find_window_data *find_data; ARRAY_DECL(, u_int) list_idx;
struct cmd_find_window_data *find_data1; ARRAY_DECL(, char *) list_ctx;
char *str, *searchstr; char *str, *sres, *sctx, *searchstr;
const char *template; u_int i, line;
u_int i, match_flags;
if (c == NULL) { if (ctx->curclient == NULL) {
cmdq_error(item, "no client available"); ctx->error(ctx, "must be run interactively");
return (CMD_RETURN_ERROR); return (-1);
} }
s = ctx->curclient->session;
if ((template = args_get(args, 'F')) == NULL) if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
template = FIND_WINDOW_TEMPLATE; return (-1);
match_flags = cmd_find_window_match_flags(args);
str = args->argv[0]; str = args->argv[0];
TAILQ_INIT(&find_list); ARRAY_INIT(&list_idx);
ARRAY_INIT(&list_ctx);
xasprintf(&searchstr, "*%s*", str); xasprintf(&searchstr, "*%s*", str);
RB_FOREACH(wm, winlinks, &s->windows) RB_FOREACH(wm, winlinks, &s->windows) {
cmd_find_window_match(&find_list, match_flags, wm, str, searchstr); i = 0;
free(searchstr); TAILQ_FOREACH(wp, &wm->window->panes, entry) {
i++;
if (TAILQ_EMPTY(&find_list)) { if (fnmatch(searchstr, wm->window->name, 0) == 0)
cmdq_error(item, "no windows matching: %s", str); sctx = xstrdup("");
return (CMD_RETURN_ERROR); else {
sres = window_pane_search(wp, str, &line);
if (sres == NULL &&
fnmatch(searchstr, wp->base.title, 0) != 0)
continue;
if (sres == NULL) {
xasprintf(&sctx,
"pane %u title: \"%s\"", i - 1,
wp->base.title);
} else {
xasprintf(&sctx,
"pane %u line %u: \"%s\"", i - 1,
line + 1, sres);
xfree(sres);
}
}
ARRAY_ADD(&list_idx, wm->idx);
ARRAY_ADD(&list_ctx, sctx);
}
}
xfree(searchstr);
if (ARRAY_LENGTH(&list_idx) == 0) {
ctx->error(ctx, "no windows matching: %s", str);
ARRAY_FREE(&list_idx);
ARRAY_FREE(&list_ctx);
return (-1);
} }
if (TAILQ_NEXT(TAILQ_FIRST(&find_list), entry) == NULL) { if (ARRAY_LENGTH(&list_idx) == 1) {
if (session_select(s, TAILQ_FIRST(&find_list)->wl->idx) == 0) if (session_select(s, ARRAY_FIRST(&list_idx)) == 0)
server_redraw_session(s); server_redraw_session(s);
recalculate_sizes(); recalculate_sizes();
goto out; goto out;
@@ -186,55 +123,54 @@ cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
goto out; goto out;
i = 0; for (i = 0; i < ARRAY_LENGTH(&list_idx); i++) {
TAILQ_FOREACH(find_data, &find_list, entry) { wm = winlink_find_by_index(
cdata = window_choose_data_create(TREE_OTHER, c, c->session); &s->windows, ARRAY_ITEM(&list_idx, i));
cdata->idx = find_data->wl->idx; w = wm->window;
cdata->wl = find_data->wl;
cdata->ft_template = xstrdup(template); sctx = ARRAY_ITEM(&list_ctx, i);
cdata->pane_id = find_data->pane_id; window_choose_add(wl->window->active,
wm->idx, "%3d: %s [%ux%u] (%u panes) %s", wm->idx, w->name,
format_add(cdata->ft, "line", "%u", i); w->sx, w->sy, window_count_panes(w), sctx);
format_add(cdata->ft, "window_find_matches", "%s", xfree(sctx);
find_data->list_ctx);
format_defaults(cdata->ft, NULL, s, find_data->wl, NULL);
window_choose_add(wl->window->active, cdata);
i++;
} }
window_choose_ready(wl->window->active, 0, cmd_find_window_callback); cdata = xmalloc(sizeof *cdata);
cdata->session = s;
cdata->session->references++;
window_choose_ready(wl->window->active,
0, cmd_find_window_callback, cmd_find_window_free, cdata);
out: out:
TAILQ_FOREACH_SAFE(find_data, &find_list, entry, find_data1) { ARRAY_FREE(&list_idx);
free(find_data->list_ctx); ARRAY_FREE(&list_ctx);
TAILQ_REMOVE(&find_list, find_data, entry);
free(find_data); return (0);
}
return (CMD_RETURN_NORMAL);
} }
static void void
cmd_find_window_callback(struct window_choose_data *cdata) cmd_find_window_callback(void *data, int idx)
{ {
struct session *s; struct cmd_find_window_data *cdata = data;
struct window_pane *wp; struct session *s = cdata->session;
if (cdata == NULL) if (idx == -1)
return; return;
s = cdata->start_session;
if (!session_alive(s)) if (!session_alive(s))
return; return;
wp = window_pane_at_index(cdata->wl->window, cdata->pane_id); if (session_select(s, idx) == 0) {
if (wp != NULL && window_pane_visible(wp))
window_set_active_pane(cdata->wl->window, wp);
if (session_select(s, cdata->idx) == 0) {
server_redraw_session(s); server_redraw_session(s);
recalculate_sizes(); recalculate_sizes();
} }
} }
void
cmd_find_window_free(void *data)
{
struct cmd_find_window_data *cdata = data;
cdata->session->references--;
xfree(cdata);
}

1295
cmd-find.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,7 @@
/* $Id$ */
/* /*
* Copyright (c) 2017 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -16,16 +18,31 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h> #include "tmux.h"
#include <string.h>
#include "compat.h" /*
* Cause client to report an error and exit with 1 if session doesn't exist.
*/
void int cmd_has_session_exec(struct cmd *, struct cmd_ctx *);
freezero(void *ptr, size_t size)
const struct cmd_entry cmd_has_session_entry = {
"has-session", "has",
"t:", 0, 0,
CMD_TARGET_SESSION_USAGE,
0,
NULL,
NULL,
cmd_has_session_exec
};
int
cmd_has_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
if (ptr != NULL) { struct args *args = self->args;
memset(ptr, 0, size);
free(ptr); if (cmd_find_session(ctx, args_get(args, 't'), 0) == NULL)
} return (-1);
return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -20,7 +20,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -29,174 +28,95 @@
* Executes a tmux command if a shell command returns true or false. * Executes a tmux command if a shell command returns true or false.
*/ */
static enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmdq_item *); int cmd_if_shell_exec(struct cmd *, struct cmd_ctx *);
static enum cmd_retval cmd_if_shell_error(struct cmdq_item *, void *); void cmd_if_shell_callback(struct job *);
static void cmd_if_shell_callback(struct job *); void cmd_if_shell_free(void *);
static void cmd_if_shell_free(void *);
const struct cmd_entry cmd_if_shell_entry = { const struct cmd_entry cmd_if_shell_entry = {
.name = "if-shell", "if-shell", "if",
.alias = "if", "", 2, 3,
"shell-command command [command]",
.args = { "bFt:", 2, 3 }, 0,
.usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command " NULL,
"[command]", NULL,
cmd_if_shell_exec
.tflag = CMD_PANE_CANFAIL,
.flags = 0,
.exec = cmd_if_shell_exec
}; };
struct cmd_if_shell_data { struct cmd_if_shell_data {
char *file; char *cmd_if;
u_int line; char *cmd_else;
struct cmd_ctx ctx;
char *cmd_if;
char *cmd_else;
struct client *client;
struct cmdq_item *item;
struct mouse_event mouse;
}; };
static enum cmd_retval int
cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item) cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_if_shell_data *cdata; struct cmd_if_shell_data *cdata;
char *shellcmd, *cmd, *cause; const char *shellcmd = args->argv[0];
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
struct client *c = item->state.c;
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct window_pane *wp = item->state.tflag.wp;
const char *cwd;
if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
else if (s != NULL)
cwd = s->cwd;
else
cwd = NULL;
shellcmd = format_single(item, args->argv[0], c, s, wl, wp);
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);
cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);
if (cmdlist == NULL) {
if (cause != NULL) {
cmdq_error(item, "%s", cause);
free(cause);
}
return (CMD_RETURN_ERROR);
}
new_item = cmdq_get_command(cmdlist, NULL, &item->mouse, 0);
cmdq_insert_after(item, new_item);
cmd_list_free(cmdlist);
return (CMD_RETURN_NORMAL);
}
cdata = xcalloc(1, sizeof *cdata);
if (self->file != NULL) {
cdata->file = xstrdup(self->file);
cdata->line = self->line;
}
cdata = xmalloc(sizeof *cdata);
cdata->cmd_if = xstrdup(args->argv[1]); cdata->cmd_if = xstrdup(args->argv[1]);
if (args->argc == 3) if (args->argc == 3)
cdata->cmd_else = xstrdup(args->argv[2]); cdata->cmd_else = xstrdup(args->argv[2]);
else else
cdata->cmd_else = NULL; cdata->cmd_else = NULL;
memcpy(&cdata->ctx, ctx, sizeof cdata->ctx);
cdata->client = item->client; if (ctx->cmdclient != NULL)
cdata->client->references++; ctx->cmdclient->references++;
if (ctx->curclient != NULL)
ctx->curclient->references++;
if (!args_has(args, 'b')) job_run(shellcmd, cmd_if_shell_callback, cmd_if_shell_free, cdata);
cdata->item = item;
else
cdata->item = NULL;
memcpy(&cdata->mouse, &item->mouse, sizeof cdata->mouse);
job_run(shellcmd, s, cwd, cmd_if_shell_callback, cmd_if_shell_free, return (1); /* don't let client exit */
cdata);
free(shellcmd);
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
} }
static enum cmd_retval void
cmd_if_shell_error(struct cmdq_item *item, void *data)
{
char *error = data;
cmdq_error(item, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static void
cmd_if_shell_callback(struct job *job) cmd_if_shell_callback(struct job *job)
{ {
struct cmd_if_shell_data *cdata = job->data; struct cmd_if_shell_data *cdata = job->data;
struct client *c = cdata->client; struct cmd_ctx *ctx = &cdata->ctx;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmdq_item *new_item; char *cause, *cmd;
char *cause, *cmd, *file = cdata->file;
u_int line = cdata->line;
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) {
cmd = cdata->cmd_else; cmd = cdata->cmd_else;
else if (cmd == NULL)
return;
} else
cmd = cdata->cmd_if; cmd = cdata->cmd_if;
if (cmd == NULL) if (cmd_string_parse(cmd, &cmdlist, &cause) != 0) {
goto out; if (cause != NULL) {
ctx->error(ctx, "%s", cause);
cmdlist = cmd_string_parse(cmd, file, line, &cause); xfree(cause);
if (cmdlist == NULL) { }
if (cause != NULL) return;
new_item = cmdq_get_callback(cmd_if_shell_error, cause);
else
new_item = NULL;
} else {
new_item = cmdq_get_command(cmdlist, NULL, &cdata->mouse, 0);
cmd_list_free(cmdlist);
} }
if (new_item != NULL) { cmd_list_exec(cmdlist, ctx);
if (cdata->item == NULL) cmd_list_free(cmdlist);
cmdq_append(c, new_item);
else
cmdq_insert_after(cdata->item, new_item);
}
out:
if (cdata->item != NULL)
cdata->item->flags &= ~CMDQ_WAITING;
} }
static void void
cmd_if_shell_free(void *data) cmd_if_shell_free(void *data)
{ {
struct cmd_if_shell_data *cdata = data; struct cmd_if_shell_data *cdata = data;
struct cmd_ctx *ctx = &cdata->ctx;
struct msg_exit_data exitdata;
server_client_unref(cdata->client); if (ctx->cmdclient != NULL) {
ctx->cmdclient->references--;
exitdata.retcode = ctx->cmdclient->retcode;
ctx->cmdclient->flags |= CLIENT_EXIT;
}
if (ctx->curclient != NULL)
ctx->curclient->references--;
free(cdata->cmd_else); if (cdata->cmd_else != NULL)
free(cdata->cmd_if); xfree(cdata->cmd_else);
xfree(cdata->cmd_if);
free(cdata->file); xfree(cdata);
free(cdata);
} }

View File

@@ -1,8 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2011 George Nachman <tmux@georgester.com> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -25,41 +24,38 @@
#include "tmux.h" #include "tmux.h"
/* /*
* Join or move a pane into another (like split/swap/kill). * Join a pane into another (like split/swap/kill).
*/ */
static enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmdq_item *); void cmd_join_pane_key_binding(struct cmd *, int);
int cmd_join_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_join_pane_entry = { const struct cmd_entry cmd_join_pane_entry = {
.name = "join-pane", "join-pane", "joinp",
.alias = "joinp", "dhvp:l:s:t:", 0, 0,
"[-dhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]",
.args = { "bdhvp:l:s:t:", 0, 0 }, 0,
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE, cmd_join_pane_key_binding,
NULL,
.sflag = CMD_PANE_MARKED, cmd_join_pane_exec
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_join_pane_exec
}; };
const struct cmd_entry cmd_move_pane_entry = { void
.name = "move-pane", cmd_join_pane_key_binding(struct cmd *self, int key)
.alias = "movep", {
switch (key) {
case '%':
self->args = args_create(0);
args_set(self->args, 'h', NULL);
break;
default:
self->args = args_create(0);
break;
}
}
.args = { "bdhvp:l:s:t:", 0, 0 }, int
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE, cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
.sflag = CMD_PANE,
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_join_pane_exec
};
static enum cmd_retval
cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *dst_s; struct session *dst_s;
@@ -70,32 +66,21 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
int size, percentage, dst_idx; int size, percentage, dst_idx;
enum layout_type type; enum layout_type type;
struct layout_cell *lc; struct layout_cell *lc;
int not_same_window;
if (self->entry == &cmd_join_pane_entry) dst_wl = cmd_find_pane(ctx, args_get(args, 't'), &dst_s, &dst_wp);
not_same_window = 1; if (dst_wl == NULL)
else return (-1);
not_same_window = 0;
dst_s = item->state.tflag.s;
dst_wl = item->state.tflag.wl;
dst_wp = item->state.tflag.wp;
dst_w = dst_wl->window; dst_w = dst_wl->window;
dst_idx = dst_wl->idx; dst_idx = dst_wl->idx;
server_unzoom_window(dst_w);
src_wl = item->state.sflag.wl; src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp);
src_wp = item->state.sflag.wp; if (src_wl == NULL)
return (-1);
src_w = src_wl->window; src_w = src_wl->window;
server_unzoom_window(src_w);
if (not_same_window && src_w == dst_w) { if (src_w == dst_w) {
cmdq_error(item, "can't join a pane to its own window"); ctx->error(ctx, "can't join a pane to its own window");
return (CMD_RETURN_ERROR); return (-1);
}
if (!not_same_window && src_wp == dst_wp) {
cmdq_error(item, "source and target panes must be different");
return (CMD_RETURN_ERROR);
} }
type = LAYOUT_TOPBOTTOM; type = LAYOUT_TOPBOTTOM;
@@ -106,33 +91,40 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'l')) { if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause); size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) { if (cause != NULL) {
cmdq_error(item, "size %s", cause); ctx->error(ctx, "size %s", cause);
free(cause); xfree(cause);
return (CMD_RETURN_ERROR); return (-1);
} }
} else if (args_has(args, 'p')) { } else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, 100, &cause); percentage = args_strtonum(args, 'p', 0, 100, &cause);
if (cause != NULL) { if (cause != NULL) {
cmdq_error(item, "percentage %s", cause); ctx->error(ctx, "percentage %s", cause);
free(cause); xfree(cause);
return (CMD_RETURN_ERROR); return (-1);
} }
if (type == LAYOUT_TOPBOTTOM) if (type == LAYOUT_TOPBOTTOM)
size = (dst_wp->sy * percentage) / 100; size = (dst_wp->sy * percentage) / 100;
else else
size = (dst_wp->sx * percentage) / 100; size = (dst_wp->sx * percentage) / 100;
} }
lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b'), 0);
if (lc == NULL) { if ((lc = layout_split_pane(dst_wp, type, size)) == NULL) {
cmdq_error(item, "create pane failed: pane too small"); ctx->error(ctx, "create pane failed: pane too small");
return (CMD_RETURN_ERROR); return (-1);
} }
layout_close_pane(src_wp); layout_close_pane(src_wp);
window_lost_pane(src_w, src_wp); if (src_w->active == src_wp) {
src_w->active = TAILQ_PREV(src_wp, window_panes, entry);
if (src_w->active == NULL)
src_w->active = TAILQ_NEXT(src_wp, entry);
}
TAILQ_REMOVE(&src_w->panes, src_wp, entry); TAILQ_REMOVE(&src_w->panes, src_wp, entry);
if (window_count_panes(src_w) == 0)
server_kill_window(src_w);
src_wp->window = dst_w; src_wp->window = dst_w;
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry); TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
layout_assign_pane(lc, src_wp); layout_assign_pane(lc, src_wp);
@@ -149,11 +141,5 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
} else } else
server_status_session(dst_s); server_status_session(dst_s);
if (window_count_panes(src_w) == 0) return (0);
server_kill_window(src_w);
else
notify_window("window-layout-changed", src_w);
notify_window("window-layout-changed", dst_w);
return (CMD_RETURN_NORMAL);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -26,47 +26,50 @@
* Kill pane. * Kill pane.
*/ */
static enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmdq_item *); int cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_pane_entry = { const struct cmd_entry cmd_kill_pane_entry = {
.name = "kill-pane", "kill-pane", "killp",
.alias = "killp", "at:", 0, 0,
"[-a] " CMD_TARGET_PANE_USAGE,
.args = { "at:", 0, 0 }, 0,
.usage = "[-a] " CMD_TARGET_PANE_USAGE, NULL,
NULL,
.tflag = CMD_PANE, cmd_kill_pane_exec
.flags = 0,
.exec = cmd_kill_pane_exec
}; };
static enum cmd_retval int
cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct winlink *wl = item->state.tflag.wl; struct args *args = self->args;
struct window_pane *loopwp, *tmpwp, *wp = item->state.tflag.wp; struct winlink *wl;
struct window_pane *loopwp, *nextwp, *wp;
server_unzoom_window(wl->window); if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL)
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);
}
server_redraw_window(wl->window);
return (CMD_RETURN_NORMAL);
}
if (window_count_panes(wl->window) == 1) { if (window_count_panes(wl->window) == 1) {
/* Only one pane, kill the window. */
server_kill_window(wl->window); server_kill_window(wl->window);
recalculate_sizes(); recalculate_sizes();
return (0);
}
if (args_has(self->args, 'a')) {
loopwp = TAILQ_FIRST(&wl->window->panes);
while (loopwp != NULL) {
nextwp = TAILQ_NEXT(loopwp, entry);
if (loopwp != wp) {
layout_close_pane(loopwp);
window_remove_pane(wl->window, loopwp);
}
loopwp = nextwp;
}
} else { } else {
layout_close_pane(wp); 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); server_redraw_window(wl->window);
return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -27,35 +27,23 @@
* Kill the server and do nothing else. * Kill the server and do nothing else.
*/ */
static enum cmd_retval cmd_kill_server_exec(struct cmd *, struct cmdq_item *); int cmd_kill_server_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_server_entry = { const struct cmd_entry cmd_kill_server_entry = {
.name = "kill-server", "kill-server", NULL,
.alias = NULL, "", 0, 0,
"",
.args = { "", 0, 0 }, 0,
.usage = "", NULL,
NULL,
.flags = 0, cmd_kill_server_exec
.exec = cmd_kill_server_exec
}; };
const struct cmd_entry cmd_start_server_entry = { /* ARGSUSED */
.name = "start-server", int
.alias = "start", cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
.args = { "", 0, 0 },
.usage = "",
.flags = CMD_STARTSERVER,
.exec = cmd_kill_server_exec
};
static enum cmd_retval
cmd_kill_server_exec(struct cmd *self, __unused struct cmdq_item *item)
{ {
if (self->entry == &cmd_kill_server_entry) kill(getpid(), SIGTERM);
kill(getpid(), SIGTERM);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -27,46 +27,29 @@
* Note this deliberately has no alias to make it hard to hit by accident. * Note this deliberately has no alias to make it hard to hit by accident.
*/ */
static enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmdq_item *); int cmd_kill_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_session_entry = { const struct cmd_entry cmd_kill_session_entry = {
.name = "kill-session", "kill-session", NULL,
.alias = NULL, "t:", 0, 0,
CMD_TARGET_SESSION_USAGE,
.args = { "aCt:", 0, 0 }, 0,
.usage = "[-aC] " CMD_TARGET_SESSION_USAGE, NULL,
NULL,
.tflag = CMD_SESSION, cmd_kill_session_exec
.flags = 0,
.exec = cmd_kill_session_exec
}; };
static enum cmd_retval int
cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item) cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s, *sloop, *stmp; struct session *s;
struct winlink *wl;
s = item->state.tflag.s; if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
return (-1);
if (args_has(args, 'C')) { server_destroy_session(s);
RB_FOREACH(wl, winlinks, &s->windows) { session_destroy(s);
wl->window->flags &= ~WINDOW_ALERTFLAGS;
wl->flags &= ~WINLINK_ALERTFLAGS; return (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);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -24,58 +24,29 @@
* Destroy window. * Destroy window.
*/ */
static enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmdq_item *); int cmd_kill_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_window_entry = { const struct cmd_entry cmd_kill_window_entry = {
.name = "kill-window", "kill-window", "killw",
.alias = "killw", "t:", 0, 0,
CMD_TARGET_WINDOW_USAGE,
.args = { "at:", 0, 0 }, 0,
.usage = "[-a] " CMD_TARGET_WINDOW_USAGE, NULL,
NULL,
.tflag = CMD_WINDOW, cmd_kill_window_exec
.flags = 0,
.exec = cmd_kill_window_exec
}; };
const struct cmd_entry cmd_unlink_window_entry = { int
.name = "unlink-window", cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx)
.alias = "unlinkw",
.args = { "kt:", 0, 0 },
.usage = "[-k] " CMD_TARGET_WINDOW_USAGE,
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_kill_window_exec
};
static enum cmd_retval
cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl, *wl2, *wl3; struct winlink *wl;
struct window *w = wl->window;
struct session *s = item->state.tflag.s;
if (self->entry == &cmd_unlink_window_entry) { if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
if (!args_has(self->args, 'k') && !session_is_linked(s, w)) { return (-1);
cmdq_error(item, "window only linked to one session");
return (CMD_RETURN_ERROR);
}
server_unlink_window(s, wl);
} else {
if (args_has(args, 'a')) {
RB_FOREACH_SAFE(wl2, winlinks, &s->windows, wl3) {
if (wl != wl2)
server_kill_window(wl2->window);
}
} else
server_kill_window(wl->window);
}
server_kill_window(wl->window);
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL);
return (0);
} }

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

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

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -27,45 +26,33 @@
* List paste buffers. * List paste buffers.
*/ */
#define LIST_BUFFERS_TEMPLATE \ int cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *);
"#{buffer_name}: #{buffer_size} bytes: \"#{buffer_sample}\""
static enum cmd_retval cmd_list_buffers_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_list_buffers_entry = { const struct cmd_entry cmd_list_buffers_entry = {
.name = "list-buffers", "list-buffers", "lsb",
.alias = "lsb", "", 0, 0,
"",
.args = { "F:", 0, 0 }, 0,
.usage = "[-F format]", NULL,
NULL,
.flags = CMD_AFTERHOOK, cmd_list_buffers_exec
.exec = cmd_list_buffers_exec
}; };
static enum cmd_retval /* ARGSUSED */
cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item) int
cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args;
struct paste_buffer *pb; struct paste_buffer *pb;
struct format_tree *ft; u_int idx;
char *line; char *tmp;
const char *template;
if ((template = args_get(args, 'F')) == NULL) idx = 0;
template = LIST_BUFFERS_TEMPLATE; while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) {
tmp = paste_print(pb, 50);
pb = NULL; ctx->print(ctx,
while ((pb = paste_walk(pb)) != NULL) { "%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp);
ft = format_create(item, FORMAT_NONE, 0); xfree(tmp);
format_defaults_paste_buffer(ft, pb);
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
format_free(ft);
} }
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
@@ -28,62 +27,64 @@
* List all clients. * List all clients.
*/ */
#define LIST_CLIENTS_TEMPLATE \ int cmd_list_clients_exec(struct cmd *, struct cmd_ctx *);
"#{client_name}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}]" \
"#{?client_utf8, (utf8),} #{?client_readonly, (ro),}"
static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_list_clients_entry = { const struct cmd_entry cmd_list_clients_entry = {
.name = "list-clients", "list-clients", "lsc",
.alias = "lsc", "F:t:", 0, 0,
"[-F format] " CMD_TARGET_SESSION_USAGE,
.args = { "F:t:", 0, 0 }, CMD_READONLY,
.usage = "[-F format] " CMD_TARGET_SESSION_USAGE, NULL,
NULL,
.tflag = CMD_SESSION, cmd_list_clients_exec
.flags = CMD_READONLY|CMD_AFTERHOOK,
.exec = cmd_list_clients_exec
}; };
static enum cmd_retval /* ARGSUSED */
cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item) int
cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c;
struct session *s; struct session *s;
struct format_tree *ft; struct format_tree *ft;
const char *template; const char *template;
u_int idx; u_int i;
char *line; char *line;
if (args_has(args, 't')) if (args_has(args, 't')) {
s = item->state.tflag.s; s = cmd_find_session(ctx, args_get(args, 't'), 0);
else if (s == NULL)
return (-1);
} else
s = NULL; s = NULL;
if ((template = args_get(args, 'F')) == NULL) template = args_get(args, 'F');
template = LIST_CLIENTS_TEMPLATE; if (template == NULL) {
template = "#{client_tty}: #{session_name} "
idx = 0; "[#{client_width}x#{client_height} #{client_termname}]"
TAILQ_FOREACH(c, &clients, entry) { "#{?client_utf8, (utf8),}"
if (c->session == NULL || (s != NULL && s != c->session)) "#{?client_readonly, (ro),}";
continue;
ft = format_create(item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", idx);
format_defaults(ft, c, NULL, NULL, NULL);
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
format_free(ft);
idx++;
} }
return (CMD_RETURN_NORMAL); for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
continue;
if (s != NULL && s != c->session)
continue;
ft = format_create();
format_add(ft, "line", "%u", i);
format_session(ft, c->session);
format_client(ft, c);
line = format_expand(ft, template);
ctx->print(ctx, "%s", line);
xfree(line);
format_free(ft);
}
return (0);
} }

View File

@@ -1,6 +1,7 @@
/* $Id$ */
/* /*
* Copyright (c) 2013 Dagobert Michelsen * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -17,17 +18,32 @@
#include <sys/types.h> #include <sys/types.h>
#include <string.h> #include "tmux.h"
#include <termios.h>
#include "compat.h" /*
* List all commands with usages.
*/
void int cmd_list_commands_exec(struct cmd *, struct cmd_ctx *);
cfmakeraw(struct termios *tio)
const struct cmd_entry cmd_list_commands_entry = {
"list-commands", "lscm",
"", 0, 0,
"",
0,
NULL,
NULL,
cmd_list_commands_exec
};
/* ARGSUSED */
int
cmd_list_commands_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{ {
tio->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); const struct cmd_entry **entryp;
tio->c_oflag &= ~OPOST;
tio->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); for (entryp = cmd_table; *entryp != NULL; entryp++)
tio->c_cflag &= ~(CSIZE|PARENB); ctx->print(ctx, "%s %s", (*entryp)->name, (*entryp)->usage);
tio->c_cflag |= CS8;
return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -27,147 +26,124 @@
* List key bindings. * List key bindings.
*/ */
static enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmdq_item *); int cmd_list_keys_exec(struct cmd *, struct cmd_ctx *);
static enum cmd_retval cmd_list_keys_commands(struct cmd *, int cmd_list_keys_table(struct cmd *, struct cmd_ctx *);
struct cmdq_item *);
const struct cmd_entry cmd_list_keys_entry = { const struct cmd_entry cmd_list_keys_entry = {
.name = "list-keys", "list-keys", "lsk",
.alias = "lsk", "t:", 0, 0,
"[-t key-table]",
.args = { "T:", 0, 0 }, 0,
.usage = "[-T key-table]", NULL,
NULL,
.flags = CMD_STARTSERVER|CMD_AFTERHOOK, cmd_list_keys_exec
.exec = cmd_list_keys_exec
}; };
const struct cmd_entry cmd_list_commands_entry = { int
.name = "list-commands", cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
.alias = "lscm",
.args = { "F:", 0, 0 },
.usage = "[-F format]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_keys_exec
};
static enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct key_table *table;
struct key_binding *bd; struct key_binding *bd;
const char *key, *tablename, *r; const char *key;
char *cp, tmp[BUFSIZ]; char tmp[BUFSIZ], flags[8];
int repeat, width, tablewidth, keywidth; size_t used;
int width, keywidth;
if (self->entry == &cmd_list_commands_entry) if (args_has(args, 't'))
return (cmd_list_keys_commands(self, item)); return (cmd_list_keys_table(self, ctx));
tablename = args_get(args, 'T'); width = 0;
if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(item, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR);
}
repeat = 0; RB_FOREACH(bd, key_bindings, &key_bindings) {
tablewidth = keywidth = 0; key = key_string_lookup_key(bd->key & ~KEYC_PREFIX);
RB_FOREACH(table, key_tables, &key_tables) { if (key == NULL)
if (tablename != NULL && strcmp(table->name, tablename) != 0)
continue; continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
key = key_string_lookup_key(bd->key);
keywidth = strlen(key);
if (!(bd->key & KEYC_PREFIX)) {
if (bd->can_repeat) if (bd->can_repeat)
repeat = 1; keywidth += 4;
width = utf8_cstrwidth(table->name);
if (width > tablewidth)
tablewidth = width;
width = utf8_cstrwidth(key);
if (width > keywidth)
keywidth = width;
}
}
RB_FOREACH(table, key_tables, &key_tables) {
if (tablename != NULL && strcmp(table->name, tablename) != 0)
continue;
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 else
r = " "; keywidth += 3;
xsnprintf(tmp, sizeof tmp, "%s-T ", r); } else if (bd->can_repeat)
keywidth += 3;
if (keywidth > width)
width = keywidth;
}
cp = utf8_padcstr(table->name, tablewidth); RB_FOREACH(bd, key_bindings, &key_bindings) {
strlcat(tmp, cp, sizeof tmp); key = key_string_lookup_key(bd->key & ~KEYC_PREFIX);
strlcat(tmp, " ", sizeof tmp); if (key == NULL)
free(cp); continue;
cp = utf8_padcstr(key, keywidth); *flags = '\0';
strlcat(tmp, cp, sizeof tmp); if (!(bd->key & KEYC_PREFIX)) {
strlcat(tmp, " ", sizeof tmp); if (bd->can_repeat)
free(cp); xsnprintf(flags, sizeof flags, "-rn ");
else
xsnprintf(flags, sizeof flags, "-n ");
} else if (bd->can_repeat)
xsnprintf(flags, sizeof flags, "-r ");
cp = cmd_list_print(bd->cmdlist); used = xsnprintf(tmp, sizeof tmp, "%s%*s ",
strlcat(tmp, cp, sizeof tmp); flags, (int) (width - strlen(flags)), key);
free(cp); if (used >= sizeof tmp)
continue;
cmdq_print(item, "bind-key %s", tmp); cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used);
ctx->print(ctx, "bind-key %s", tmp);
}
return (0);
}
int
cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
const char *tablename;
const struct mode_key_table *mtab;
struct mode_key_binding *mbind;
const char *key, *cmdstr, *mode;
int width, keywidth, any_mode;
tablename = args_get(args, 't');
if ((mtab = mode_key_findtable(tablename)) == NULL) {
ctx->error(ctx, "unknown key table: %s", tablename);
return (-1);
}
width = 0;
any_mode = 0;
RB_FOREACH(mbind, mode_key_tree, mtab->tree) {
key = key_string_lookup_key(mbind->key);
if (key == NULL)
continue;
if (mbind->mode != 0)
any_mode = 1;
keywidth = strlen(key);
if (keywidth > width)
width = keywidth;
}
RB_FOREACH(mbind, mode_key_tree, mtab->tree) {
key = key_string_lookup_key(mbind->key);
if (key == NULL)
continue;
mode = "";
if (mbind->mode != 0)
mode = "c";
cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd);
if (cmdstr != NULL) {
ctx->print(ctx, "bind-key -%st %s%s %*s %s",
mode, any_mode && *mode == '\0' ? " " : "",
mtab->name, (int) width, key, cmdstr);
} }
} }
return (CMD_RETURN_NORMAL); return (0);
}
static enum cmd_retval
cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
const struct cmd_entry **entryp;
const struct cmd_entry *entry;
struct format_tree *ft;
const char *template, *s;
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(item, FORMAT_NONE, 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)
s = entry->alias;
else
s = "";
format_add(ft, "command_list_alias", "%s", s);
if (entry->usage != NULL)
s = entry->usage;
else
s = "";
format_add(ft, "command_list_usage", "%s", s);
line = format_expand(ft, template);
if (*line != '\0')
cmdq_print(item, "%s", line);
free(line);
}
format_free(ft);
return (CMD_RETURN_NORMAL);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -26,66 +26,70 @@
* List panes on given window. * List panes on given window.
*/ */
static enum cmd_retval cmd_list_panes_exec(struct cmd *, struct cmdq_item *); int cmd_list_panes_exec(struct cmd *, struct cmd_ctx *);
static void cmd_list_panes_server(struct cmd *, struct cmdq_item *); void cmd_list_panes_server(struct cmd *, struct cmd_ctx *);
static void cmd_list_panes_session(struct cmd *, struct session *, void cmd_list_panes_session(
struct cmdq_item *, int); struct cmd *, struct session *, struct cmd_ctx *, int);
static void cmd_list_panes_window(struct cmd *, struct session *, void cmd_list_panes_window(struct cmd *,
struct winlink *, struct cmdq_item *, int); struct session *, struct winlink *, struct cmd_ctx *, int);
const struct cmd_entry cmd_list_panes_entry = { const struct cmd_entry cmd_list_panes_entry = {
.name = "list-panes", "list-panes", "lsp",
.alias = "lsp", "asF:t:", 0, 0,
"[-as] [-F format] [-t target]",
.args = { "asF:t:", 0, 0 }, 0,
.usage = "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE, NULL,
NULL,
.tflag = CMD_WINDOW, cmd_list_panes_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_list_panes_exec
}; };
static enum cmd_retval int
cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item) cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s = item->state.tflag.s; struct session *s;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl;
if (args_has(args, 'a')) if (args_has(args, 'a'))
cmd_list_panes_server(self, item); cmd_list_panes_server(self, ctx);
else if (args_has(args, 's')) else if (args_has(args, 's')) {
cmd_list_panes_session(self, s, item, 1); s = cmd_find_session(ctx, args_get(args, 't'), 0);
else if (s == NULL)
cmd_list_panes_window(self, s, wl, item, 0); return (-1);
cmd_list_panes_session(self, s, ctx, 1);
} else {
wl = cmd_find_window(ctx, args_get(args, 't'), &s);
if (wl == NULL)
return (-1);
cmd_list_panes_window(self, s, wl, ctx, 0);
}
return (CMD_RETURN_NORMAL); return (0);
} }
static void void
cmd_list_panes_server(struct cmd *self, struct cmdq_item *item) cmd_list_panes_server(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct session *s; struct session *s;
RB_FOREACH(s, sessions, &sessions) RB_FOREACH(s, sessions, &sessions)
cmd_list_panes_session(self, s, item, 2); cmd_list_panes_session(self, s, ctx, 2);
} }
static void void
cmd_list_panes_session(struct cmd *self, struct session *s, cmd_list_panes_session(
struct cmdq_item *item, int type) struct cmd *self, struct session *s, struct cmd_ctx *ctx, int type)
{ {
struct winlink *wl; struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows) RB_FOREACH(wl, winlinks, &s->windows)
cmd_list_panes_window(self, s, wl, item, type); cmd_list_panes_window(self, s, wl, ctx, type);
} }
static void void
cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl, cmd_list_panes_window(struct cmd *self,
struct cmdq_item *item, int type) struct session *s, struct winlink *wl, struct cmd_ctx *ctx, int type)
{ {
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp; struct window_pane *wp;
@@ -112,9 +116,9 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
"#{?pane_active, (active),}#{?pane_dead, (dead),}"; "#{?pane_active, (active),}#{?pane_dead, (dead),}";
break; break;
case 2: case 2:
template = "#{session_name}:#{window_index}." template = "#{session_name}:#{window_index}.#{pane_index}: "
"#{pane_index}: [#{pane_width}x#{pane_height}] " "[#{pane_width}x#{pane_height}] [history "
"[history #{history_size}/#{history_limit}, " "#{history_size}/#{history_limit}, "
"#{history_bytes} bytes] #{pane_id}" "#{history_bytes} bytes] #{pane_id}"
"#{?pane_active, (active),}#{?pane_dead, (dead),}"; "#{?pane_active, (active),}#{?pane_dead, (dead),}";
break; break;
@@ -123,13 +127,15 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
n = 0; n = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) { TAILQ_FOREACH(wp, &wl->window->panes, entry) {
ft = format_create(item, FORMAT_NONE, 0); ft = format_create();
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, wp); format_session(ft, s);
format_winlink(ft, s, wl);
format_window_pane(ft, wp);
line = format_expand(ft, template); line = format_expand(ft, template);
cmdq_print(item, "%s", line); ctx->print(ctx, "%s", line);
free(line); xfree(line);
format_free(ft); format_free(ft);
n++; n++;

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
@@ -28,30 +27,20 @@
* List all sessions. * List all sessions.
*/ */
#define LIST_SESSIONS_TEMPLATE \ int cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *);
"#{session_name}: #{session_windows} windows " \
"(created #{t:session_created}) " \
"[#{session_width}x#{session_height}]" \
"#{?session_grouped, (group ,}" \
"#{session_group}#{?session_grouped,),}" \
"#{?session_attached, (attached),}"
static enum cmd_retval cmd_list_sessions_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_list_sessions_entry = { const struct cmd_entry cmd_list_sessions_entry = {
.name = "list-sessions", "list-sessions", "ls",
.alias = "ls", "F:", 0, 0,
"[-F format]",
.args = { "F:", 0, 0 }, 0,
.usage = "[-F format]", NULL,
NULL,
.flags = CMD_AFTERHOOK, cmd_list_sessions_exec
.exec = cmd_list_sessions_exec
}; };
static enum cmd_retval int
cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item) cmd_list_sessions_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s; struct session *s;
@@ -60,22 +49,28 @@ cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
const char *template; const char *template;
char *line; char *line;
if ((template = args_get(args, 'F')) == NULL) template = args_get(args, 'F');
template = LIST_SESSIONS_TEMPLATE; if (template == NULL) {
template = "#{session_name}: #{session_windows} windows "
"(created #{session_created_string}) [#{session_width}x"
"#{session_height}]#{?session_grouped, (group ,}"
"#{session_group}#{?session_grouped,),}"
"#{?session_attached, (attached),}";
}
n = 0; n = 0;
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
ft = format_create(item, FORMAT_NONE, 0); ft = format_create();
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, NULL, NULL); format_session(ft, s);
line = format_expand(ft, template); line = format_expand(ft, template);
cmdq_print(item, "%s", line); ctx->print(ctx, "%s", line);
free(line); xfree(line);
format_free(ft); format_free(ft);
n++; n++;
} }
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -27,62 +26,52 @@
* List windows on given session. * List windows on given session.
*/ */
#define LIST_WINDOWS_TEMPLATE \ int cmd_list_windows_exec(struct cmd *, struct cmd_ctx *);
"#{window_index}: #{window_name}#{window_flags} " \
"(#{window_panes} panes) " \
"[#{window_width}x#{window_height}] " \
"[layout #{window_layout}] #{window_id}" \
"#{?window_active, (active),}";
#define LIST_WINDOWS_WITH_SESSION_TEMPLATE \
"#{session_name}:" \
"#{window_index}: #{window_name}#{window_flags} " \
"(#{window_panes} panes) " \
"[#{window_width}x#{window_height}] "
static enum cmd_retval cmd_list_windows_exec(struct cmd *, struct cmdq_item *); void cmd_list_windows_server(struct cmd *, struct cmd_ctx *);
void cmd_list_windows_session(
static void cmd_list_windows_server(struct cmd *, struct cmdq_item *); struct cmd *, struct session *, struct cmd_ctx *, int);
static void cmd_list_windows_session(struct cmd *, struct session *,
struct cmdq_item *, int);
const struct cmd_entry cmd_list_windows_entry = { const struct cmd_entry cmd_list_windows_entry = {
.name = "list-windows", "list-windows", "lsw",
.alias = "lsw", "aF:t:", 0, 0,
"[-a] [-F format] " CMD_TARGET_SESSION_USAGE,
.args = { "F:at:", 0, 0 }, 0,
.usage = "[-a] [-F format] " CMD_TARGET_SESSION_USAGE, NULL,
NULL,
.tflag = CMD_SESSION, cmd_list_windows_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_list_windows_exec
}; };
static enum cmd_retval int
cmd_list_windows_exec(struct cmd *self, struct cmdq_item *item) cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s;
if (args_has(args, 'a')) if (args_has(args, 'a'))
cmd_list_windows_server(self, item); cmd_list_windows_server(self, ctx);
else else {
cmd_list_windows_session(self, item->state.tflag.s, item, 0); s = cmd_find_session(ctx, args_get(args, 't'), 0);
if (s == NULL)
return (-1);
cmd_list_windows_session(self, s, ctx, 0);
}
return (CMD_RETURN_NORMAL); return (0);
} }
static void void
cmd_list_windows_server(struct cmd *self, struct cmdq_item *item) cmd_list_windows_server(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct session *s; struct session *s;
RB_FOREACH(s, sessions, &sessions) RB_FOREACH(s, sessions, &sessions)
cmd_list_windows_session(self, s, item, 1); cmd_list_windows_session(self, s, ctx, 1);
} }
static void void
cmd_list_windows_session(struct cmd *self, struct session *s, cmd_list_windows_session(
struct cmdq_item *item, int type) struct cmd *self, struct session *s, struct cmd_ctx *ctx, int type)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl; struct winlink *wl;
@@ -95,23 +84,32 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
if (template == NULL) { if (template == NULL) {
switch (type) { switch (type) {
case 0: case 0:
template = LIST_WINDOWS_TEMPLATE; template = "#{window_index}: "
"#{window_name} "
"[#{window_width}x#{window_height}] "
"[layout #{window_layout}]"
"#{?window_active, (active),}";
break; break;
case 1: case 1:
template = LIST_WINDOWS_WITH_SESSION_TEMPLATE; template = "#{session_name}:#{window_index}: "
"#{window_name} "
"[#{window_width}x#{window_height}] "
"[layout #{window_layout}]"
"#{?window_active, (active),}";
break; break;
} }
} }
n = 0; n = 0;
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
ft = format_create(item, FORMAT_NONE, 0); ft = format_create();
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, NULL); format_session(ft, s);
format_winlink(ft, s, wl);
line = format_expand(ft, template); line = format_expand(ft, template);
cmdq_print(item, "%s", line); ctx->print(ctx, "%s", line);
free(line); xfree(line);
format_free(ft); format_free(ft);
n++; n++;

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,14 +18,12 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
struct cmd_list * struct cmd_list *
cmd_list_parse(int argc, char **argv, const char *file, u_int line, cmd_list_parse(int argc, char **argv, char **cause)
char **cause)
{ {
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd *cmd; struct cmd *cmd;
@@ -35,7 +33,7 @@ cmd_list_parse(int argc, char **argv, const char *file, u_int line,
copy_argv = cmd_copy_argv(argc, argv); copy_argv = cmd_copy_argv(argc, argv);
cmdlist = xcalloc(1, sizeof *cmdlist); cmdlist = xmalloc(sizeof *cmdlist);
cmdlist->references = 1; cmdlist->references = 1;
TAILQ_INIT(&cmdlist->list); TAILQ_INIT(&cmdlist->list);
@@ -56,7 +54,7 @@ cmd_list_parse(int argc, char **argv, const char *file, u_int line,
if (arglen != 1) if (arglen != 1)
new_argc++; new_argc++;
cmd = cmd_parse(new_argc, new_argv, file, line, cause); cmd = cmd_parse(new_argc, new_argv, cause);
if (cmd == NULL) if (cmd == NULL)
goto bad; goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry); TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
@@ -65,8 +63,7 @@ cmd_list_parse(int argc, char **argv, const char *file, u_int line,
} }
if (lastsplit != argc) { if (lastsplit != argc) {
cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit, cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit, cause);
file, line, cause);
if (cmd == NULL) if (cmd == NULL)
goto bad; goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry); TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
@@ -81,46 +78,73 @@ bad:
return (NULL); return (NULL);
} }
int
cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx)
{
struct cmd *cmd;
int n, retval;
retval = 0;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
if ((n = cmd_exec(cmd, ctx)) == -1)
return (-1);
/*
* A 1 return value means the command client is being attached
* (sent MSG_READY).
*/
if (n == 1) {
retval = 1;
/*
* The command client has been attached, so mangle the
* context to treat any following commands as if they
* were called from inside.
*/
if (ctx->curclient == NULL) {
ctx->curclient = ctx->cmdclient;
ctx->cmdclient = NULL;
ctx->error = key_bindings_error;
ctx->print = key_bindings_print;
ctx->info = key_bindings_info;
}
}
}
return (retval);
}
void void
cmd_list_free(struct cmd_list *cmdlist) cmd_list_free(struct cmd_list *cmdlist)
{ {
struct cmd *cmd, *cmd1; struct cmd *cmd;
if (--cmdlist->references != 0) if (--cmdlist->references != 0)
return; return;
TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) { while (!TAILQ_EMPTY(&cmdlist->list)) {
cmd = TAILQ_FIRST(&cmdlist->list);
TAILQ_REMOVE(&cmdlist->list, cmd, qentry); TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
args_free(cmd->args); cmd_free(cmd);
free(cmd->file);
free(cmd);
} }
xfree(cmdlist);
free(cmdlist);
} }
char * size_t
cmd_list_print(struct cmd_list *cmdlist) cmd_list_print(struct cmd_list *cmdlist, char *buf, size_t len)
{ {
struct cmd *cmd; struct cmd *cmd;
char *buf, *this; size_t off;
size_t len;
len = 1;
buf = xcalloc(1, len);
off = 0;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
this = cmd_print(cmd); if (off >= len)
break;
len += strlen(this) + 3; off += cmd_print(cmd, buf + off, len - off);
buf = xrealloc(buf, len); if (off >= len)
break;
strlcat(buf, this, len);
if (TAILQ_NEXT(cmd, qentry) != NULL) if (TAILQ_NEXT(cmd, qentry) != NULL)
strlcat(buf, " ; ", len); off += xsnprintf(buf + off, len - off, " ; ");
free(this);
} }
return (off);
return (buf);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -19,7 +19,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -31,66 +30,86 @@
* Loads a paste buffer from a file. * Loads a paste buffer from a file.
*/ */
static enum cmd_retval cmd_load_buffer_exec(struct cmd *, struct cmdq_item *); int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_load_buffer_callback(struct client *, void *);
static void cmd_load_buffer_callback(struct client *, int, void *);
const struct cmd_entry cmd_load_buffer_entry = { const struct cmd_entry cmd_load_buffer_entry = {
.name = "load-buffer", "load-buffer", "loadb",
.alias = "loadb", "b:", 1, 1,
CMD_BUFFER_USAGE " path",
.args = { "b:", 1, 1 }, 0,
.usage = CMD_BUFFER_USAGE " path", NULL,
NULL,
.flags = CMD_AFTERHOOK, cmd_load_buffer_exec
.exec = cmd_load_buffer_exec
}; };
struct cmd_load_buffer_data { int
struct cmdq_item *item; cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
char *bufname;
};
static enum cmd_retval
cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_load_buffer_data *cdata; struct client *c = ctx->cmdclient;
struct client *c = item->client; struct session *s;
FILE *f; FILE *f;
const char *path, *bufname; const char *path, *newpath, *wd;
char *pdata, *new_pdata, *cause, *file; char *pdata, *new_pdata, *cause;
size_t psize; size_t psize;
int ch, error; u_int limit;
int ch, buffer;
int *buffer_ptr;
bufname = NULL; if (!args_has(args, 'b'))
if (args_has(args, 'b')) buffer = -1;
bufname = args_get(args, 'b'); else {
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
ctx->error(ctx, "buffer %s", cause);
xfree(cause);
return (-1);
}
}
path = args->argv[0]; path = args->argv[0];
if (strcmp(path, "-") == 0) { if (strcmp(path, "-") == 0) {
cdata = xcalloc(1, sizeof *cdata); if (c == NULL) {
cdata->item = item; ctx->error(ctx, "%s: can't read from stdin", path);
return (-1);
if (bufname != NULL)
cdata->bufname = xstrdup(bufname);
error = server_set_stdin_callback(c, cmd_load_buffer_callback,
cdata, &cause);
if (error != 0) {
cmdq_error(item, "%s: %s", path, cause);
free(cause);
return (CMD_RETURN_ERROR);
} }
return (CMD_RETURN_WAIT); if (c->flags & CLIENT_TERMINAL) {
ctx->error(ctx, "%s: stdin is a tty", path);
return (-1);
}
if (c->stdin_fd == -1) {
ctx->error(ctx, "%s: can't read from stdin", path);
return (-1);
}
buffer_ptr = xmalloc(sizeof *buffer_ptr);
*buffer_ptr = buffer;
c->stdin_data = buffer_ptr;
c->stdin_callback = cmd_load_buffer_callback;
c->references++;
bufferevent_enable(c->stdin_event, EV_READ);
return (1);
} }
file = server_client_get_path(c, path); if (c != NULL)
f = fopen(file, "rb"); wd = c->cwd;
if (f == NULL) { else if ((s = cmd_current_session(ctx, 0)) != NULL) {
cmdq_error(item, "%s: %s", file, strerror(errno)); wd = options_get_string(&s->options, "default-path");
free(file); if (*wd == '\0')
return (CMD_RETURN_ERROR); wd = s->cwd;
} else
wd = NULL;
if (wd != NULL && *wd != '\0') {
newpath = get_full_path(wd, path);
if (newpath != NULL)
path = newpath;
}
if ((f = fopen(path, "rb")) == NULL) {
ctx->error(ctx, "%s: %s", path, strerror(errno));
return (-1);
} }
pdata = NULL; pdata = NULL;
@@ -98,76 +117,73 @@ cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
while ((ch = getc(f)) != EOF) { while ((ch = getc(f)) != EOF) {
/* Do not let the server die due to memory exhaustion. */ /* Do not let the server die due to memory exhaustion. */
if ((new_pdata = realloc(pdata, psize + 2)) == NULL) { if ((new_pdata = realloc(pdata, psize + 2)) == NULL) {
cmdq_error(item, "realloc error: %s", strerror(errno)); ctx->error(ctx, "realloc error: %s", strerror(errno));
goto error; goto error;
} }
pdata = new_pdata; pdata = new_pdata;
pdata[psize++] = ch; pdata[psize++] = ch;
} }
if (ferror(f)) { if (ferror(f)) {
cmdq_error(item, "%s: read error", file); ctx->error(ctx, "%s: read error", path);
goto error; goto error;
} }
if (pdata != NULL) if (pdata != NULL)
pdata[psize] = '\0'; pdata[psize] = '\0';
fclose(f); fclose(f);
free(file);
if (paste_set(pdata, psize, bufname, &cause) != 0) { limit = options_get_number(&global_options, "buffer-limit");
cmdq_error(item, "%s", cause); if (buffer == -1) {
free(pdata); paste_add(&global_buffers, pdata, psize, limit);
free(cause); return (0);
return (CMD_RETURN_ERROR); }
if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) {
ctx->error(ctx, "no buffer %d", buffer);
xfree(pdata);
return (-1);
} }
return (CMD_RETURN_NORMAL); return (0);
error: error:
free(pdata); if (pdata != NULL)
xfree(pdata);
if (f != NULL) if (f != NULL)
fclose(f); fclose(f);
return (CMD_RETURN_ERROR); return (-1);
} }
static void void
cmd_load_buffer_callback(struct client *c, int closed, void *data) cmd_load_buffer_callback(struct client *c, void *data)
{ {
struct cmd_load_buffer_data *cdata = data; int *buffer = data;
char *pdata, *cause, *saved; char *pdata;
size_t psize; size_t psize;
u_int limit;
if (!closed) /*
* Event callback has already checked client is not dead and reduced
* its reference count. But tell it to exit.
*/
c->flags |= CLIENT_EXIT;
psize = EVBUFFER_LENGTH(c->stdin_event->input);
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) {
xfree(data);
return; return;
c->stdin_callback = NULL;
server_client_unref(c);
if (c->flags & CLIENT_DEAD)
goto out;
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, cdata->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: bufferevent_read(c->stdin_event, pdata, psize);
cdata->item->flags &= ~CMDQ_WAITING; pdata[psize] = '\0';
free(cdata->bufname); limit = options_get_number(&global_options, "buffer-limit");
free(cdata); if (*buffer == -1)
paste_add(&global_buffers, pdata, psize, limit);
else if (paste_replace(&global_buffers, *buffer, pdata, psize) != 0) {
/* No context so can't use server_client_msg_error. */
evbuffer_add_printf(
c->stderr_event->output, "no buffer %d\n", *buffer);
bufferevent_enable(c->stderr_event, EV_WRITE);
}
xfree(data);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,62 +18,68 @@
#include <sys/types.h> #include <sys/types.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Lock commands. * Lock commands.
*/ */
static enum cmd_retval cmd_lock_server_exec(struct cmd *, struct cmdq_item *); int cmd_lock_server_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_lock_server_entry = { const struct cmd_entry cmd_lock_server_entry = {
.name = "lock-server", "lock-server", "lock",
.alias = "lock", "", 0, 0,
"",
.args = { "", 0, 0 }, 0,
.usage = "", NULL,
NULL,
.flags = CMD_AFTERHOOK, cmd_lock_server_exec
.exec = cmd_lock_server_exec
}; };
const struct cmd_entry cmd_lock_session_entry = { const struct cmd_entry cmd_lock_session_entry = {
.name = "lock-session", "lock-session", "locks",
.alias = "locks", "t:", 0, 0,
CMD_TARGET_SESSION_USAGE,
.args = { "t:", 0, 0 }, 0,
.usage = CMD_TARGET_SESSION_USAGE, NULL,
NULL,
.tflag = CMD_SESSION, cmd_lock_server_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_lock_server_exec
}; };
const struct cmd_entry cmd_lock_client_entry = { const struct cmd_entry cmd_lock_client_entry = {
.name = "lock-client", "lock-client", "lockc",
.alias = "lockc", "t:", 0, 0,
CMD_TARGET_CLIENT_USAGE,
.args = { "t:", 0, 0 }, 0,
.usage = CMD_TARGET_CLIENT_USAGE, NULL,
NULL,
.tflag = CMD_CLIENT, cmd_lock_server_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_lock_server_exec
}; };
static enum cmd_retval /* ARGSUSED */
cmd_lock_server_exec(struct cmd *self, __unused struct cmdq_item *item) int
cmd_lock_server_exec(struct cmd *self, unused struct cmd_ctx *ctx)
{ {
struct args *args = self->args;
struct client *c;
struct session *s;
if (self->entry == &cmd_lock_server_entry) if (self->entry == &cmd_lock_server_entry)
server_lock(); server_lock();
else if (self->entry == &cmd_lock_session_entry) else if (self->entry == &cmd_lock_session_entry) {
server_lock_session(item->state.tflag.s); if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
else return (-1);
server_lock_client(item->state.c); server_lock_session(s);
} else {
if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
return (-1);
server_lock_client(c);
}
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -26,80 +26,41 @@
* Move a window. * Move a window.
*/ */
static enum cmd_retval cmd_move_window_exec(struct cmd *, struct cmdq_item *); int cmd_move_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_move_window_entry = { const struct cmd_entry cmd_move_window_entry = {
.name = "move-window", "move-window", "movew",
.alias = "movew", "dks:t:", 0, 0,
"[-dk] " CMD_SRCDST_WINDOW_USAGE,
.args = { "adkrs:t:", 0, 0 }, 0,
.usage = "[-dkr] " CMD_SRCDST_WINDOW_USAGE, NULL,
NULL,
.sflag = CMD_WINDOW, cmd_move_window_exec
.tflag = CMD_MOVEW_R,
.flags = 0,
.exec = cmd_move_window_exec
}; };
const struct cmd_entry cmd_link_window_entry = { int
.name = "link-window", cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx)
.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
};
static enum cmd_retval
cmd_move_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *src = item->state.sflag.s; struct session *src, *dst;
struct session *dst = item->state.tflag.s; struct winlink *wl;
struct winlink *wl = item->state.sflag.wl;
char *cause; char *cause;
int idx = item->state.tflag.idx, kflag, dflag, sflag; int idx, kflag, dflag;
if (args_has(args, 'r')) { if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL)
session_renumber_windows(dst); return (-1);
recalculate_sizes(); if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2)
return (-1);
return (CMD_RETURN_NORMAL);
}
kflag = args_has(self->args, 'k'); kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd'); dflag = args_has(self->args, 'd');
sflag = args_has(self->args, 's'); if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) {
ctx->error(ctx, "can't move window: %s", cause);
if (args_has(self->args, 'a')) { xfree(cause);
if ((idx = winlink_shuffle_up(dst, dst->curw)) == -1) return (-1);
return (CMD_RETURN_ERROR);
} }
server_unlink_window(src, wl);
if (server_link_window(src, wl, dst, idx, kflag, !dflag,
&cause) != 0) {
cmdq_error(item, "can't link window: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (self->entry == &cmd_move_window_entry)
server_unlink_window(src, wl);
/*
* Renumber the winlinks in the src session only, the destination
* session already has the correct winlink id to us, either
* automatically or specified by -s.
*/
if (!sflag && options_get_number(src->options, "renumber-windows"))
session_renumber_windows(src);
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,8 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <errno.h> #include <pwd.h>
#include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <termios.h> #include <termios.h>
@@ -31,189 +30,159 @@
* Create a new session and attach to the current terminal unless -d is given. * Create a new session and attach to the current terminal unless -d is given.
*/ */
#define NEW_SESSION_TEMPLATE "#{session_name}:" int cmd_new_session_check(struct args *);
int cmd_new_session_exec(struct cmd *, struct cmd_ctx *);
static enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_new_session_entry = { const struct cmd_entry cmd_new_session_entry = {
.name = "new-session", "new-session", "new",
.alias = "new", "dn:s:t:x:y:", 0, 1,
"[-d] [-n window-name] [-s session-name] [-t target-session] "
.args = { "Ac:dDEF:n:Ps:t:x:y:", 0, -1 }, "[-x width] [-y height] [command]",
.usage = "[-AdDEP] [-c start-directory] [-F format] [-n window-name] " CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON,
"[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] " NULL,
"[-y height] [command]", cmd_new_session_check,
cmd_new_session_exec
.tflag = CMD_SESSION_CANFAIL,
.flags = CMD_STARTSERVER,
.exec = cmd_new_session_exec
}; };
const struct cmd_entry cmd_has_session_entry = { int
.name = "has-session", cmd_new_session_check(struct args *args)
.alias = "has", {
if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n')))
return (-1);
return (0);
}
.args = { "t:", 0, 0 }, int
.usage = CMD_TARGET_SESSION_USAGE, cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
.tflag = CMD_SESSION,
.flags = 0,
.exec = cmd_new_session_exec
};
static enum cmd_retval
cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->client; struct session *s, *old_s, *groupwith;
struct session *s, *as, *groupwith;
struct window *w; struct window *w;
struct environ *env; struct window_pane *wp;
struct environ env;
struct termios tio, *tiop; struct termios tio, *tiop;
struct session_group *sg; struct passwd *pw;
const char *newname, *errstr, *template, *group, *prefix; const char *newname, *target, *update, *cwd, *errstr;
const char *path, *cmd, *cwd, *to_free = NULL; char *overrides, *cmd, *cause;
char **argv, *cause, *cp; int detached, idx;
int detached, already_attached, idx, argc; u_int sx, sy, i;
u_int sx, sy;
struct environ_entry *envent;
struct cmd_find_state fs;
if (self->entry == &cmd_has_session_entry) {
/*
* cmd_prepare() will fail if the session cannot be found,
* hence always return success here.
*/
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) {
cmdq_error(item, "command or window name given with target");
return (CMD_RETURN_ERROR);
}
newname = args_get(args, 's'); newname = args_get(args, 's');
if (newname != NULL) { if (newname != NULL) {
if (!session_check_name(newname)) { if (!session_check_name(newname)) {
cmdq_error(item, "bad session name: %s", newname); ctx->error(ctx, "bad session name: %s", newname);
return (CMD_RETURN_ERROR); return (-1);
} }
if ((as = session_find(newname)) != NULL) { if (session_find(newname) != NULL) {
if (args_has(args, 'A')) { ctx->error(ctx, "duplicate session: %s", newname);
/* return (-1);
* This item is now destined for
* attach-session. Because attach-session will
* have already been prepared, copy this
* session into its tflag so it can be used.
*/
cmd_find_from_session(&item->state.tflag, as);
return (cmd_attach_session(item,
args_has(args, 'D'), 0, NULL,
args_has(args, 'E')));
}
cmdq_error(item, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR);
} }
} }
/* Is this going to be part of a session group? */ target = args_get(args, 't');
group = args_get(args, 't'); if (target != NULL) {
if (group != NULL) { groupwith = cmd_find_session(ctx, target, 0);
groupwith = item->state.tflag.s; if (groupwith == NULL)
if (groupwith == NULL) { return (-1);
if (!session_check_name(group)) { } else
cmdq_error(item, "bad group name: %s", group);
goto error;
}
sg = session_group_find(group);
} else
sg = session_group_contains(groupwith);
if (sg != NULL)
prefix = sg->name;
else if (groupwith != NULL)
prefix = groupwith->name;
else
prefix = group;
} else {
groupwith = NULL; groupwith = NULL;
sg = NULL;
prefix = NULL; /*
} * There are three cases:
*
* 1. If cmdclient is non-NULL, new-session has been called from the
* command-line - cmdclient is to become a new attached, interactive
* client. Unless -d is given, the terminal must be opened and then
* the client sent MSG_READY.
*
* 2. If cmdclient is NULL, new-session has been called from an
* existing client (such as a key binding).
*
* 3. Both are NULL, the command was in the configuration file. Treat
* this as if -d was given even if it was not.
*
* In all cases, a new additional session needs to be created and
* (unless -d) set as the current session for the client.
*/
/* Set -d if no client. */ /* Set -d if no client. */
detached = args_has(args, 'd'); detached = args_has(args, 'd');
if (c == NULL) if (ctx->cmdclient == NULL && ctx->curclient == NULL)
detached = 1; detached = 1;
/* Is this client already attached? */
already_attached = 0;
if (c != NULL && c->session != NULL)
already_attached = 1;
/* Get the new session working directory. */
if (args_has(args, 'c')) {
cwd = args_get(args, 'c');
to_free = cwd = format_single(item, cwd, c, NULL, NULL, NULL);
} else if (c != NULL && c->session == NULL && c->cwd != NULL)
cwd = c->cwd;
else
cwd = ".";
/* /*
* If this is a new client, check for nesting and save the termios * Save the termios settings, part of which is used for new windows in
* settings (part of which is used for new windows in this session). * this session.
* *
* tcgetattr() is used rather than using tty.tio since if the client is * This is read again with tcgetattr() rather than using tty.tio as if
* detached, tty_open won't be called. It must be done before opening * detached, tty_open won't be called. Because of this, it must be done
* the terminal as that calls tcsetattr() to prepare for tmux taking * before opening the terminal as that calls tcsetattr() to prepare for
* over. * tmux taking over.
*/ */
if (!detached && !already_attached && c->tty.fd != -1) { if (ctx->cmdclient != NULL && ctx->cmdclient->tty.fd != -1) {
if (server_client_check_nested(item->client)) { if (tcgetattr(ctx->cmdclient->tty.fd, &tio) != 0)
cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force");
return (CMD_RETURN_ERROR);
}
if (tcgetattr(c->tty.fd, &tio) != 0)
fatal("tcgetattr failed"); fatal("tcgetattr failed");
tiop = &tio; tiop = &tio;
} else } else
tiop = NULL; tiop = NULL;
/* Open the terminal if necessary. */ /* Open the terminal if necessary. */
if (!detached && !already_attached) { if (!detached && ctx->cmdclient != NULL) {
if (server_client_open(c, &cause) != 0) { if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) {
cmdq_error(item, "open terminal failed: %s", cause); ctx->error(ctx, "not a terminal");
free(cause); return (-1);
goto error; }
overrides =
options_get_string(&global_s_options, "terminal-overrides");
if (tty_open(&ctx->cmdclient->tty, overrides, &cause) != 0) {
ctx->error(ctx, "open terminal failed: %s", cause);
xfree(cause);
return (-1);
} }
} }
/* Get the new session working directory. */
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
cwd = ctx->cmdclient->cwd;
else {
pw = getpwuid(getuid());
if (pw->pw_dir != NULL && *pw->pw_dir != '\0')
cwd = pw->pw_dir;
else
cwd = "/";
}
/* Find new session size. */ /* Find new session size. */
if (c != NULL) { if (ctx->cmdclient != NULL) {
sx = c->tty.sx; sx = ctx->cmdclient->tty.sx;
sy = c->tty.sy; sy = ctx->cmdclient->tty.sy;
} else if (ctx->curclient != NULL) {
sx = ctx->curclient->tty.sx;
sy = ctx->curclient->tty.sy;
} else { } else {
sx = 80; sx = 80;
sy = 24; sy = 24;
} }
if (detached && args_has(args, 'x')) { if (detached) {
sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr); if (args_has(args, 'x')) {
if (errstr != NULL) { sx = strtonum(
cmdq_error(item, "width %s", errstr); args_get(args, 'x'), 1, USHRT_MAX, &errstr);
goto error; if (errstr != NULL) {
ctx->error(ctx, "width %s", errstr);
return (-1);
}
}
if (args_has(args, 'y')) {
sy = strtonum(
args_get(args, 'y'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
ctx->error(ctx, "height %s", errstr);
return (-1);
}
} }
} }
if (detached && args_has(args, 'y')) { if (sy > 0 && options_get_number(&global_s_options, "status"))
sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
goto error;
}
}
if (sy > 0 && options_get_number(global_s_options, "status"))
sy--; sy--;
if (sx == 0) if (sx == 0)
sx = 1; sx = 1;
@@ -221,89 +190,71 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
sy = 1; sy = 1;
/* Figure out the command for the new window. */ /* Figure out the command for the new window. */
argc = -1; if (target != NULL)
argv = NULL; cmd = NULL;
if (!args_has(args, 't') && args->argc != 0) { else if (args->argc != 0)
argc = args->argc; cmd = args->argv[0];
argv = args->argv;
} else if (sg == NULL && groupwith == NULL) {
cmd = options_get_string(global_s_options, "default-command");
if (cmd != NULL && *cmd != '\0') {
argc = 1;
argv = (char **)&cmd;
} else {
argc = 0;
argv = NULL;
}
}
path = NULL;
if (c != NULL && c->session == NULL)
envent = environ_find(c->environ, "PATH");
else else
envent = environ_find(global_environ, "PATH"); cmd = options_get_string(&global_s_options, "default-command");
if (envent != NULL)
path = envent->value;
/* Construct the environment. */ /* Construct the environment. */
env = environ_create(); environ_init(&env);
if (c != NULL && !args_has(args, 'E')) update = options_get_string(&global_s_options, "update-environment");
environ_update(global_s_options, c->environ, env); if (ctx->cmdclient != NULL)
environ_update(update, &ctx->cmdclient->environ, &env);
/* Create the new session. */ /* Create the new session. */
idx = -1 - options_get_number(global_s_options, "base-index"); idx = -1 - options_get_number(&global_s_options, "base-index");
s = session_create(prefix, newname, argc, argv, path, cwd, env, tiop, s = session_create(newname, cmd, cwd, &env, tiop, idx, sx, sy, &cause);
idx, sx, sy, &cause);
environ_free(env);
if (s == NULL) { if (s == NULL) {
cmdq_error(item, "create session failed: %s", cause); ctx->error(ctx, "create session failed: %s", cause);
free(cause); xfree(cause);
goto error; return (-1);
} }
environ_free(&env);
/* Set the initial window name if one given. */ /* Set the initial window name if one given. */
if (argc >= 0 && args_has(args, 'n')) { if (cmd != NULL && args_has(args, 'n')) {
w = s->curw->window; w = s->curw->window;
window_set_name(w, args_get(args, 'n'));
options_set_number(w->options, "automatic-rename", 0); xfree(w->name);
w->name = xstrdup(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, * If a target session is given, this is to be part of a session group,
* so add it to the group and synchronize. * so add it to the group and synchronize.
*/ */
if (group != NULL) { if (groupwith != NULL) {
if (sg == NULL) { session_group_add(groupwith, s);
if (groupwith != NULL) {
sg = session_group_new(groupwith->name);
session_group_add(sg, groupwith);
} else
sg = session_group_new(group);
}
session_group_add(sg, s);
session_group_synchronize_to(s); session_group_synchronize_to(s);
session_select(s, RB_MIN(winlinks, &s->windows)->idx); session_select(s, RB_ROOT(&s->windows)->idx);
} }
notify_session("session-created", s);
/* /*
* Set the client to the new session. If a command client exists, it is * 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. * taking this session and needs to get MSG_READY and stay around.
*/ */
if (!detached) { if (!detached) {
if (!already_attached) { if (ctx->cmdclient != NULL) {
if (~c->flags & CLIENT_CONTROL) server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
proc_send(c->peer, MSG_READY, -1, NULL, 0);
} else if (c->session != NULL) old_s = ctx->cmdclient->session;
c->last_session = c->session; if (old_s != NULL)
c->session = s; ctx->cmdclient->last_session = old_s;
if (!item->repeat) ctx->cmdclient->session = s;
server_client_set_key_table(c, NULL); session_update_activity(s);
status_timer_start(c); server_redraw_client(ctx->cmdclient);
notify_client("client-session-changed", c); } else {
session_update_activity(s, NULL); old_s = ctx->curclient->session;
gettimeofday(&s->last_attached_time, NULL); if (old_s != NULL)
server_redraw_client(c); ctx->curclient->last_session = old_s;
ctx->curclient->session = s;
session_update_activity(s);
server_redraw_client(ctx->curclient);
}
} }
recalculate_sizes(); recalculate_sizes();
server_update_socket(); server_update_socket();
@@ -312,31 +263,17 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
* If there are still configuration file errors to display, put the new * If there are still configuration file errors to display, put the new
* session's current window into more mode and display them now. * session's current window into more mode and display them now.
*/ */
if (cfg_finished) if (cfg_finished && !ARRAY_EMPTY(&cfg_causes)) {
cfg_show_causes(s); wp = s->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode);
/* Print if requested. */ window_copy_init_for_output(wp);
if (args_has(args, 'P')) { for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
if ((template = args_get(args, 'F')) == NULL) cause = ARRAY_ITEM(&cfg_causes, i);
template = NEW_SESSION_TEMPLATE; window_copy_add(wp, "%s", cause);
cp = format_single(item, template, c, s, NULL, NULL); xfree(cause);
cmdq_print(item, "%s", cp); }
free(cp); ARRAY_FREE(&cfg_causes);
} }
if (!detached) return (!detached); /* 1 means don't tell command client to exit */
c->flags |= CLIENT_ATTACHED;
if (to_free != NULL)
free((void *)to_free);
cmd_find_from_session(&fs, s);
hooks_insert(s->hooks, item, &fs, "after-new-session");
return (CMD_RETURN_NORMAL);
error:
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_ERROR);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,11 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -30,76 +26,55 @@
* Create a new window. * Create a new window.
*/ */
#define NEW_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" int cmd_new_window_exec(struct cmd *, struct cmd_ctx *);
static enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_new_window_entry = { const struct cmd_entry cmd_new_window_entry = {
.name = "new-window", "new-window", "neww",
.alias = "neww", "adkn:Pt:", 0, 1,
"[-adk] [-n window-name] [-t target-window] [command]",
.args = { "ac:dF:kn:Pt:", 0, -1 }, 0,
.usage = "[-adkP] [-c start-directory] [-F format] [-n window-name] " NULL,
CMD_TARGET_WINDOW_USAGE " [command]", NULL,
cmd_new_window_exec
.tflag = CMD_WINDOW_INDEX,
.flags = 0,
.exec = cmd_new_window_exec
}; };
static enum cmd_retval int
cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s = item->state.tflag.s; struct session *s;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl;
struct client *c = item->state.c; const char *cmd, *cwd;
int idx = item->state.tflag.idx; char *cause;
const char *cmd, *path, *template, *cwd, *to_free; int idx, last, detached;
char **argv, *cause, *cp;
int argc, detached;
struct environ_entry *envent;
struct cmd_find_state fs;
if (args_has(args, 'a')) { if (args_has(args, 'a')) {
if ((idx = winlink_shuffle_up(s, wl)) == -1) { wl = cmd_find_window(ctx, args_get(args, 't'), &s);
cmdq_error(item, "no free window indexes"); if (wl == NULL)
return (CMD_RETURN_ERROR); return (-1);
} idx = wl->idx + 1;
}
detached = args_has(args, 'd');
if (args->argc == 0) { /* Find the next free index. */
cmd = options_get_string(s->options, "default-command"); for (last = idx; last < INT_MAX; last++) {
if (cmd != NULL && *cmd != '\0') { if (winlink_find_by_index(&s->windows, last) == NULL)
argc = 1; break;
argv = (char **)&cmd; }
} else { if (last == INT_MAX) {
argc = 0; ctx->error(ctx, "no free window indexes");
argv = NULL; return (-1);
}
/* Move everything from last - 1 to idx up a bit. */
for (; last > idx; last--) {
wl = winlink_find_by_index(&s->windows, last - 1);
server_link_window(s, wl, s, last, 0, 0, NULL);
server_unlink_window(s, wl);
} }
} else { } else {
argc = args->argc; if ((idx = cmd_find_index(ctx, args_get(args, 't'), &s)) == -2)
argv = args->argv; return (-1);
} }
detached = args_has(args, 'd');
path = NULL;
if (item->client != NULL && item->client->session == NULL)
envent = environ_find(item->client->environ, "PATH");
else
envent = environ_find(s->environ, "PATH");
if (envent != NULL)
path = envent->value;
to_free = NULL;
if (args_has(args, 'c')) {
cwd = args_get(args, 'c');
to_free = cwd = format_single(item, cwd, c, s, NULL, NULL);
} else if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
else
cwd = s->cwd;
wl = NULL; wl = NULL;
if (idx != -1) if (idx != -1)
@@ -109,7 +84,6 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
* Can't use session_detach as it will destroy session if this * Can't use session_detach as it will destroy session if this
* makes it empty. * makes it empty.
*/ */
notify_session_window("window-unlinked", s, wl->window);
wl->flags &= ~WINLINK_ALERTFLAGS; wl->flags &= ~WINLINK_ALERTFLAGS;
winlink_stack_remove(&s->lastw, wl); winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl); winlink_remove(&s->windows, wl);
@@ -121,14 +95,19 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
} }
} }
if (args->argc == 0)
cmd = options_get_string(&s->options, "default-command");
else
cmd = args->argv[0];
cwd = cmd_get_default_path(ctx);
if (idx == -1) if (idx == -1)
idx = -1 - options_get_number(s->options, "base-index"); idx = -1 - options_get_number(&s->options, "base-index");
wl = session_new(s, args_get(args, 'n'), argc, argv, path, cwd, idx, wl = session_new(s, args_get(args, 'n'), cmd, cwd, idx, &cause);
&cause);
if (wl == NULL) { if (wl == NULL) {
cmdq_error(item, "create window failed: %s", cause); ctx->error(ctx, "create window failed: %s", cause);
free(cause); xfree(cause);
goto error; return (-1);
} }
if (!detached) { if (!detached) {
session_select(s, wl->idx); session_select(s, wl->idx);
@@ -136,24 +115,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
} else } else
server_status_session_group(s); server_status_session_group(s);
if (args_has(args, 'P')) { if (args_has(args, 'P'))
if ((template = args_get(args, 'F')) == NULL) ctx->print(ctx, "%s:%u", s->name, wl->idx);
template = NEW_WINDOW_TEMPLATE; return (0);
cp = format_single(item, template, c, s, wl, NULL);
cmdq_print(item, "%s", cp);
free(cp);
}
if (to_free != NULL)
free((void *)to_free);
cmd_find_from_winlink(&fs, s, wl);
hooks_insert(s->hooks, item, &fs, "after-new-window");
return (CMD_RETURN_NORMAL);
error:
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_ERROR);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -27,47 +27,57 @@
* Paste paste buffer if present. * Paste paste buffer if present.
*/ */
static enum cmd_retval cmd_paste_buffer_exec(struct cmd *, struct cmdq_item *); int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_paste_buffer_filter(
struct window_pane *, const char *, size_t, const char *);
const struct cmd_entry cmd_paste_buffer_entry = { const struct cmd_entry cmd_paste_buffer_entry = {
.name = "paste-buffer", "paste-buffer", "pasteb",
.alias = "pasteb", "db:rs:t:", 0, 0,
"[-dr] [-s separator] [-b buffer-index] [-t target-pane]",
.args = { "db:prs:t:", 0, 0 }, 0,
.usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " " NULL,
CMD_TARGET_PANE_USAGE, NULL,
cmd_paste_buffer_exec
.tflag = CMD_PANE,
.flags = CMD_AFTERHOOK,
.exec = cmd_paste_buffer_exec
}; };
static enum cmd_retval int
cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item) cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp = item->state.tflag.wp; struct window_pane *wp;
struct session *s;
struct paste_buffer *pb; struct paste_buffer *pb;
const char *sepstr, *bufname, *bufdata, *bufend, *line; const char *sepstr;
size_t seplen, bufsize; char *cause;
int bracket = args_has(args, 'p'); int buffer;
bufname = NULL; if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
if (args_has(args, 'b')) return (-1);
bufname = args_get(args, 'b');
if (bufname == NULL) if (!args_has(args, 'b'))
pb = paste_get_top(NULL); buffer = -1;
else { else {
pb = paste_get_name(bufname); buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (pb == NULL) { if (cause != NULL) {
cmdq_error(item, "no buffer %s", bufname); ctx->error(ctx, "buffer %s", cause);
return (CMD_RETURN_ERROR); xfree(cause);
return (-1);
} }
} }
if (pb != NULL && ~wp->flags & PANE_INPUTOFF) { if (buffer == -1)
pb = paste_get_top(&global_buffers);
else {
pb = paste_get_index(&global_buffers, buffer);
if (pb == NULL) {
ctx->error(ctx, "no buffer %d", buffer);
return (-1);
}
}
if (pb != NULL) {
sepstr = args_get(args, 's'); sepstr = args_get(args, 's');
if (sepstr == NULL) { if (sepstr == NULL) {
if (args_has(args, 'r')) if (args_has(args, 'r'))
@@ -75,33 +85,37 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
else else
sepstr = "\r"; sepstr = "\r";
} }
seplen = strlen(sepstr); cmd_paste_buffer_filter(wp, pb->data, pb->size, sepstr);
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);
} }
if (pb != NULL && args_has(args, 'd')) /* Delete the buffer if -d. */
paste_free(pb); if (args_has(args, 'd')) {
if (buffer == -1)
paste_free_top(&global_buffers);
else
paste_free_index(&global_buffers, buffer);
}
return (CMD_RETURN_NORMAL); return (0);
}
/* Add bytes to a buffer and filter '\n' according to separator. */
void
cmd_paste_buffer_filter(
struct window_pane *wp, const char *data, size_t size, const char *sep)
{
const char *end = data + size;
const char *lf;
size_t seplen;
seplen = strlen(sep);
while ((lf = memchr(data, '\n', end - data)) != NULL) {
if (lf != data)
bufferevent_write(wp->event, data, lf - data);
bufferevent_write(wp->event, sep, seplen);
data = lf + 1;
}
if (end != data)
bufferevent_write(wp->event, data, end - data);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -21,7 +21,6 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
@@ -32,34 +31,32 @@
* Open pipe to redirect pane output. If already open, close first. * Open pipe to redirect pane output. If already open, close first.
*/ */
static enum cmd_retval cmd_pipe_pane_exec(struct cmd *, struct cmdq_item *); int cmd_pipe_pane_exec(struct cmd *, struct cmd_ctx *);
static void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *); void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *);
const struct cmd_entry cmd_pipe_pane_entry = { const struct cmd_entry cmd_pipe_pane_entry = {
.name = "pipe-pane", "pipe-pane", "pipep",
.alias = "pipep", "ot:", 0, 1,
"[-o] " CMD_TARGET_PANE_USAGE " [command]",
.args = { "ot:", 0, 1 }, 0,
.usage = "[-o] " CMD_TARGET_PANE_USAGE " [command]", NULL,
NULL,
.tflag = CMD_PANE, cmd_pipe_pane_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_pipe_pane_exec
}; };
static enum cmd_retval int
cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct client *c;
struct window_pane *wp = item->state.tflag.wp; struct window_pane *wp;
struct session *s = item->state.tflag.s; char *command;
struct winlink *wl = item->state.tflag.wl;
char *cmd;
int old_fd, pipe_fd[2], null_fd; int old_fd, pipe_fd[2], null_fd;
struct format_tree *ft;
if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
return (-1);
c = cmd_find_client(ctx, NULL);
/* Destroy the old pipe. */ /* Destroy the old pipe. */
old_fd = wp->pipe_fd; old_fd = wp->pipe_fd;
@@ -71,7 +68,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
/* If no pipe command, that is enough. */ /* If no pipe command, that is enough. */
if (args->argc == 0 || *args->argv[0] == '\0') if (args->argc == 0 || *args->argv[0] == '\0')
return (CMD_RETURN_NORMAL); return (0);
/* /*
* With -o, only open the new pipe if there was no previous one. This * With -o, only open the new pipe if there was no previous one. This
@@ -80,27 +77,19 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
* bind ^p pipep -o 'cat >>~/output' * bind ^p pipep -o 'cat >>~/output'
*/ */
if (args_has(self->args, 'o') && old_fd != -1) if (args_has(self->args, 'o') && old_fd != -1)
return (CMD_RETURN_NORMAL); return (0);
/* Open the new pipe. */ /* Open the new pipe. */
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) { if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) {
cmdq_error(item, "socketpair error: %s", strerror(errno)); ctx->error(ctx, "socketpair error: %s", strerror(errno));
return (CMD_RETURN_ERROR); return (-1);
} }
/* Expand the command. */
ft = format_create(item, FORMAT_NONE, 0);
format_defaults(ft, c, s, wl, wp);
cmd = format_expand_time(ft, args->argv[0], time(NULL));
format_free(ft);
/* Fork the child. */ /* Fork the child. */
switch (fork()) { switch (fork()) {
case -1: case -1:
cmdq_error(item, "fork error: %s", strerror(errno)); ctx->error(ctx, "fork error: %s", strerror(errno));
return (-1);
free(cmd);
return (CMD_RETURN_ERROR);
case 0: case 0:
/* Child process. */ /* Child process. */
close(pipe_fd[0]); close(pipe_fd[0]);
@@ -121,7 +110,9 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
closefrom(STDERR_FILENO + 1); closefrom(STDERR_FILENO + 1);
execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); command = status_replace(
c, NULL, NULL, NULL, args->argv[0], time(NULL), 0);
execl(_PATH_BSHELL, "sh", "-c", command, (char *) NULL);
_exit(1); _exit(1);
default: default:
/* Parent process. */ /* Parent process. */
@@ -135,15 +126,14 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
bufferevent_enable(wp->pipe_event, EV_WRITE); bufferevent_enable(wp->pipe_event, EV_WRITE);
setblocking(wp->pipe_fd, 0); setblocking(wp->pipe_fd, 0);
return (0);
free(cmd);
return (CMD_RETURN_NORMAL);
} }
} }
static void /* ARGSUSED */
cmd_pipe_pane_error_callback(__unused struct bufferevent *bufev, void
__unused short what, void *data) cmd_pipe_pane_error_callback(
unused struct bufferevent *bufev, unused short what, void *data)
{ {
struct window_pane *wp = data; struct window_pane *wp = data;

View File

@@ -1,445 +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"
/* Global command queue. */
static struct cmdq_list global_queue = TAILQ_HEAD_INITIALIZER(global_queue);
/* Get command queue name. */
static const char *
cmdq_name(struct client *c)
{
static char s[32];
if (c == NULL)
return ("<global>");
xsnprintf(s, sizeof s, "<%p>", c);
return (s);
}
/* Get command queue from client. */
static struct cmdq_list *
cmdq_get(struct client *c)
{
if (c == NULL)
return (&global_queue);
return (&c->queue);
}
/* Append an item. */
void
cmdq_append(struct client *c, struct cmdq_item *item)
{
struct cmdq_list *queue = cmdq_get(c);
struct cmdq_item *next;
do {
next = item->next;
item->next = NULL;
if (c != NULL)
c->references++;
item->client = c;
item->queue = queue;
TAILQ_INSERT_TAIL(queue, item, entry);
item = next;
} while (item != NULL);
}
/* Insert an item. */
void
cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
{
struct client *c = after->client;
struct cmdq_list *queue = after->queue;
struct cmdq_item *next;
do {
next = item->next;
item->next = NULL;
if (c != NULL)
c->references++;
item->client = c;
item->queue = queue;
if (after->next != NULL)
TAILQ_INSERT_AFTER(queue, after->next, item, entry);
else
TAILQ_INSERT_AFTER(queue, after, item, entry);
after->next = item;
item = next;
} while (item != NULL);
}
/* Remove an item. */
static void
cmdq_remove(struct cmdq_item *item)
{
if (item->formats != NULL)
format_free(item->formats);
if (item->client != NULL)
server_client_unref(item->client);
if (item->type == CMDQ_COMMAND)
cmd_list_free(item->cmdlist);
TAILQ_REMOVE(item->queue, item, entry);
free((void *)item->name);
free(item);
}
/* Set command group. */
static u_int
cmdq_next_group(void)
{
static u_int group;
return (++group);
}
/* Remove all subsequent items that match this item's group. */
static void
cmdq_remove_group(struct cmdq_item *item)
{
struct cmdq_item *this, *next;
this = TAILQ_NEXT(item, entry);
while (this != NULL) {
next = TAILQ_NEXT(this, entry);
if (this->group == item->group)
cmdq_remove(this);
this = next;
}
}
/* Get a command for the command queue. */
struct cmdq_item *
cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
struct mouse_event *m, int flags)
{
struct cmdq_item *item, *first = NULL, *last = NULL;
struct cmd *cmd;
u_int group = cmdq_next_group();
char *tmp;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
xasprintf(&tmp, "command[%s]", cmd->entry->name);
item = xcalloc(1, sizeof *item);
item->name = tmp;
item->type = CMDQ_COMMAND;
item->group = group;
item->flags = flags;
item->cmdlist = cmdlist;
item->cmd = cmd;
if (current != NULL)
cmd_find_copy_state(&item->current, current);
if (m != NULL)
memcpy(&item->mouse, m, sizeof item->mouse);
cmdlist->references++;
if (first == NULL)
first = item;
if (last != NULL)
last->next = item;
last = item;
}
return (first);
}
/* Fire command on command queue. */
static enum cmd_retval
cmdq_fire_command(struct cmdq_item *item)
{
struct client *c = item->client;
struct cmd *cmd = item->cmd;
enum cmd_retval retval;
const char *name;
struct cmd_find_state *fsp, fs;
int flags;
flags = !!(cmd->flags & CMD_CONTROL);
cmdq_guard(item, "begin", flags);
if (cmd_prepare_state(cmd, item) != 0) {
retval = CMD_RETURN_ERROR;
goto out;
}
if (item->client == NULL)
item->client = cmd_find_client(item, NULL, CMD_FIND_QUIET);
retval = cmd->entry->exec(cmd, item);
if (retval == CMD_RETURN_ERROR)
goto out;
if (cmd->entry->flags & CMD_AFTERHOOK) {
name = cmd->entry->name;
if (cmd_find_valid_state(&item->state.tflag))
fsp = &item->state.tflag;
else {
if (cmd_find_current(&fs, item, CMD_FIND_QUIET) != 0)
goto out;
fsp = &fs;
}
hooks_insert(fsp->s->hooks, item, fsp, "after-%s", name);
}
out:
item->client = c;
if (retval == CMD_RETURN_ERROR)
cmdq_guard(item, "error", flags);
else
cmdq_guard(item, "end", flags);
return (retval);
}
/* Get a callback for the command queue. */
struct cmdq_item *
cmdq_get_callback1(const char *name, cmdq_cb cb, void *data)
{
struct cmdq_item *item;
char *tmp;
xasprintf(&tmp, "callback[%s]", name);
item = xcalloc(1, sizeof *item);
item->name = tmp;
item->type = CMDQ_CALLBACK;
item->group = 0;
item->flags = 0;
item->cb = cb;
item->data = data;
return (item);
}
/* Fire callback on callback queue. */
static enum cmd_retval
cmdq_fire_callback(struct cmdq_item *item)
{
return (item->cb(item, item->data));
}
/* Add a format to command queue. */
void
cmdq_format(struct cmdq_item *item, const char *key, const char *fmt, ...)
{
va_list ap;
struct cmdq_item *loop;
char *value;
va_start(ap, fmt);
xvasprintf(&value, fmt, ap);
va_end(ap);
for (loop = item; loop != NULL; loop = item->next) {
if (loop->formats == NULL)
loop->formats = format_create(NULL, FORMAT_NONE, 0);
format_add(loop->formats, key, "%s", value);
}
free(value);
}
/* Process next item on command queue. */
u_int
cmdq_next(struct client *c)
{
struct cmdq_list *queue = cmdq_get(c);
const char *name = cmdq_name(c);
struct cmdq_item *item;
enum cmd_retval retval;
u_int items = 0;
static u_int number;
if (TAILQ_EMPTY(queue)) {
log_debug("%s %s: empty", __func__, name);
return (0);
}
if (TAILQ_FIRST(queue)->flags & CMDQ_WAITING) {
log_debug("%s %s: waiting", __func__, name);
return (0);
}
log_debug("%s %s: enter", __func__, name);
for (;;) {
item = TAILQ_FIRST(queue);
if (item == NULL)
break;
log_debug("%s %s: %s (%d), flags %x", __func__, name,
item->name, item->type, item->flags);
/*
* Any item with the waiting flag set waits until an external
* event clears the flag (for example, a job - look at
* run-shell).
*/
if (item->flags & CMDQ_WAITING)
goto waiting;
/*
* Items are only fired once, once the fired flag is set, a
* waiting flag can only be cleared by an external event.
*/
if (~item->flags & CMDQ_FIRED) {
item->time = time(NULL);
item->number = ++number;
switch (item->type)
{
case CMDQ_COMMAND:
retval = cmdq_fire_command(item);
/*
* If a command returns an error, remove any
* subsequent commands in the same group.
*/
if (retval == CMD_RETURN_ERROR)
cmdq_remove_group(item);
break;
case CMDQ_CALLBACK:
retval = cmdq_fire_callback(item);
break;
default:
retval = CMD_RETURN_ERROR;
break;
}
item->flags |= CMDQ_FIRED;
if (retval == CMD_RETURN_WAIT) {
item->flags |= CMDQ_WAITING;
goto waiting;
}
items++;
}
cmdq_remove(item);
}
log_debug("%s %s: exit (empty)", __func__, name);
return (items);
waiting:
log_debug("%s %s: exit (wait)", __func__, name);
return (items);
}
/* Print a guard line. */
void
cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
{
struct client *c = item->client;
if (c == NULL || !(c->flags & CLIENT_CONTROL))
return;
evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
(long)item->time, item->number, flags);
server_client_push_stdout(c);
}
/* Show message from command. */
void
cmdq_print(struct cmdq_item *item, const char *fmt, ...)
{
struct client *c = item->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 cmdq_item *item, const char *fmt, ...)
{
struct client *c = item->client;
struct cmd *cmd = item->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);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -24,57 +24,32 @@
* Refresh client. * Refresh client.
*/ */
static enum cmd_retval cmd_refresh_client_exec(struct cmd *, int cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *);
struct cmdq_item *);
const struct cmd_entry cmd_refresh_client_entry = { const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client", "refresh-client", "refresh",
.alias = "refresh", "St:", 0, 0,
"[-S] " CMD_TARGET_CLIENT_USAGE,
.args = { "C:St:", 0, 0 }, 0,
.usage = "[-S] [-C size] " CMD_TARGET_CLIENT_USAGE, NULL,
NULL,
.tflag = CMD_CLIENT, cmd_refresh_client_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_refresh_client_exec
}; };
static enum cmd_retval int
cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct client *c;
const char *size;
u_int w, h;
if (args_has(args, 'C')) { if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
if ((size = args_get(args, 'C')) == NULL) { return (-1);
cmdq_error(item, "missing size");
return (CMD_RETURN_ERROR); if (args_has(args, 'S')) {
} status_update_jobs(c);
if (sscanf(size, "%u,%u", &w, &h) != 2) {
cmdq_error(item, "bad size argument");
return (CMD_RETURN_ERROR);
}
if (w < PANE_MINIMUM || w > 5000 ||
h < PANE_MINIMUM || h > 5000) {
cmdq_error(item, "size too small or too big");
return (CMD_RETURN_ERROR);
}
if (!(c->flags & CLIENT_CONTROL)) {
cmdq_error(item, "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); server_status_client(c);
} else { } else
c->flags |= CLIENT_STATUSFORCE;
server_redraw_client(c); server_redraw_client(c);
}
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -19,7 +19,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -27,49 +26,44 @@
* Change session name. * Change session name.
*/ */
static enum cmd_retval cmd_rename_session_exec(struct cmd *, int cmd_rename_session_exec(struct cmd *, struct cmd_ctx *);
struct cmdq_item *);
const struct cmd_entry cmd_rename_session_entry = { const struct cmd_entry cmd_rename_session_entry = {
.name = "rename-session", "rename-session", "rename",
.alias = "rename", "t:", 1, 1,
CMD_TARGET_SESSION_USAGE " new-name",
.args = { "t:", 1, 1 }, 0,
.usage = CMD_TARGET_SESSION_USAGE " new-name", NULL,
NULL,
.tflag = CMD_SESSION, cmd_rename_session_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_rename_session_exec
}; };
static enum cmd_retval int
cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item) cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s = item->state.tflag.s; struct session *s;
const char *newname; const char *newname;
newname = args->argv[0]; newname = args->argv[0];
if (strcmp(newname, s->name) == 0)
return (CMD_RETURN_NORMAL);
if (!session_check_name(newname)) { if (!session_check_name(newname)) {
cmdq_error(item, "bad session name: %s", newname); ctx->error(ctx, "bad session name: %s", newname);
return (CMD_RETURN_ERROR); return (-1);
} }
if (session_find(newname) != NULL) { if (session_find(newname) != NULL) {
cmdq_error(item, "duplicate session: %s", newname); ctx->error(ctx, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR); return (-1);
} }
if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
return (-1);
RB_REMOVE(sessions, &sessions, s); RB_REMOVE(sessions, &sessions, s);
free(s->name); xfree(s->name);
s->name = xstrdup(newname); s->name = xstrdup(newname);
RB_INSERT(sessions, &sessions, s); RB_INSERT(sessions, &sessions, s);
server_status_session(s); server_status_session(s);
notify_session("session-renamed", s);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -26,32 +26,33 @@
* Rename a window. * Rename a window.
*/ */
static enum cmd_retval cmd_rename_window_exec(struct cmd *, int cmd_rename_window_exec(struct cmd *, struct cmd_ctx *);
struct cmdq_item *);
const struct cmd_entry cmd_rename_window_entry = { const struct cmd_entry cmd_rename_window_entry = {
.name = "rename-window", "rename-window", "renamew",
.alias = "renamew", "t:", 1, 1,
CMD_TARGET_WINDOW_USAGE " new-name",
.args = { "t:", 1, 1 }, 0,
.usage = CMD_TARGET_WINDOW_USAGE " new-name", NULL,
NULL,
.tflag = CMD_WINDOW, cmd_rename_window_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_rename_window_exec
}; };
static enum cmd_retval int
cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item) cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl; struct session *s;
struct winlink *wl;
window_set_name(wl->window, args->argv[0]); if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL)
options_set_number(wl->window->options, "automatic-rename", 0); return (-1);
xfree(wl->window->name);
wl->window->name = xstrdup(args->argv[0]);
options_set_number(&wl->window->options, "automatic-rename", 0);
server_status_window(wl->window); server_status_window(wl->window);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -26,149 +26,92 @@
* Increase or decrease pane size. * Increase or decrease pane size.
*/ */
static enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmdq_item *); void cmd_resize_pane_key_binding(struct cmd *, int);
int cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *);
static void cmd_resize_pane_mouse_update(struct client *,
struct mouse_event *);
const struct cmd_entry cmd_resize_pane_entry = { const struct cmd_entry cmd_resize_pane_entry = {
.name = "resize-pane", "resize-pane", "resizep",
.alias = "resizep", "DLRt:U", 0, 1,
"[-DLRU] " CMD_TARGET_PANE_USAGE " [adjustment]",
.args = { "DLMRt:Ux:y:Z", 0, 1 }, 0,
.usage = "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " " cmd_resize_pane_key_binding,
"[adjustment]", NULL,
cmd_resize_pane_exec
.tflag = CMD_PANE,
.flags = CMD_AFTERHOOK,
.exec = cmd_resize_pane_exec
}; };
static enum cmd_retval void
cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_resize_pane_key_binding(struct cmd *self, int key)
{
switch (key) {
case KEYC_UP | KEYC_CTRL:
self->args = args_create(0);
args_set(self->args, 'U', NULL);
break;
case KEYC_DOWN | KEYC_CTRL:
self->args = args_create(0);
args_set(self->args, 'D', NULL);
break;
case KEYC_LEFT | KEYC_CTRL:
self->args = args_create(0);
args_set(self->args, 'L', NULL);
break;
case KEYC_RIGHT | KEYC_CTRL:
self->args = args_create(0);
args_set(self->args, 'R', NULL);
break;
case KEYC_UP | KEYC_ESCAPE:
self->args = args_create(1, "5");
args_set(self->args, 'U', NULL);
break;
case KEYC_DOWN | KEYC_ESCAPE:
self->args = args_create(1, "5");
args_set(self->args, 'D', NULL);
break;
case KEYC_LEFT | KEYC_ESCAPE:
self->args = args_create(1, "5");
args_set(self->args, 'L', NULL);
break;
case KEYC_RIGHT | KEYC_ESCAPE:
self->args = args_create(1, "5");
args_set(self->args, 'R', NULL);
break;
default:
self->args = args_create(0);
break;
}
}
int
cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct window_pane *wp = item->state.tflag.wp; struct winlink *wl;
struct winlink *wl = item->state.tflag.wl;
struct window *w = wl->window;
struct client *c = item->client;
struct session *s = item->state.tflag.s;
const char *errstr; const char *errstr;
char *cause; struct window_pane *wp;
u_int adjust; u_int adjust;
int x, y;
if (args_has(args, 'M')) { if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL)
if (cmd_mouse_window(&item->mouse, &s) == NULL) return (-1);
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, &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) if (args->argc == 0)
adjust = 1; adjust = 1;
else { else {
adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr); adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
cmdq_error(item, "adjustment %s", errstr); ctx->error(ctx, "adjustment %s", errstr);
return (CMD_RETURN_ERROR); return (-1);
} }
} }
if (args_has(self->args, 'x')) {
x = args_strtonum(self->args, 'x', PANE_MINIMUM, INT_MAX,
&cause);
if (cause != NULL) {
cmdq_error(item, "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(item, "height %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
}
if (args_has(self->args, 'L')) if (args_has(self->args, 'L'))
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust, 1); layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust);
else if (args_has(self->args, 'R')) else if (args_has(self->args, 'R'))
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust, 1); layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust);
else if (args_has(self->args, 'U')) else if (args_has(self->args, 'U'))
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, -adjust, 1); layout_resize_pane(wp, LAYOUT_TOPBOTTOM, -adjust);
else if (args_has(self->args, 'D')) else if (args_has(self->args, 'D'))
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust, 1); layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust);
server_redraw_window(wl->window); server_redraw_window(wl->window);
return (CMD_RETURN_NORMAL); return (0);
}
static 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, 0);
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, 0);
found = 1;
}
}
if (found)
server_redraw_window(wl->window);
else
c->tty.mouse_drag_update = NULL;
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
* Copyright (c) 2011 Marcel P. Partap <mpartap@gmx.net> * Copyright (c) 2011 Marcel P. Partap <mpartap@gmx.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
@@ -19,7 +19,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -28,67 +27,65 @@
* Respawn a pane (restart the command). Kill existing if -k given. * Respawn a pane (restart the command). Kill existing if -k given.
*/ */
static enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmdq_item *); int cmd_respawn_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_respawn_pane_entry = { const struct cmd_entry cmd_respawn_pane_entry = {
.name = "respawn-pane", "respawn-pane", "respawnp",
.alias = "respawnp", "kt:", 0, 1,
"[-k] " CMD_TARGET_PANE_USAGE " [command]",
.args = { "kt:", 0, -1 }, 0,
.usage = "[-k] " CMD_TARGET_PANE_USAGE " [command]", NULL,
NULL,
.tflag = CMD_PANE, cmd_respawn_pane_exec
.flags = 0,
.exec = cmd_respawn_pane_exec
}; };
static enum cmd_retval int
cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl;
struct window *w = wl->window; struct window *w;
struct window_pane *wp = item->state.tflag.wp; struct window_pane *wp;
struct session *s = item->state.tflag.s; struct session *s;
struct environ *env; struct environ env;
const char *path; const char *cmd;
char *cause; char *cause;
u_int idx; u_int idx;
struct environ_entry *envent;
if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL)
return (-1);
w = wl->window;
if (!args_has(self->args, 'k') && wp->fd != -1) { if (!args_has(self->args, 'k') && wp->fd != -1) {
if (window_pane_index(wp, &idx) != 0) if (window_pane_index(wp, &idx) != 0)
fatalx("index not found"); fatalx("index not found");
cmdq_error(item, "pane still active: %s:%d.%u", ctx->error(ctx, "pane still active: %s:%u.%u",
s->name, wl->idx, idx); s->name, wl->idx, idx);
return (CMD_RETURN_ERROR); return (-1);
} }
environ_init(&env);
environ_copy(&global_environ, &env);
environ_copy(&s->environ, &env);
server_fill_environ(s, &env);
window_pane_reset_mode(wp); window_pane_reset_mode(wp);
screen_reinit(&wp->base); screen_reinit(&wp->base);
input_init(wp); input_init(wp);
path = NULL; if (args->argc != 0)
if (item->client != NULL && item->client->session == NULL) cmd = args->argv[0];
envent = environ_find(item->client->environ, "PATH");
else else
envent = environ_find(s->environ, "PATH"); cmd = NULL;
if (envent != NULL) if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) {
path = envent->value; ctx->error(ctx, "respawn pane failed: %s", cause);
xfree(cause);
env = environ_for_session(s); environ_free(&env);
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env, return (-1);
s->tio, &cause) != 0) {
cmdq_error(item, "respawn pane failed: %s", cause);
free(cause);
environ_free(env);
return (CMD_RETURN_ERROR);
} }
environ_free(env);
wp->flags |= PANE_REDRAW; wp->flags |= PANE_REDRAW;
server_status_window(w); server_status_window(w);
return (CMD_RETURN_NORMAL); environ_free(&env);
return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -27,71 +26,67 @@
* Respawn a window (restart the command). Kill existing if -k given. * Respawn a window (restart the command). Kill existing if -k given.
*/ */
static enum cmd_retval cmd_respawn_window_exec(struct cmd *, int cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *);
struct cmdq_item *);
const struct cmd_entry cmd_respawn_window_entry = { const struct cmd_entry cmd_respawn_window_entry = {
.name = "respawn-window", "respawn-window", "respawnw",
.alias = "respawnw", "kt:", 0, 1,
"[-k] " CMD_TARGET_WINDOW_USAGE " [command]",
.args = { "kt:", 0, -1 }, 0,
.usage = "[-k] " CMD_TARGET_WINDOW_USAGE " [command]", NULL,
NULL,
.tflag = CMD_WINDOW, cmd_respawn_window_exec
.flags = 0,
.exec = cmd_respawn_window_exec
}; };
static enum cmd_retval int
cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item) cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s = item->state.tflag.s; struct winlink *wl;
struct winlink *wl = item->state.tflag.wl; struct window *w;
struct window *w = wl->window;
struct window_pane *wp; struct window_pane *wp;
struct environ *env; struct session *s;
const char *path; struct environ env;
const char *cmd;
char *cause; char *cause;
struct environ_entry *envent;
if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL)
return (-1);
w = wl->window;
if (!args_has(self->args, 'k')) { if (!args_has(self->args, 'k')) {
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd == -1) if (wp->fd == -1)
continue; continue;
cmdq_error(item, "window still active: %s:%d", s->name, ctx->error(ctx,
wl->idx); "window still active: %s:%d", s->name, wl->idx);
return (CMD_RETURN_ERROR); return (-1);
} }
} }
environ_init(&env);
environ_copy(&global_environ, &env);
environ_copy(&s->environ, &env);
server_fill_environ(s, &env);
wp = TAILQ_FIRST(&w->panes); wp = TAILQ_FIRST(&w->panes);
TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_REMOVE(&w->panes, wp, entry);
layout_free(w); layout_free(w);
window_destroy_panes(w); window_destroy_panes(w);
TAILQ_INSERT_HEAD(&w->panes, wp, entry); TAILQ_INSERT_HEAD(&w->panes, wp, entry);
window_pane_resize(wp, w->sx, w->sy); window_pane_resize(wp, w->sx, w->sy);
if (args->argc != 0)
path = NULL; cmd = args->argv[0];
if (item->client != NULL && item->client->session == NULL)
envent = environ_find(item->client->environ, "PATH");
else else
envent = environ_find(s->environ, "PATH"); cmd = NULL;
if (envent != NULL) if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) {
path = envent->value; ctx->error(ctx, "respawn window failed: %s", cause);
xfree(cause);
env = environ_for_session(s); environ_free(&env);
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env, server_destroy_pane(wp);
s->tio, &cause) != 0) { return (-1);
cmdq_error(item, "respawn window failed: %s", cause);
free(cause);
environ_free(env);
server_destroy_pane(wp, 0);
return (CMD_RETURN_ERROR);
} }
environ_free(env); layout_init(w);
layout_init(w, wp);
window_pane_reset_mode(wp); window_pane_reset_mode(wp);
screen_reinit(&wp->base); screen_reinit(&wp->base);
input_init(wp); input_init(wp);
@@ -100,5 +95,6 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
recalculate_sizes(); recalculate_sizes();
server_redraw_window(w); server_redraw_window(w);
return (CMD_RETURN_NORMAL); environ_free(&env);
return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -24,32 +24,40 @@
* Rotate the panes in a window. * Rotate the panes in a window.
*/ */
static enum cmd_retval cmd_rotate_window_exec(struct cmd *, void cmd_rotate_window_key_binding(struct cmd *, int);
struct cmdq_item *); int cmd_rotate_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_rotate_window_entry = { const struct cmd_entry cmd_rotate_window_entry = {
.name = "rotate-window", "rotate-window", "rotatew",
.alias = "rotatew", "Dt:U", 0, 0,
"[-DU] " CMD_TARGET_WINDOW_USAGE,
.args = { "Dt:U", 0, 0 }, 0,
.usage = "[-DU] " CMD_TARGET_WINDOW_USAGE, cmd_rotate_window_key_binding,
NULL,
.tflag = CMD_WINDOW, cmd_rotate_window_exec
.flags = 0,
.exec = cmd_rotate_window_exec
}; };
static enum cmd_retval void
cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item) cmd_rotate_window_key_binding(struct cmd *self, int key)
{ {
struct winlink *wl = item->state.tflag.wl; self->args = args_create(0);
struct window *w = wl->window; if (key == ('o' | KEYC_ESCAPE))
args_set(self->args, 'D', NULL);
}
int
cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct winlink *wl;
struct window *w;
struct window_pane *wp, *wp2; struct window_pane *wp, *wp2;
struct layout_cell *lc; struct layout_cell *lc;
u_int sx, sy, xoff, yoff; u_int sx, sy, xoff, yoff;
server_unzoom_window(w); if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
return (-1);
w = wl->window;
if (args_has(self->args, 'D')) { if (args_has(self->args, 'D')) {
wp = TAILQ_LAST(&w->panes, window_panes); wp = TAILQ_LAST(&w->panes, window_panes);
@@ -107,5 +115,5 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
server_redraw_window(w); server_redraw_window(w);
} }
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -20,7 +20,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -29,107 +28,67 @@
* Runs a command without a window. * Runs a command without a window.
*/ */
static enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmdq_item *); int cmd_run_shell_exec(struct cmd *, struct cmd_ctx *);
static void cmd_run_shell_callback(struct job *); void cmd_run_shell_callback(struct job *);
static void cmd_run_shell_free(void *); void cmd_run_shell_free(void *);
static void cmd_run_shell_print(struct job *, const char *);
const struct cmd_entry cmd_run_shell_entry = { const struct cmd_entry cmd_run_shell_entry = {
.name = "run-shell", "run-shell", "run",
.alias = "run", "", 1, 1,
"command",
.args = { "bt:", 1, 1 }, 0,
.usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command", NULL,
NULL,
.tflag = CMD_PANE_CANFAIL, cmd_run_shell_exec
.flags = 0,
.exec = cmd_run_shell_exec
}; };
struct cmd_run_shell_data { struct cmd_run_shell_data {
char *cmd; char *cmd;
struct cmdq_item *item; struct cmd_ctx ctx;
int wp_id;
}; };
static void int
cmd_run_shell_print(struct job *job, const char *msg) cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_run_shell_data *cdata = job->data;
struct window_pane *wp = NULL;
struct cmd_find_state fs;
if (cdata->wp_id != -1)
wp = window_pane_find_by_id(cdata->wp_id);
if (wp == NULL) {
if (cdata->item != NULL) {
cmdq_print(cdata->item, "%s", msg);
return;
}
if (cmd_find_current (&fs, NULL, CMD_FIND_QUIET) != 0)
return;
wp = fs.wp;
if (wp == NULL)
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);
}
static enum cmd_retval
cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_run_shell_data *cdata; struct cmd_run_shell_data *cdata;
struct client *c = item->state.c; const char *shellcmd = args->argv[0];
struct session *s = item->state.tflag.s;
struct winlink *wl = item->state.tflag.wl;
struct window_pane *wp = item->state.tflag.wp;
const char *cwd;
if (item->client != NULL && item->client->session == NULL) cdata = xmalloc(sizeof *cdata);
cwd = item->client->cwd; cdata->cmd = xstrdup(args->argv[0]);
else if (s != NULL) memcpy(&cdata->ctx, ctx, sizeof cdata->ctx);
cwd = s->cwd;
else
cwd = NULL;
cdata = xcalloc(1, sizeof *cdata); if (ctx->cmdclient != NULL)
cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp); ctx->cmdclient->references++;
if (ctx->curclient != NULL)
ctx->curclient->references++;
if (args_has(args, 't') && wp != NULL) job_run(shellcmd, cmd_run_shell_callback, cmd_run_shell_free, cdata);
cdata->wp_id = wp->id;
else
cdata->wp_id = -1;
if (!args_has(args, 'b')) return (1); /* don't let client exit */
cdata->item = item;
job_run(cdata->cmd, s, cwd, cmd_run_shell_callback, cmd_run_shell_free,
cdata);
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
} }
static void void
cmd_run_shell_callback(struct job *job) cmd_run_shell_callback(struct job *job)
{ {
struct cmd_run_shell_data *cdata = job->data; struct cmd_run_shell_data *cdata = job->data;
char *cmd = cdata->cmd, *msg, *line; struct cmd_ctx *ctx = &cdata->ctx;
char *cmd, *msg, *line;
size_t size; size_t size;
int retcode; int retcode;
u_int lines;
if (ctx->cmdclient != NULL && ctx->cmdclient->flags & CLIENT_DEAD)
return;
if (ctx->curclient != NULL && ctx->curclient->flags & CLIENT_DEAD)
return;
lines = 0;
do { do {
if ((line = evbuffer_readline(job->event->input)) != NULL) { if ((line = evbuffer_readline(job->event->input)) != NULL) {
cmd_run_shell_print(job, line); ctx->print(ctx, "%s", line);
free(line); lines++;
} }
} while (line != NULL); } while (line != NULL);
@@ -139,11 +98,14 @@ cmd_run_shell_callback(struct job *job)
memcpy(line, EVBUFFER_DATA(job->event->input), size); memcpy(line, EVBUFFER_DATA(job->event->input), size);
line[size] = '\0'; line[size] = '\0';
cmd_run_shell_print(job, line); ctx->print(ctx, "%s", line);
lines++;
free(line); xfree(line);
} }
cmd = cdata->cmd;
msg = NULL; msg = NULL;
if (WIFEXITED(job->status)) { if (WIFEXITED(job->status)) {
if ((retcode = WEXITSTATUS(job->status)) != 0) if ((retcode = WEXITSTATUS(job->status)) != 0)
@@ -152,19 +114,28 @@ cmd_run_shell_callback(struct job *job)
retcode = WTERMSIG(job->status); retcode = WTERMSIG(job->status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode); xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
} }
if (msg != NULL) if (msg != NULL) {
cmd_run_shell_print(job, msg); if (lines != 0)
free(msg); ctx->print(ctx, "%s", msg);
else
if (cdata->item != NULL) ctx->info(ctx, "%s", msg);
cdata->item->flags &= ~CMDQ_WAITING; xfree(msg);
}
} }
static void void
cmd_run_shell_free(void *data) cmd_run_shell_free(void *data)
{ {
struct cmd_run_shell_data *cdata = data; struct cmd_run_shell_data *cdata = data;
struct cmd_ctx *ctx = &cdata->ctx;
free(cdata->cmd); if (ctx->cmdclient != NULL) {
free(cdata); ctx->cmdclient->references--;
ctx->cmdclient->flags |= CLIENT_EXIT;
}
if (ctx->curclient != NULL)
ctx->curclient->references--;
xfree(cdata->cmd);
xfree(cdata);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -20,10 +20,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -31,124 +28,90 @@
* Saves a paste buffer to a file. * Saves a paste buffer to a file.
*/ */
static enum cmd_retval cmd_save_buffer_exec(struct cmd *, struct cmdq_item *); int cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_save_buffer_entry = { const struct cmd_entry cmd_save_buffer_entry = {
.name = "save-buffer", "save-buffer", "saveb",
.alias = "saveb", "ab:", 1, 1,
"[-a] " CMD_BUFFER_USAGE,
.args = { "ab:", 1, 1 }, 0,
.usage = "[-a] " CMD_BUFFER_USAGE " path", NULL,
NULL,
.flags = CMD_AFTERHOOK, cmd_save_buffer_exec
.exec = cmd_save_buffer_exec
}; };
const struct cmd_entry cmd_show_buffer_entry = { int
.name = "show-buffer", cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
.alias = "showb",
.args = { "b:", 0, 0 },
.usage = CMD_BUFFER_USAGE,
.flags = CMD_AFTERHOOK,
.exec = cmd_save_buffer_exec
};
static enum cmd_retval
cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->client; struct client *c = ctx->cmdclient;
struct session *s;
struct paste_buffer *pb; struct paste_buffer *pb;
const char *path, *bufname, *bufdata, *start, *end; const char *path, *newpath, *wd;
const char *flags; char *cause;
char *msg, *file; int buffer;
size_t size, used, msglen, bufsize; mode_t mask;
FILE *f; FILE *f;
if (!args_has(args, 'b')) { if (!args_has(args, 'b')) {
if ((pb = paste_get_top(NULL)) == NULL) { if ((pb = paste_get_top(&global_buffers)) == NULL) {
cmdq_error(item, "no buffers"); ctx->error(ctx, "no buffers");
return (CMD_RETURN_ERROR); return (-1);
} }
} else { } else {
bufname = args_get(args, 'b'); buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
pb = paste_get_name(bufname); if (cause != NULL) {
ctx->error(ctx, "buffer %s", cause);
xfree(cause);
return (-1);
}
pb = paste_get_index(&global_buffers, buffer);
if (pb == NULL) { if (pb == NULL) {
cmdq_error(item, "no buffer %s", bufname); ctx->error(ctx, "no buffer %d", buffer);
return (CMD_RETURN_ERROR); return (-1);
} }
} }
bufdata = paste_buffer_data(pb, &bufsize);
if (self->entry == &cmd_show_buffer_entry) path = args->argv[0];
path = "-";
else
path = args->argv[0];
if (strcmp(path, "-") == 0) { if (strcmp(path, "-") == 0) {
if (c == NULL) { if (c == NULL) {
cmdq_error(item, "can't write to stdout"); ctx->error(ctx, "%s: can't write to stdout", path);
return (CMD_RETURN_ERROR); return (-1);
}
bufferevent_write(c->stdout_event, pb->data, pb->size);
} else {
if (c != NULL)
wd = c->cwd;
else if ((s = cmd_current_session(ctx, 0)) != NULL) {
wd = options_get_string(&s->options, "default-path");
if (*wd == '\0')
wd = s->cwd;
} else
wd = NULL;
if (wd != NULL && *wd != '\0') {
newpath = get_full_path(wd, path);
if (newpath != NULL)
path = newpath;
} }
if (c->session == NULL || (c->flags & CLIENT_CONTROL))
goto do_stdout;
goto do_print;
}
flags = "wb"; mask = umask(S_IRWXG | S_IRWXO);
if (args_has(self->args, 'a')) if (args_has(self->args, 'a'))
flags = "ab"; f = fopen(path, "ab");
file = server_client_get_path(c, path);
f = fopen(file, flags);
if (f == NULL) {
cmdq_error(item, "%s: %s", file, strerror(errno));
free(file);
return (CMD_RETURN_ERROR);
}
if (fwrite(bufdata, 1, bufsize, f) != bufsize) {
cmdq_error(item, "%s: write error", file);
fclose(f);
return (CMD_RETURN_ERROR);
}
fclose(f);
free(file);
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(item, "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 else
size = bufsize - used; f = fopen(path, "wb");
umask(mask);
msglen = size * 4 + 1; if (f == NULL) {
msg = xrealloc(msg, msglen); ctx->error(ctx, "%s: %s", path, strerror(errno));
return (-1);
strvisx(msg, start, size, VIS_OCTAL|VIS_TAB); }
cmdq_print(item, "%s", msg); if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
ctx->error(ctx, "%s: fwrite error", path);
used += size + (end != NULL); fclose(f);
return (-1);
}
fclose(f);
} }
free(msg); return (0);
return (CMD_RETURN_NORMAL);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,123 +18,116 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Switch window to selected layout. * Switch window to selected layout.
*/ */
static enum cmd_retval cmd_select_layout_exec(struct cmd *, void cmd_select_layout_key_binding(struct cmd *, int);
struct cmdq_item *); int cmd_select_layout_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_select_layout_entry = { const struct cmd_entry cmd_select_layout_entry = {
.name = "select-layout", "select-layout", "selectl",
.alias = "selectl", "npt:", 0, 1,
"[-np] " CMD_TARGET_WINDOW_USAGE " [layout-name]",
.args = { "nopt:", 0, 1 }, 0,
.usage = "[-nop] " CMD_TARGET_WINDOW_USAGE " [layout-name]", cmd_select_layout_key_binding,
NULL,
.tflag = CMD_WINDOW, cmd_select_layout_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec
}; };
const struct cmd_entry cmd_next_layout_entry = { const struct cmd_entry cmd_next_layout_entry = {
.name = "next-layout", "next-layout", "nextl",
.alias = "nextl", "t:", 0, 0,
CMD_TARGET_WINDOW_USAGE,
.args = { "t:", 0, 0 }, 0,
.usage = CMD_TARGET_WINDOW_USAGE, NULL,
NULL,
.tflag = CMD_WINDOW, cmd_select_layout_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec
}; };
const struct cmd_entry cmd_previous_layout_entry = { const struct cmd_entry cmd_previous_layout_entry = {
.name = "previous-layout", "previous-layout", "prevl",
.alias = "prevl", "t:", 0, 0,
CMD_TARGET_WINDOW_USAGE,
.args = { "t:", 0, 0 }, 0,
.usage = CMD_TARGET_WINDOW_USAGE, NULL,
NULL,
.tflag = CMD_WINDOW, cmd_select_layout_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec
}; };
static enum cmd_retval void
cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item) cmd_select_layout_key_binding(struct cmd *self, int key)
{
switch (key) {
case '1' | KEYC_ESCAPE:
self->args = args_create(1, "even-horizontal");
break;
case '2' | KEYC_ESCAPE:
self->args = args_create(1, "even-vertical");
break;
case '3' | KEYC_ESCAPE:
self->args = args_create(1, "main-horizontal");
break;
case '4' | KEYC_ESCAPE:
self->args = args_create(1, "main-vertical");
break;
case '5' | KEYC_ESCAPE:
self->args = args_create(1, "tiled");
break;
default:
self->args = args_create(0);
break;
}
}
int
cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl;
struct window *w;
const char *layoutname; const char *layoutname;
char *oldlayout;
int next, previous, layout; int next, previous, layout;
w = wl->window; if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
server_unzoom_window(w); return (-1);
next = self->entry == &cmd_next_layout_entry; next = self->entry == &cmd_next_layout_entry;
if (args_has(args, 'n')) if (args_has(self->args, 'n'))
next = 1; next = 1;
previous = self->entry == &cmd_previous_layout_entry; previous = self->entry == &cmd_previous_layout_entry;
if (args_has(args, 'p')) if (args_has(self->args, 'p'))
previous = 1; previous = 1;
oldlayout = w->old_layout;
w->old_layout = layout_dump(w->layout_root);
if (next || previous) { if (next || previous) {
if (next) if (next)
layout_set_next(w); layout = layout_set_next(wl->window);
else else
layout_set_previous(w); layout = layout_set_previous(wl->window);
goto changed; ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
return (0);
} }
if (!args_has(args, 'o')) { if (args->argc == 0)
if (args->argc == 0) layout = wl->window->lastlayout;
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 else
layoutname = NULL; layout = layout_set_lookup(args->argv[0]);
if (layout != -1) {
if (layoutname != NULL) { layout = layout_set_select(wl->window, layout);
if (layout_parse(w, layoutname) == -1) { ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
cmdq_error(item, "can't set layout: %s", layoutname); return (0);
goto error;
}
goto changed;
} }
free(oldlayout); if (args->argc != 0) {
return (CMD_RETURN_NORMAL); layoutname = args->argv[0];
if (layout_parse(wl->window, layoutname) == -1) {
ctx->error(ctx, "can't set layout: %s", layoutname);
return (-1);
}
ctx->info(ctx, "arranging in: %s", layoutname);
return (0);
}
changed: return (0);
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$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -24,140 +24,93 @@
* Select pane. * Select pane.
*/ */
static enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmdq_item *); void cmd_select_pane_key_binding(struct cmd *, int);
int cmd_select_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_select_pane_entry = { const struct cmd_entry cmd_select_pane_entry = {
.name = "select-pane", "select-pane", "selectp",
.alias = "selectp", "lDLRt:U", 0, 0,
"[-lDLRU] " CMD_TARGET_PANE_USAGE,
.args = { "DdegLlMmP:Rt:U", 0, 0 }, 0,
.usage = "[-DdegLlMmRU] [-P style] " CMD_TARGET_PANE_USAGE, cmd_select_pane_key_binding,
NULL,
.tflag = CMD_PANE, cmd_select_pane_exec
.flags = 0,
.exec = cmd_select_pane_exec
}; };
const struct cmd_entry cmd_last_pane_entry = { const struct cmd_entry cmd_last_pane_entry = {
.name = "last-pane", "last-pane", "lastp",
.alias = "lastp", "t:", 0, 0,
CMD_TARGET_WINDOW_USAGE,
.args = { "det:", 0, 0 }, 0,
.usage = "[-de] " CMD_TARGET_WINDOW_USAGE, NULL,
NULL,
.tflag = CMD_WINDOW, cmd_select_pane_exec
.flags = 0,
.exec = cmd_select_pane_exec
}; };
static enum cmd_retval void
cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_select_pane_key_binding(struct cmd *self, int key)
{
self->args = args_create(0);
if (key == KEYC_UP)
args_set(self->args, 'U', NULL);
if (key == KEYC_DOWN)
args_set(self->args, 'D', NULL);
if (key == KEYC_LEFT)
args_set(self->args, 'L', NULL);
if (key == KEYC_RIGHT)
args_set(self->args, 'R', NULL);
if (key == 'o')
args_set(self->args, 't', ":.+");
}
int
cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct winlink *wl = item->state.tflag.wl; struct winlink *wl;
struct window *w = wl->window; struct window_pane *wp;
struct session *s = item->state.tflag.s;
struct window_pane *wp = item->state.tflag.wp, *lastwp, *markedwp;
const char *style;
if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) { if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
wl = cmd_find_window(ctx, args_get(args, 't'), NULL);
if (wl == NULL)
return (-1);
if (wl->window->last == NULL) { if (wl->window->last == NULL) {
cmdq_error(item, "no last pane"); ctx->error(ctx, "no last pane");
return (CMD_RETURN_ERROR); return (-1);
} }
if (args_has(self->args, 'e')) window_set_active_pane(wl->window, wl->window->last);
w->last->flags &= ~PANE_INPUTOFF; server_status_window(wl->window);
else if (args_has(self->args, 'd')) server_redraw_window_borders(wl->window);
w->last->flags |= PANE_INPUTOFF;
else {
server_unzoom_window(w);
window_redraw_active_switch(w, w->last);
if (window_set_active_pane(w, w->last)) {
server_status_window(w);
server_redraw_window_borders(w);
}
}
return (CMD_RETURN_NORMAL); return (0);
} }
if (args_has(args, 'm') || args_has(args, 'M')) { if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL)
if (args_has(args, 'm') && !window_pane_visible(wp)) return (-1);
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 (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(item, "bad style: %s", style);
return (CMD_RETURN_ERROR);
}
wp->flags |= PANE_REDRAW;
}
if (args_has(self->args, 'g'))
cmdq_print(item, "%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)) { if (!window_pane_visible(wp)) {
cmdq_error(item, "pane not visible"); ctx->error(ctx, "pane not visible");
return (CMD_RETURN_ERROR); return (-1);
}
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); if (args_has(self->args, 'L'))
wp = window_pane_find_left(wp);
else if (args_has(self->args, 'R'))
wp = window_pane_find_right(wp);
else if (args_has(self->args, 'U'))
wp = window_pane_find_up(wp);
else if (args_has(self->args, 'D'))
wp = window_pane_find_down(wp);
if (wp == NULL) {
ctx->error(ctx, "pane not found");
return (-1);
}
window_set_active_pane(wl->window, wp);
server_status_window(wl->window);
server_redraw_window_borders(wl->window);
return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -26,66 +26,69 @@
* Select window by index. * Select window by index.
*/ */
static enum cmd_retval cmd_select_window_exec(struct cmd *, void cmd_select_window_key_binding(struct cmd *, int);
struct cmdq_item *); int cmd_select_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_select_window_entry = { const struct cmd_entry cmd_select_window_entry = {
.name = "select-window", "select-window", "selectw",
.alias = "selectw", "lnpt:", 0, 0,
"[-lnp] " CMD_TARGET_WINDOW_USAGE,
.args = { "lnpTt:", 0, 0 }, 0,
.usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE, cmd_select_window_key_binding,
NULL,
.tflag = CMD_WINDOW, cmd_select_window_exec
.flags = 0,
.exec = cmd_select_window_exec
}; };
const struct cmd_entry cmd_next_window_entry = { const struct cmd_entry cmd_next_window_entry = {
.name = "next-window", "next-window", "next",
.alias = "next", "at:", 0, 0,
"[-a] " CMD_TARGET_SESSION_USAGE,
.args = { "at:", 0, 0 }, 0,
.usage = "[-a] " CMD_TARGET_SESSION_USAGE, cmd_select_window_key_binding,
NULL,
.tflag = CMD_SESSION, cmd_select_window_exec
.flags = 0,
.exec = cmd_select_window_exec
}; };
const struct cmd_entry cmd_previous_window_entry = { const struct cmd_entry cmd_previous_window_entry = {
.name = "previous-window", "previous-window", "prev",
.alias = "prev", "at:", 0, 0,
"[-a] " CMD_TARGET_SESSION_USAGE,
.args = { "at:", 0, 0 }, 0,
.usage = "[-a] " CMD_TARGET_SESSION_USAGE, cmd_select_window_key_binding,
NULL,
.tflag = CMD_SESSION, cmd_select_window_exec
.flags = 0,
.exec = cmd_select_window_exec
}; };
const struct cmd_entry cmd_last_window_entry = { const struct cmd_entry cmd_last_window_entry = {
.name = "last-window", "last-window", "last",
.alias = "last", "t:", 0, 0,
CMD_TARGET_SESSION_USAGE,
.args = { "t:", 0, 0 }, 0,
.usage = CMD_TARGET_SESSION_USAGE, NULL,
NULL,
.tflag = CMD_SESSION, cmd_select_window_exec
.flags = 0,
.exec = cmd_select_window_exec
}; };
static enum cmd_retval void
cmd_select_window_exec(struct cmd *self, struct cmdq_item *item) cmd_select_window_key_binding(struct cmd *self, int key)
{ {
struct winlink *wl = item->state.tflag.wl; char tmp[16];
struct session *s = item->state.tflag.s;
self->args = args_create(0);
if (key >= '0' && key <= '9') {
xsnprintf(tmp, sizeof tmp, ":%d", key - '0');
args_set(self->args, 't', tmp);
}
if (key == ('n' | KEYC_ESCAPE) || key == ('p' | KEYC_ESCAPE))
args_set(self->args, 'a', NULL);
}
int
cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct winlink *wl;
struct session *s;
int next, previous, last, activity; int next, previous, last, activity;
next = self->entry == &cmd_next_window_entry; next = self->entry == &cmd_next_window_entry;
@@ -99,40 +102,38 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
last = 1; last = 1;
if (next || previous || last) { if (next || previous || last) {
s = cmd_find_session(ctx, args_get(args, 't'), 0);
if (s == NULL)
return (-1);
activity = args_has(self->args, 'a'); activity = args_has(self->args, 'a');
if (next) { if (next) {
if (session_next(s, activity) != 0) { if (session_next(s, activity) != 0) {
cmdq_error(item, "no next window"); ctx->error(ctx, "no next window");
return (CMD_RETURN_ERROR); return (-1);
} }
} else if (previous) { } else if (previous) {
if (session_previous(s, activity) != 0) { if (session_previous(s, activity) != 0) {
cmdq_error(item, "no previous window"); ctx->error(ctx, "no previous window");
return (CMD_RETURN_ERROR); return (-1);
} }
} else { } else {
if (session_last(s) != 0) { if (session_last(s) != 0) {
cmdq_error(item, "no last window"); ctx->error(ctx, "no last window");
return (CMD_RETURN_ERROR); return (-1);
} }
} }
server_redraw_session(s); server_redraw_session(s);
} else { } else {
/* wl = cmd_find_window(ctx, args_get(args, 't'), &s);
* If -T and select-window is invoked on same window as if (wl == NULL)
* current, switch to previous window. return (-1);
*/
if (args_has(self->args, 'T') && wl == s->curw) { if (session_select(s, wl->idx) == 0)
if (session_last(s) != 0) {
cmdq_error(item, "no last window");
return (-1);
}
server_redraw_session(s);
} else if (session_select(s, wl->idx) == 0)
server_redraw_session(s); server_redraw_session(s);
} }
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -27,118 +27,57 @@
* Send keys to client. * Send keys to client.
*/ */
static enum cmd_retval cmd_send_keys_exec(struct cmd *, struct cmdq_item *); int cmd_send_keys_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_send_keys_entry = { const struct cmd_entry cmd_send_keys_entry = {
.name = "send-keys", "send-keys", "send",
.alias = "send", "Rt:", 0, -1,
"[-R] [-t target-pane] key ...",
.args = { "lXRMN:t:", 0, -1 }, 0,
.usage = "[-lXRM] [-N repeat-count] " CMD_TARGET_PANE_USAGE " key ...", NULL,
NULL,
.tflag = CMD_PANE, cmd_send_keys_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_send_keys_exec
}; };
const struct cmd_entry cmd_send_prefix_entry = { int
.name = "send-prefix", cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
.alias = NULL,
.args = { "2t:", 0, 0 },
.usage = "[-2] " CMD_TARGET_PANE_USAGE,
.tflag = CMD_PANE,
.flags = CMD_AFTERHOOK,
.exec = cmd_send_keys_exec
};
static enum cmd_retval
cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct window_pane *wp;
struct window_pane *wp = item->state.tflag.wp; struct session *s;
struct session *s = item->state.tflag.s; struct input_ctx *ictx;
struct mouse_event *m = &item->mouse; const char *str;
struct utf8_data *ud, *uc; int i, key;
wchar_t wc;
int i, literal;
key_code key;
u_int np = 1;
char *cause = NULL;
if (args_has(args, 'N')) { if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
np = args_strtonum(args, 'N', 1, UINT_MAX, &cause); return (-1);
if (cause != NULL) {
cmdq_error(item, "repeat count %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'X') || args->argc == 0)
wp->modeprefix = np;
}
if (args_has(args, 'X')) {
if (wp->mode == NULL || wp->mode->command == NULL) {
cmdq_error(item, "not in a mode");
return (CMD_RETURN_ERROR);
}
if (!m->valid)
wp->mode->command(wp, c, s, args, NULL);
else
wp->mode->command(wp, c, s, args, m);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'M')) {
wp = cmd_mouse_pane(m, &s, NULL);
if (wp == NULL) {
cmdq_error(item, "no mouse target");
return (CMD_RETURN_ERROR);
}
window_pane_key(wp, NULL, s, m->key, m);
return (CMD_RETURN_NORMAL);
}
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')) { if (args_has(args, 'R')) {
window_pane_reset_palette(wp); ictx = &wp->ictx;
input_reset(wp, 1);
memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
ictx->old_cx = 0;
ictx->old_cy = 0;
if (wp->mode == NULL)
screen_write_start(&ictx->ctx, wp, &wp->base);
else
screen_write_start(&ictx->ctx, NULL, &wp->base);
screen_write_reset(&ictx->ctx);
screen_write_stop(&ictx->ctx);
} }
for (; np != 0; np--) { for (i = 0; i < args->argc; i++) {
for (i = 0; i < args->argc; i++) { str = args->argv[i];
literal = args_has(args, 'l');
if (!literal) { if ((key = key_string_lookup_string(str)) != KEYC_NONE) {
key = key_string_lookup_string(args->argv[i]); window_pane_key(wp, s, key);
if (key != KEYC_NONE && key != KEYC_UNKNOWN) } else {
window_pane_key(wp, NULL, s, key, NULL); for (; *str != '\0'; str++)
else window_pane_key(wp, s, *str);
literal = 1;
}
if (literal) {
ud = utf8_fromcstr(args->argv[i]);
for (uc = ud; uc->size != 0; uc++) {
if (utf8_combine(uc, &wc) != UTF8_DONE)
continue;
window_pane_key(wp, NULL, s, wc, NULL);
}
free(ud);
}
} }
} }
return (CMD_RETURN_NORMAL); return (0);
} }

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

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

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

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

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,106 +18,58 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Add, set, append to or delete a paste buffer. * Add or set a paste buffer.
*/ */
static enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmdq_item *); int cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_set_buffer_entry = { const struct cmd_entry cmd_set_buffer_entry = {
.name = "set-buffer", "set-buffer", "setb",
.alias = "setb", "b:", 1, 1,
CMD_BUFFER_USAGE " data",
.args = { "ab:n:", 0, 1 }, 0,
.usage = "[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data", NULL,
NULL,
.flags = CMD_AFTERHOOK, cmd_set_buffer_exec
.exec = cmd_set_buffer_exec
}; };
const struct cmd_entry cmd_delete_buffer_entry = { int
.name = "delete-buffer", cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
.alias = "deleteb",
.args = { "b:", 0, 0 },
.usage = CMD_BUFFER_USAGE,
.flags = CMD_AFTERHOOK,
.exec = cmd_set_buffer_exec
};
static enum cmd_retval
cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct paste_buffer *pb; u_int limit;
char *bufdata, *cause; char *pdata, *cause;
const char *bufname, *olddata; size_t psize;
size_t bufsize, newsize; int buffer;
bufname = args_get(args, 'b'); limit = options_get_number(&global_options, "buffer-limit");
if (bufname == NULL)
pb = NULL;
else
pb = paste_get_name(bufname);
if (self->entry == &cmd_delete_buffer_entry) { pdata = xstrdup(args->argv[0]);
if (pb == NULL) psize = strlen(pdata);
pb = paste_get_top(&bufname);
if (pb == NULL) { if (!args_has(args, 'b')) {
cmdq_error(item, "no buffer"); paste_add(&global_buffers, pdata, psize, limit);
return (CMD_RETURN_ERROR); return (0);
}
paste_free(pb);
return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'n')) { buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (pb == NULL) if (cause != NULL) {
pb = paste_get_top(&bufname); ctx->error(ctx, "buffer %s", cause);
if (pb == NULL) { xfree(cause);
cmdq_error(item, "no buffer"); xfree(pdata);
return (CMD_RETURN_ERROR); return (-1);
}
if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
} }
if (args->argc != 1) { if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) {
cmdq_error(item, "no data specified"); ctx->error(ctx, "no buffer %d", buffer);
return (CMD_RETURN_ERROR); xfree(pdata);
} return (-1);
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); return (0);
memcpy(bufdata + bufsize, args->argv[0], newsize);
bufsize += newsize;
if (paste_set(bufdata, bufsize, bufname, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(bufdata);
free(cause);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -27,77 +27,68 @@
* Set an environment variable. * Set an environment variable.
*/ */
static enum cmd_retval cmd_set_environment_exec(struct cmd *, int cmd_set_environment_exec(struct cmd *, struct cmd_ctx *);
struct cmdq_item *);
const struct cmd_entry cmd_set_environment_entry = { const struct cmd_entry cmd_set_environment_entry = {
.name = "set-environment", "set-environment", "setenv",
.alias = "setenv", "grt:u", 1, 2,
"[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
.args = { "grt:u", 1, 2 }, 0,
.usage = "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]", NULL,
NULL,
.tflag = CMD_SESSION_CANFAIL, cmd_set_environment_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_set_environment_exec
}; };
static enum cmd_retval int
cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item) cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s;
struct environ *env; struct environ *env;
const char *name, *value, *target; const char *name, *value;
name = args->argv[0]; name = args->argv[0];
if (*name == '\0') { if (*name == '\0') {
cmdq_error(item, "empty variable name"); ctx->error(ctx, "empty variable name");
return (CMD_RETURN_ERROR); return (-1);
} }
if (strchr(name, '=') != NULL) { if (strchr(name, '=') != NULL) {
cmdq_error(item, "variable name contains ="); ctx->error(ctx, "variable name contains =");
return (CMD_RETURN_ERROR); return (-1);
} }
if (args->argc < 2) if (args->argc < 1)
value = NULL; value = NULL;
else else
value = args->argv[1]; value = args->argv[1];
if (args_has(self->args, 'g')) if (args_has(self->args, 'g'))
env = global_environ; env = &global_environ;
else { else {
if (item->state.tflag.s == NULL) { if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
target = args_get(args, 't'); return (-1);
if (target != NULL) env = &s->environ;
cmdq_error(item, "no such session: %s", target);
else
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
}
env = item->state.tflag.s->environ;
} }
if (args_has(self->args, 'u')) { if (args_has(self->args, 'u')) {
if (value != NULL) { if (value != NULL) {
cmdq_error(item, "can't specify a value with -u"); ctx->error(ctx, "can't specify a value with -u");
return (CMD_RETURN_ERROR); return (-1);
} }
environ_unset(env, name); environ_unset(env, name);
} else if (args_has(self->args, 'r')) { } else if (args_has(self->args, 'r')) {
if (value != NULL) { if (value != NULL) {
cmdq_error(item, "can't specify a value with -r"); ctx->error(ctx, "can't specify a value with -r");
return (CMD_RETURN_ERROR); return (-1);
} }
environ_clear(env, name); environ_set(env, name, NULL);
} else { } else {
if (value == NULL) { if (value == NULL) {
cmdq_error(item, "no value specified"); ctx->error(ctx, "no value specified");
return (CMD_RETURN_ERROR); return (-1);
} }
environ_set(env, name, "%s", value); environ_set(env, name, value);
} }
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,130 +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.
*/
static enum cmd_retval cmd_set_hook_exec(struct cmd *, struct cmdq_item *);
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 = CMD_AFTERHOOK,
.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 = CMD_AFTERHOOK,
.exec = cmd_set_hook_exec
};
static enum cmd_retval
cmd_set_hook_exec(struct cmd *self, struct cmdq_item *item)
{
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 (item->state.tflag.s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(item, "no such session: %s", target);
else
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
}
hooks = item->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(item, "%s -> %s", hook->name, tmp);
free(tmp);
hook = hooks_next(hook);
}
return (CMD_RETURN_NORMAL);
}
name = args->argv[0];
if (*name == '\0') {
cmdq_error(item, "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(item, "command passed to unset hook: %s",
name);
return (CMD_RETURN_ERROR);
}
hooks_remove(hooks, name);
return (CMD_RETURN_NORMAL);
}
if (cmd == NULL) {
cmdq_error(item, "no command to set hook: %s", name);
return (CMD_RETURN_ERROR);
}
cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);
if (cmdlist == NULL) {
if (cause != NULL) {
cmdq_error(item, "%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$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -27,366 +27,373 @@
* Set an option. * Set an option.
*/ */
static enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmdq_item *); int cmd_set_option_exec(struct cmd *, struct cmd_ctx *);
static int cmd_set_option_set(struct cmd *, struct cmdq_item *, int cmd_set_option_find(const char *, const struct options_table_entry **,
struct options *, struct options_entry *, const char *); const struct options_table_entry **);
static int cmd_set_option_flag(struct cmdq_item *,
const struct options_table_entry *, struct options *, int cmd_set_option_unset(struct cmd *, struct cmd_ctx *,
const char *); const struct options_table_entry *, struct options *,
static int cmd_set_option_choice(struct cmdq_item *, const char *);
const struct options_table_entry *, struct options *, int cmd_set_option_set(struct cmd *, struct cmd_ctx *,
const char *); const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_string(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_number(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_key(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_colour(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_attributes(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_flag(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *,
const char *);
struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *,
const char *);
const struct cmd_entry cmd_set_option_entry = { const struct cmd_entry cmd_set_option_entry = {
.name = "set-option", "set-option", "set",
.alias = "set", "agst:uw", 1, 2,
"[-agsuw] [-t target-session|target-window] option [value]",
.args = { "agoqst:uw", 1, 2 }, 0,
.usage = "[-agosquw] [-t target-window] option [value]", NULL,
NULL,
.tflag = CMD_WINDOW_CANFAIL, cmd_set_option_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec
}; };
const struct cmd_entry cmd_set_window_option_entry = { const struct cmd_entry cmd_set_window_option_entry = {
.name = "set-window-option", "set-window-option", "setw",
.alias = "setw", "agt:u", 1, 2,
"[-agu] " CMD_TARGET_WINDOW_USAGE " option [value]",
.args = { "agoqt:u", 1, 2 }, 0,
.usage = "[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]", NULL,
NULL,
.tflag = CMD_WINDOW_CANFAIL, cmd_set_option_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec
}; };
static enum cmd_retval /* Look for an option in all three tables. */
cmd_set_option_exec(struct cmd *self, struct cmdq_item *item) int
cmd_set_option_find(
const char *optstr, const struct options_table_entry **table,
const struct options_table_entry **oe)
{ {
struct args *args = self->args; static const struct options_table_entry *tables[] = {
int append = args_has(args, 'a'); server_options_table,
struct cmd_find_state *fs = &item->state.tflag; window_options_table,
struct session *s = fs->s; session_options_table
struct winlink *wl = fs->wl; };
struct window *w; const struct options_table_entry *oe_loop;
struct client *c; u_int i;
enum options_table_scope scope;
struct options *oo;
struct options_entry *parent, *o;
const char *name, *value, *target;
int window, idx, already, error, ambiguous;
char *cause;
/* Parse option name and index. */ for (i = 0; i < nitems(tables); i++) {
name = options_match(args->argv[0], &idx, &ambiguous); for (oe_loop = tables[i]; oe_loop->name != NULL; oe_loop++) {
if (name == NULL) { if (strncmp(oe_loop->name, optstr, strlen(optstr)) != 0)
if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL);
if (ambiguous)
cmdq_error(item, "ambiguous option: %s", args->argv[0]);
else
cmdq_error(item, "invalid option: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
if (args->argc < 2)
value = NULL;
else
value = args->argv[1];
/*
* Figure out the scope: for user options it comes from the arguments,
* otherwise from the option name.
*/
if (*name == '@') {
window = (self->entry == &cmd_set_window_option_entry);
scope = options_scope_from_flags(args, window, fs, &oo, &cause);
} else {
if (options_get_only(global_options, name) != NULL)
scope = OPTIONS_TABLE_SERVER;
else if (options_get_only(global_s_options, name) != NULL)
scope = OPTIONS_TABLE_SESSION;
else if (options_get_only(global_w_options, name) != NULL)
scope = OPTIONS_TABLE_WINDOW;
else {
scope = OPTIONS_TABLE_NONE;
xasprintf(&cause, "unknown option: %s", args->argv[0]);
}
}
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL);
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
/* Which table should this option go into? */
if (scope == OPTIONS_TABLE_SERVER)
oo = global_options;
else if (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(item, "no such session: %s", target);
else
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
} else
oo = s->options;
} else if (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(item, "no such window: %s", target);
else
cmdq_error(item, "no current window");
return (CMD_RETURN_ERROR);
} else
oo = wl->window->options;
}
o = options_get_only(oo, name);
parent = options_get(oo, name);
/* Check that array options and indexes match up. */
if (idx != -1) {
if (*name == '@' || options_array_size(parent, NULL) == -1) {
cmdq_error(item, "not an array: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
}
/* With -o, check this option is not already set. */
if (!args_has(args, 'u') && args_has(args, 'o')) {
if (idx == -1)
already = (o != NULL);
else {
if (o == NULL)
already = 0;
else
already = (options_array_get(o, idx) != NULL);
}
if (already) {
if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL);
cmdq_error(item, "already set: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
}
/* Change the option. */
if (args_has(args, 'u')) {
if (o == NULL)
return (CMD_RETURN_NORMAL);
if (idx == -1) {
if (oo == global_options ||
oo == global_s_options ||
oo == global_w_options)
options_default(oo, options_table_entry(o));
else
options_remove(o);
} else
options_array_set(o, idx, NULL, 0);
} else if (*name == '@') {
if (value == NULL) {
cmdq_error(item, "empty value");
return (CMD_RETURN_ERROR);
}
options_set_string(oo, name, append, "%s", value);
} else if (idx == -1 && options_array_size(parent, NULL) == -1) {
error = cmd_set_option_set(self, item, oo, parent, value);
if (error != 0)
return (CMD_RETURN_ERROR);
} else {
if (value == NULL) {
cmdq_error(item, "empty value");
return (CMD_RETURN_ERROR);
}
if (o == NULL)
o = options_empty(oo, options_table_entry(parent));
if (idx == -1) {
if (!append)
options_array_clear(o);
options_array_assign(o, value);
} else if (options_array_set(o, idx, value, append) != 0) {
cmdq_error(item, "invalid index: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
}
/* Update timers and so on for various options. */
if (strcmp(name, "automatic-rename") == 0) {
RB_FOREACH(w, windows, &windows) {
if (w->active == NULL)
continue; continue;
if (options_get_number(w->options, "automatic-rename"))
w->active->flags |= PANE_CHANGED; /* If already found, ambiguous. */
if (*oe != NULL)
return (-1);
*oe = oe_loop;
*table = tables[i];
/* Bail now if an exact match. */
if (strcmp((*oe)->name, optstr) == 0)
break;
} }
} }
if (strcmp(name, "key-table") == 0) { return (0);
TAILQ_FOREACH(c, &clients, entry)
server_client_set_key_table(c, NULL);
}
if (strcmp(name, "status") == 0 ||
strcmp(name, "status-interval") == 0)
status_timer_start_all();
if (strcmp(name, "monitor-silence") == 0)
alerts_reset_all();
if (strcmp(name, "window-style") == 0 ||
strcmp(name, "window-active-style") == 0) {
RB_FOREACH(w, windows, &windows)
w->flags |= WINDOW_STYLECHANGED;
}
if (strcmp(name, "pane-border-status") == 0) {
RB_FOREACH(w, windows, &windows)
layout_fix_panes(w, w->sx, w->sy);
}
RB_FOREACH (s, sessions, &sessions)
status_update_saved(s);
/*
* Update sizes and redraw. May not always be necessary but do it
* anyway.
*/
recalculate_sizes();
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != NULL)
server_redraw_client(c);
}
return (CMD_RETURN_NORMAL);
} }
static int int
cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo, cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
struct options_entry *parent, const char *value)
{ {
const struct options_table_entry *oe;
struct args *args = self->args; struct args *args = self->args;
int append = args_has(args, 'a'); const struct options_table_entry *table, *oe;
struct options_entry *o; struct session *s;
long long number; struct winlink *wl;
const char *errstr; struct client *c;
key_code key; struct options *oo;
const char *optstr, *valstr;
u_int i;
oe = options_table_entry(parent); /* Get the option name and value. */
if (value == NULL && optstr = args->argv[0];
oe->type != OPTIONS_TABLE_FLAG && if (*optstr == '\0') {
oe->type != OPTIONS_TABLE_CHOICE) { ctx->error(ctx, "invalid option");
cmdq_error(item, "empty value"); return (-1);
}
if (args->argc < 2)
valstr = NULL;
else
valstr = args->argv[1];
/* Find the option entry, try each table. */
table = oe = NULL;
if (cmd_set_option_find(optstr, &table, &oe) != 0) {
ctx->error(ctx, "ambiguous option: %s", optstr);
return (-1);
}
if (oe == NULL) {
ctx->error(ctx, "unknown option: %s", optstr);
return (-1); return (-1);
} }
switch (oe->type) { /* Work out the tree from the table. */
case OPTIONS_TABLE_STRING: if (table == server_options_table)
options_set_string(oo, oe->name, append, "%s", value); oo = &global_options;
return (0); else if (table == window_options_table) {
case OPTIONS_TABLE_NUMBER: if (args_has(self->args, 'g'))
number = strtonum(value, oe->minimum, oe->maximum, &errstr); oo = &global_w_options;
if (errstr != NULL) { else {
cmdq_error(item, "value is %s: %s", errstr, value); wl = cmd_find_window(ctx, args_get(args, 't'), NULL);
return (-1); if (wl == NULL)
return (-1);
oo = &wl->window->options;
} }
options_set_number(oo, oe->name, number); } else if (table == session_options_table) {
return (0); if (args_has(self->args, 'g'))
case OPTIONS_TABLE_KEY: oo = &global_s_options;
key = key_string_lookup_string(value); else {
if (key == KEYC_UNKNOWN) { s = cmd_find_session(ctx, args_get(args, 't'), 0);
cmdq_error(item, "bad key: %s", value); if (s == NULL)
return (-1); return (-1);
oo = &s->options;
} }
options_set_number(oo, oe->name, key); } else {
return (0); ctx->error(ctx, "unknown table");
case OPTIONS_TABLE_COLOUR: return (-1);
if ((number = colour_fromstring(value)) == -1) {
cmdq_error(item, "bad colour: %s", value);
return (-1);
}
o = options_set_number(oo, oe->name, number);
options_style_update_new(oo, o);
return (0);
case OPTIONS_TABLE_ATTRIBUTES:
if ((number = attributes_fromstring(value)) == -1) {
cmdq_error(item, "bad attributes: %s", value);
return (-1);
}
o = options_set_number(oo, oe->name, number);
options_style_update_new(oo, o);
return (0);
case OPTIONS_TABLE_FLAG:
return (cmd_set_option_flag(item, oe, oo, value));
case OPTIONS_TABLE_CHOICE:
return (cmd_set_option_choice(item, oe, oo, value));
case OPTIONS_TABLE_STYLE:
o = options_set_style(oo, oe->name, append, value);
if (o == NULL) {
cmdq_error(item, "bad style: %s", value);
return (-1);
}
options_style_update_old(oo, o);
return (0);
case OPTIONS_TABLE_ARRAY:
break;
} }
return (-1);
/* Unset or set the option. */
if (args_has(args, 'u')) {
if (cmd_set_option_unset(self, ctx, oe, oo, valstr) != 0)
return (-1);
} else {
if (cmd_set_option_set(self, ctx, oe, oo, valstr) != 0)
return (-1);
}
/* Update sizes and redraw. May not need it but meh. */
recalculate_sizes();
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c != NULL && c->session != NULL)
server_redraw_client(c);
}
return (0);
} }
static int /* Unset an option. */
cmd_set_option_flag(struct cmdq_item *item, int
const struct options_table_entry *oe, struct options *oo, cmd_set_option_unset(struct cmd *self, struct cmd_ctx *ctx,
const char *value) const struct options_table_entry *oe, struct options *oo, const char *value)
{
struct args *args = self->args;
if (args_has(args, 'g')) {
ctx->error(ctx, "can't unset global option: %s", oe->name);
return (-1);
}
if (value != NULL) {
ctx->error(ctx, "value passed to unset option: %s", oe->name);
return (-1);
}
options_remove(oo, oe->name);
ctx->info(ctx, "unset option: %s", oe->name);
return (0);
}
/* Set an option. */
int
cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const char *value)
{
struct options_entry *o;
const char *s;
if (oe->type != OPTIONS_TABLE_FLAG && value == NULL) {
ctx->error(ctx, "empty value");
return (-1);
}
o = NULL;
switch (oe->type) {
case OPTIONS_TABLE_STRING:
o = cmd_set_option_string(self, ctx, oe, oo, value);
break;
case OPTIONS_TABLE_NUMBER:
o = cmd_set_option_number(self, ctx, oe, oo, value);
break;
case OPTIONS_TABLE_KEY:
o = cmd_set_option_key(self, ctx, oe, oo, value);
break;
case OPTIONS_TABLE_COLOUR:
o = cmd_set_option_colour(self, ctx, oe, oo, value);
break;
case OPTIONS_TABLE_ATTRIBUTES:
o = cmd_set_option_attributes(self, ctx, oe, oo, value);
break;
case OPTIONS_TABLE_FLAG:
o = cmd_set_option_flag(self, ctx, oe, oo, value);
break;
case OPTIONS_TABLE_CHOICE:
o = cmd_set_option_choice(self, ctx, oe, oo, value);
break;
}
if (o == NULL)
return (-1);
s = options_table_print_entry(oe, o);
ctx->info(ctx, "set option: %s -> %s", oe->name, s);
return (0);
}
/* Set a string option. */
struct options_entry *
cmd_set_option_string(struct cmd *self, unused struct cmd_ctx *ctx,
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);
xfree(newval);
return (o);
}
/* Set a number option. */
struct options_entry *
cmd_set_option_number(unused struct cmd *self, struct cmd_ctx *ctx,
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) {
ctx->error(ctx, "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_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const char *value)
{
int key;
if ((key = key_string_lookup_string(value)) == KEYC_NONE) {
ctx->error(ctx, "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_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const char *value)
{
int colour;
if ((colour = colour_fromstring(value)) == -1) {
ctx->error(ctx, "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_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const char *value)
{
int attr;
if ((attr = attributes_fromstring(value)) == -1) {
ctx->error(ctx, "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_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const char *value)
{ {
int flag; int flag;
if (value == NULL || *value == '\0') if (value == NULL || *value == '\0')
flag = !options_get_number(oo, oe->name); flag = !options_get_number(oo, oe->name);
else if (strcmp(value, "1") == 0 ||
strcasecmp(value, "on") == 0 ||
strcasecmp(value, "yes") == 0)
flag = 1;
else if (strcmp(value, "0") == 0 ||
strcasecmp(value, "off") == 0 ||
strcasecmp(value, "no") == 0)
flag = 0;
else { else {
cmdq_error(item, "bad value: %s", value); if ((value[0] == '1' && value[1] == '\0') ||
return (-1); 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 {
ctx->error(ctx, "bad value: %s", value);
return (NULL);
}
} }
options_set_number(oo, oe->name, flag);
return (0); return (options_set_number(oo, oe->name, flag));
} }
static int /* Set a choice option. */
cmd_set_option_choice(struct cmdq_item *item, struct options_entry *
const struct options_table_entry *oe, struct options *oo, cmd_set_option_choice(unused struct cmd *self, struct cmd_ctx *ctx,
const char *value) const struct options_table_entry *oe, struct options *oo, const char *value)
{ {
const char **cp; const char **choicep;
int n, choice = -1; int n, choice = -1;
if (value == NULL) { n = 0;
choice = options_get_number(oo, oe->name); for (choicep = oe->choices; *choicep != NULL; choicep++) {
if (choice < 2) n++;
choice = !choice; if (strncmp(*choicep, value, strlen(value)) != 0)
} else { continue;
n = 0;
for (cp = oe->choices; *cp != NULL; cp++) { if (choice != -1) {
if (strcmp(*cp, value) == 0) ctx->error(ctx, "ambiguous value: %s", value);
choice = n; return (NULL);
n++;
}
if (choice == -1) {
cmdq_error(item, "unknown value: %s", value);
return (-1);
} }
choice = n - 1;
} }
options_set_number(oo, oe->name, choice); if (choice == -1) {
return (0); ctx->error(ctx, "unknown value: %s", value);
return (NULL);
}
return (options_set_number(oo, oe->name, choice));
} }

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

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

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -27,110 +27,40 @@
* Show environment. * Show environment.
*/ */
static enum cmd_retval cmd_show_environment_exec(struct cmd *, int cmd_show_environment_exec(struct cmd *, struct cmd_ctx *);
struct cmdq_item *);
static char *cmd_show_environment_escape(struct environ_entry *);
static void cmd_show_environment_print(struct cmd *, struct cmdq_item *,
struct environ_entry *);
const struct cmd_entry cmd_show_environment_entry = { const struct cmd_entry cmd_show_environment_entry = {
.name = "show-environment", "show-environment", "showenv",
.alias = "showenv", "gt:", 0, 0,
"[-g] " CMD_TARGET_SESSION_USAGE,
.args = { "gst:", 0, 1 }, 0,
.usage = "[-gs] " CMD_TARGET_SESSION_USAGE " [name]", NULL,
NULL,
.tflag = CMD_SESSION_CANFAIL, cmd_show_environment_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_show_environment_exec
}; };
static char * int
cmd_show_environment_escape(struct environ_entry *envent) cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
{
const char *value = envent->value;
char c, *out, *ret;
out = ret = xmalloc(strlen(value) * 2 + 1); /* at most twice the size */
while ((c = *value++) != '\0') {
/* POSIX interprets $ ` " and \ in double quotes. */
if (c == '$' || c == '`' || c == '"' || c == '\\')
*out++ = '\\';
*out++ = c;
}
*out = '\0';
return (ret);
}
static void
cmd_show_environment_print(struct cmd *self, struct cmdq_item *item,
struct environ_entry *envent)
{
char *escaped;
if (!args_has(self->args, 's')) {
if (envent->value != NULL)
cmdq_print(item, "%s=%s", envent->name, envent->value);
else
cmdq_print(item, "-%s", envent->name);
return;
}
if (envent->value != NULL) {
escaped = cmd_show_environment_escape(envent);
cmdq_print(item, "%s=\"%s\"; export %s;", envent->name, escaped,
envent->name);
free(escaped);
} else
cmdq_print(item, "unset %s;", envent->name);
}
static enum cmd_retval
cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct session *s;
struct environ *env; struct environ *env;
struct environ_entry *envent; struct environ_entry *envent;
const char *target;
if ((target = args_get(args, 't')) != NULL) {
if (item->state.tflag.s == NULL) {
cmdq_error(item, "no such session: %s", target);
return (CMD_RETURN_ERROR);
}
}
if (args_has(self->args, 'g')) if (args_has(self->args, 'g'))
env = global_environ; env = &global_environ;
else { else {
if (item->state.tflag.s == NULL) { if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
target = args_get(args, 't'); return (-1);
if (target != NULL) env = &s->environ;
cmdq_error(item, "no such session: %s", target);
else
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
}
env = item->state.tflag.s->environ;
} }
if (args->argc != 0) { RB_FOREACH(envent, environ, env) {
envent = environ_find(env, args->argv[0]); if (envent->value != NULL)
if (envent == NULL) { ctx->print(ctx, "%s=%s", envent->name, envent->value);
cmdq_error(item, "unknown variable: %s", args->argv[0]); else
return (CMD_RETURN_ERROR); ctx->print(ctx, "-%s", envent->name);
}
cmd_show_environment_print(self, item, envent);
return (CMD_RETURN_NORMAL);
} }
envent = environ_first(env); return (0);
while (envent != NULL) {
cmd_show_environment_print(self, item, envent);
envent = environ_next(envent);
}
return (CMD_RETURN_NORMAL);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -20,7 +20,6 @@
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -28,92 +27,38 @@
* Show client message log. * Show client message log.
*/ */
static enum cmd_retval cmd_show_messages_exec(struct cmd *, int cmd_show_messages_exec(struct cmd *, struct cmd_ctx *);
struct cmdq_item *);
const struct cmd_entry cmd_show_messages_entry = { const struct cmd_entry cmd_show_messages_entry = {
.name = "show-messages", "show-messages", "showmsgs",
.alias = "showmsgs", "t:", 0, 0,
CMD_TARGET_CLIENT_USAGE,
.args = { "JTt:", 0, 0 }, 0,
.usage = "[-JT] " CMD_TARGET_CLIENT_USAGE, NULL,
NULL,
.tflag = CMD_CLIENT, cmd_show_messages_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_show_messages_exec
}; };
static int cmd_show_messages_terminals(struct cmdq_item *, int); int
static int cmd_show_messages_jobs(struct cmdq_item *, int); cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx)
static int
cmd_show_messages_terminals(struct cmdq_item *item, int blank)
{
struct tty_term *term;
u_int i, n;
n = 0;
LIST_FOREACH(term, &tty_terms, entry) {
if (blank) {
cmdq_print(item, "%s", "");
blank = 0;
}
cmdq_print(item, "Terminal %u: %s [references=%u, flags=0x%x]:",
n, term->name, term->references, term->flags);
n++;
for (i = 0; i < tty_term_ncodes(); i++)
cmdq_print(item, "%s", tty_term_describe(term, i));
}
return (n != 0);
}
static int
cmd_show_messages_jobs(struct cmdq_item *item, int blank)
{
struct job *job;
u_int n;
n = 0;
LIST_FOREACH(job, &all_jobs, lentry) {
if (blank) {
cmdq_print(item, "%s", "");
blank = 0;
}
cmdq_print(item, "Job %u: %s [fd=%d, pid=%ld, status=%d]",
n, job->cmd, job->fd, (long)job->pid, job->status);
n++;
}
return (n != 0);
}
static enum cmd_retval
cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct client *c;
struct message_entry *msg; struct message_entry *msg;
char *tim; char *tim;
int done, blank; u_int i;
done = blank = 0; if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
if (args_has(args, 'T')) { return (-1);
blank = cmd_show_messages_terminals(item, blank);
done = 1; for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) {
} msg = &ARRAY_ITEM(&c->message_log, i);
if (args_has(args, 'J')) {
cmd_show_messages_jobs(item, blank);
done = 1;
}
if (done)
return (CMD_RETURN_NORMAL);
TAILQ_FOREACH(msg, &c->message_log, entry) {
tim = ctime(&msg->msg_time); tim = ctime(&msg->msg_time);
*strchr(tim, '\n') = '\0'; *strchr(tim, '\n') = '\0';
cmdq_print(item, "%s %s", tim, msg->msg); ctx->print(ctx, "%s %s", tim, msg->msg);
} }
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -27,153 +27,71 @@
* Show options. * Show options.
*/ */
static enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmdq_item *); int cmd_show_options_exec(struct cmd *, struct cmd_ctx *);
static enum cmd_retval cmd_show_options_one(struct cmd *, struct cmdq_item *,
struct options *);
static enum cmd_retval cmd_show_options_all(struct cmd *, struct cmdq_item *,
struct options *);
const struct cmd_entry cmd_show_options_entry = { const struct cmd_entry cmd_show_options_entry = {
.name = "show-options", "show-options", "show",
.alias = "show", "gst:w", 0, 0,
"[-gsw] [-t target-session|target-window]",
.args = { "gqst:vw", 0, 1 }, 0,
.usage = "[-gqsvw] [-t target-session|target-window] [option]", NULL,
NULL,
.tflag = CMD_WINDOW_CANFAIL, cmd_show_options_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec
}; };
const struct cmd_entry cmd_show_window_options_entry = { const struct cmd_entry cmd_show_window_options_entry = {
.name = "show-window-options", "show-window-options", "showw",
.alias = "showw", "gt:", 0, 0,
"[-g] " CMD_TARGET_WINDOW_USAGE,
.args = { "gvt:", 0, 1 }, 0,
.usage = "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]", NULL,
NULL,
.tflag = CMD_WINDOW_CANFAIL, cmd_show_options_exec
.flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec
}; };
static enum cmd_retval int
cmd_show_options_exec(struct cmd *self, struct cmdq_item *item) cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_find_state *fs = &item->state.tflag; const struct options_table_entry *table, *oe;
struct options *oo; struct session *s;
enum options_table_scope scope; struct winlink *wl;
char *cause; struct options *oo;
int window; struct options_entry *o;
const char *optval;
window = (self->entry == &cmd_show_window_options_entry); if (args_has(self->args, 's')) {
scope = options_scope_from_flags(args, window, fs, &oo, &cause); oo = &global_options;
if (scope == OPTIONS_TABLE_NONE) { table = server_options_table;
cmdq_error(item, "%s", cause); } else if (args_has(self->args, 'w') ||
free(cause); self->entry == &cmd_show_window_options_entry) {
return (CMD_RETURN_ERROR); table = window_options_table;
} if (args_has(self->args, 'g'))
oo = &global_w_options;
if (args->argc == 0)
return (cmd_show_options_all(self, item, oo));
else
return (cmd_show_options_one(self, item, oo));
}
static void
cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
struct options_entry *o, int idx)
{
const char *name;
const char *value;
char *tmp, *escaped;
u_int size, i;
if (idx != -1) {
xasprintf(&tmp, "%s[%d]", options_name(o), idx);
name = tmp;
} else {
if (options_array_size(o, &size) != -1) {
for (i = 0; i < size; i++) {
if (options_array_get(o, i) == NULL)
continue;
cmd_show_options_print(self, item, o, i);
}
return;
}
tmp = NULL;
name = options_name(o);
}
value = options_tostring(o, idx, 0);
if (args_has(self->args, 'v'))
cmdq_print(item, "%s", value);
else if (options_isstring(o)) {
utf8_stravis(&escaped, value, VIS_OCTAL|VIS_TAB|VIS_NL|VIS_DQ);
cmdq_print(item, "%s \"%s\"", name, escaped);
free(escaped);
} else
cmdq_print(item, "%s %s", name, value);
free(tmp);
}
static enum cmd_retval
cmd_show_options_one(struct cmd *self, struct cmdq_item *item,
struct options *oo)
{
struct args *args = self->args;
struct options_entry *o;
int idx, ambiguous;
const char *name = args->argv[0];
o = options_match_get(oo, name, &idx, 1, &ambiguous);
if (o == NULL) {
if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL);
if (ambiguous) {
cmdq_error(item, "ambiguous option: %s", name);
return (CMD_RETURN_ERROR);
}
if (*name != '@' &&
options_match_get(oo, name, &idx, 0, &ambiguous) != NULL)
return (CMD_RETURN_NORMAL);
cmdq_error(item, "unknown option: %s", name);
return (CMD_RETURN_ERROR);
}
cmd_show_options_print(self, item, o, idx);
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_show_options_all(struct cmd *self, struct cmdq_item *item,
struct options *oo)
{
struct options_entry *o;
const struct options_table_entry *oe;
u_int size, idx;
o = options_first(oo);
while (o != NULL) {
oe = options_table_entry(o);
if (oe != NULL && oe->style != NULL) {
o = options_next(o);
continue;
}
if (options_array_size(o, &size) == -1)
cmd_show_options_print(self, item, o, -1);
else { else {
for (idx = 0; idx < size; idx++) { wl = cmd_find_window(ctx, args_get(args, 't'), NULL);
if (options_array_get(o, idx) == NULL) if (wl == NULL)
continue; return (-1);
cmd_show_options_print(self, item, o, idx); oo = &wl->window->options;
} }
} else {
table = session_options_table;
if (args_has(self->args, 'g'))
oo = &global_s_options;
else {
s = cmd_find_session(ctx, args_get(args, 't'), 0);
if (s == NULL)
return (-1);
oo = &s->options;
} }
o = options_next(o);
} }
return (CMD_RETURN_NORMAL);
for (oe = table; oe->name != NULL; oe++) {
if ((o = options_find1(oo, oe->name)) == NULL)
continue;
optval = options_table_print_entry(oe, o);
ctx->print(ctx, "%s %s", oe->name, optval);
}
return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* Copyright (c) 2008 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2008 Tiago Cunha <me@tiagocunha.org>
@@ -18,81 +18,57 @@
#include <sys/types.h> #include <sys/types.h>
#include <errno.h>
#include <glob.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Sources a configuration file. * Sources a configuration file.
*/ */
static enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmdq_item *); int cmd_source_file_exec(struct cmd *, struct cmd_ctx *);
static enum cmd_retval cmd_source_file_done(struct cmdq_item *, void *);
const struct cmd_entry cmd_source_file_entry = { const struct cmd_entry cmd_source_file_entry = {
.name = "source-file", "source-file", "source",
.alias = "source", "", 1, 1,
"path",
.args = { "q", 1, 1 }, 0,
.usage = "[-q] path", NULL,
NULL,
.flags = 0, cmd_source_file_exec
.exec = cmd_source_file_exec
}; };
static enum cmd_retval int
cmd_source_file_exec(struct cmd *self, struct cmdq_item *item) cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
int quiet = args_has(args, 'q'); struct causelist causes;
struct client *c = item->client; char *cause;
struct cmdq_item *new_item; struct window_pane *wp;
enum cmd_retval retval; int retval;
char *pattern, *tmp;
const char *path = args->argv[0];
glob_t g;
u_int i; u_int i;
if (*path == '/') ARRAY_INIT(&causes);
pattern = xstrdup(path);
else {
utf8_stravis(&tmp, server_client_get_cwd(c), VIS_GLOB);
xasprintf(&pattern, "%s/%s", tmp, path);
free(tmp);
}
log_debug("%s: %s", __func__, pattern);
retval = CMD_RETURN_NORMAL; retval = load_cfg(args->argv[0], ctx, &causes);
if (glob(pattern, 0, NULL, &g) != 0) { if (ARRAY_EMPTY(&causes))
if (!quiet || errno != ENOENT) {
cmdq_error(item, "%s: %s", path, strerror(errno));
retval = CMD_RETURN_ERROR;
}
free(pattern);
return (retval); return (retval);
}
free(pattern);
for (i = 0; i < (u_int)g.gl_pathc; i++) { if (retval == 1 && !RB_EMPTY(&sessions) && ctx->cmdclient != NULL) {
if (load_cfg(g.gl_pathv[i], c, item, quiet) < 0) wp = RB_MIN(sessions, &sessions)->curw->window->active;
retval = CMD_RETURN_ERROR; window_pane_set_mode(wp, &window_copy_mode);
} window_copy_init_for_output(wp);
if (cfg_finished) { for (i = 0; i < ARRAY_LENGTH(&causes); i++) {
new_item = cmdq_get_callback(cmd_source_file_done, NULL); cause = ARRAY_ITEM(&causes, i);
cmdq_insert_after(item, new_item); window_copy_add(wp, "%s", cause);
xfree(cause);
}
} else {
for (i = 0; i < ARRAY_LENGTH(&causes); i++) {
cause = ARRAY_ITEM(&causes, i);
ctx->print(ctx, "%s", cause);
xfree(cause);
}
} }
ARRAY_FREE(&causes);
globfree(&g);
return (retval); return (retval);
} }
static enum cmd_retval
cmd_source_file_done(struct cmdq_item *item, __unused void *data)
{
cfg_print_causes(item);
return (CMD_RETURN_NORMAL);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,10 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -30,68 +27,57 @@
* Split a window (add a new pane). * Split a window (add a new pane).
*/ */
#define SPLIT_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" void cmd_split_window_key_binding(struct cmd *, int);
int cmd_split_window_exec(struct cmd *, struct cmd_ctx *);
static enum cmd_retval cmd_split_window_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_split_window_entry = { const struct cmd_entry cmd_split_window_entry = {
.name = "split-window", "split-window", "splitw",
.alias = "splitw", "dl:hp:Pt:v", 0, 1,
"[-dhvP] [-p percentage|-l size] [-t target-pane] [command]",
.args = { "bc:dfF:l:hp:Pt:v", 0, -1 }, 0,
.usage = "[-bdfhvP] [-c start-directory] [-F format] " cmd_split_window_key_binding,
"[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]", NULL,
cmd_split_window_exec
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_split_window_exec
}; };
static enum cmd_retval void
cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) cmd_split_window_key_binding(struct cmd *self, int key)
{
self->args = args_create(0);
if (key == '%')
args_set(self->args, 'h', NULL);
}
int
cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = item->state.c; struct session *s;
struct session *s = item->state.tflag.s; struct winlink *wl;
struct winlink *wl = item->state.tflag.wl; struct window *w;
struct window *w = wl->window; struct window_pane *wp, *new_wp = NULL;
struct window_pane *wp = item->state.tflag.wp, *new_wp = NULL; struct environ env;
struct environ *env; const char *cmd, *cwd, *shell;
const char *cmd, *path, *shell, *template, *cwd, *to_free; char *cause, *new_cause;
char **argv, *cause, *new_cause, *cp; u_int hlimit, paneidx;
u_int hlimit; int size, percentage;
int argc, size, percentage;
enum layout_type type; enum layout_type type;
struct layout_cell *lc; struct layout_cell *lc;
struct environ_entry *envent;
struct cmd_find_state fs;
server_unzoom_window(w); if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL)
return (-1);
w = wl->window;
if (args->argc == 0) { environ_init(&env);
cmd = options_get_string(s->options, "default-command"); environ_copy(&global_environ, &env);
if (cmd != NULL && *cmd != '\0') { environ_copy(&s->environ, &env);
argc = 1; server_fill_environ(s, &env);
argv = (char **)&cmd;
} else {
argc = 0;
argv = NULL;
}
} else {
argc = args->argc;
argv = args->argv;
}
to_free = NULL; if (args->argc == 0)
if (args_has(args, 'c')) { cmd = options_get_string(&s->options, "default-command");
cwd = args_get(args, 'c');
to_free = cwd = format_single(item, cwd, c, s, NULL, NULL);
} else if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
else else
cwd = s->cwd; cmd = args->argv[0];
cwd = cmd_get_default_path(ctx);
type = LAYOUT_TOPBOTTOM; type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h')) if (args_has(args, 'h'))
@@ -102,7 +88,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
size = args_strtonum(args, 'l', 0, INT_MAX, &cause); size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) { if (cause != NULL) {
xasprintf(&new_cause, "size %s", cause); xasprintf(&new_cause, "size %s", cause);
free(cause); xfree(cause);
cause = new_cause; cause = new_cause;
goto error; goto error;
} }
@@ -110,7 +96,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause); percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause);
if (cause != NULL) { if (cause != NULL) {
xasprintf(&new_cause, "percentage %s", cause); xasprintf(&new_cause, "percentage %s", cause);
free(cause); xfree(cause);
cause = new_cause; cause = new_cause;
goto error; goto error;
} }
@@ -119,36 +105,21 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
else else
size = (wp->sx * percentage) / 100; size = (wp->sx * percentage) / 100;
} }
hlimit = options_get_number(s->options, "history-limit"); hlimit = options_get_number(&s->options, "history-limit");
shell = options_get_string(s->options, "default-shell"); shell = options_get_string(&s->options, "default-shell");
if (*shell == '\0' || areshell(shell)) if (*shell == '\0' || areshell(shell))
shell = _PATH_BSHELL; shell = _PATH_BSHELL;
lc = layout_split_pane(wp, type, size, args_has(args, 'b'), if ((lc = layout_split_pane(wp, type, size)) == NULL) {
args_has(args, 'f'));
if (lc == NULL) {
cause = xstrdup("pane too small"); cause = xstrdup("pane too small");
goto error; goto error;
} }
new_wp = window_add_pane(w, wp, args_has(args, 'b'), hlimit); new_wp = window_add_pane(w, hlimit);
layout_assign_pane(lc, new_wp); if (window_pane_spawn(
new_wp, cmd, shell, cwd, &env, s->tio, &cause) != 0)
path = NULL;
if (item->client != NULL && item->client->session == NULL)
envent = environ_find(item->client->environ, "PATH");
else
envent = environ_find(s->environ, "PATH");
if (envent != NULL)
path = envent->value;
env = environ_for_session(s);
if (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, env,
s->tio, &cause) != 0) {
environ_free(env);
goto error; goto error;
} layout_assign_pane(lc, new_wp);
environ_free(env);
server_redraw_window(w); server_redraw_window(w);
@@ -159,37 +130,20 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
} else } else
server_status_session(s); server_status_session(s);
environ_free(&env);
if (args_has(args, 'P')) { if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL) if (window_pane_index(new_wp, &paneidx) != 0)
template = SPLIT_WINDOW_TEMPLATE; fatalx("index not found");
cp = format_single(item, template, c, s, wl, new_wp); ctx->print(ctx, "%s:%u.%u", s->name, wl->idx, paneidx);
cmdq_print(item, "%s", cp);
free(cp);
} }
notify_window("window-layout-changed", w); return (0);
if (to_free != NULL)
free((void *)to_free);
cmd_find_clear_state(&fs, NULL, 0);
fs.s = s;
fs.wl = wl;
fs.w = w;
fs.wp = new_wp;
cmd_find_log_state(__func__, &fs);
hooks_insert(s->hooks, item, &fs, "after-split-window");
return (CMD_RETURN_NORMAL);
error: error:
if (new_wp != NULL) { environ_free(&env);
layout_close_pane(new_wp); if (new_wp != NULL)
window_remove_pane(w, new_wp); window_remove_pane(w, new_wp);
} ctx->error(ctx, "create pane failed: %s", cause);
cmdq_error(item, "create pane failed: %s", cause); xfree(cause);
free(cause); return (-1);
if (to_free != NULL)
free((void *)to_free);
return (CMD_RETURN_ERROR);
} }

View File

@@ -1,5 +1,7 @@
/* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -16,28 +18,27 @@
#include <sys/types.h> #include <sys/types.h>
#include <errno.h> #include "tmux.h"
#include "compat.h" /*
* Start the server and do nothing else.
*/
#if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME) int cmd_start_server_exec(struct cmd *, struct cmd_ctx *);
const char *
getprogname(void)
{
return (program_invocation_short_name);
}
#elif defined(HAVE___PROGNAME)
const char *
getprogname(void)
{
extern char *__progname;
return (__progname); const struct cmd_entry cmd_start_server_entry = {
} "start-server", "start",
#else "", 0, 0,
const char * "",
getprogname(void) CMD_STARTSERVER,
NULL,
NULL,
cmd_start_server_exec
};
/* ARGSUSED */
int
cmd_start_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
{ {
return ("tmux"); return (0);
} }
#endif

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -31,14 +31,13 @@
* Parse a command from a string. * Parse a command from a string.
*/ */
static int cmd_string_getc(const char *, size_t *); int cmd_string_getc(const char *, size_t *);
static void cmd_string_ungetc(size_t *); void cmd_string_ungetc(size_t *);
static void cmd_string_copy(char **, char *, size_t *); char *cmd_string_string(const char *, size_t *, char, int);
static char *cmd_string_string(const char *, size_t *, char, int); char *cmd_string_variable(const char *, size_t *);
static char *cmd_string_variable(const char *, size_t *); char *cmd_string_expand_tilde(const char *, size_t *);
static char *cmd_string_expand_tilde(const char *, size_t *);
static int int
cmd_string_getc(const char *s, size_t *p) cmd_string_getc(const char *s, size_t *p)
{ {
const u_char *ucs = s; const u_char *ucs = s;
@@ -48,38 +47,63 @@ cmd_string_getc(const char *s, size_t *p)
return (ucs[(*p)++]); return (ucs[(*p)++]);
} }
static void void
cmd_string_ungetc(size_t *p) cmd_string_ungetc(size_t *p)
{ {
(*p)--; (*p)--;
} }
/*
* Parse command string. Returns -1 on error. If returning -1, cause is error
* string, or NULL for empty command.
*/
int int
cmd_string_split(const char *s, int *rargc, char ***rargv) cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
{ {
size_t p = 0; size_t p;
int ch, argc = 0, append = 0; int ch, i, argc, rval;
char **argv = NULL, *buf = NULL, *t; char **argv, *buf, *t;
const char *whitespace, *equals; const char *whitespace, *equals;
size_t len = 0; size_t len;
argv = NULL;
argc = 0;
buf = NULL;
len = 0;
*cause = NULL;
*cmdlist = NULL;
rval = -1;
p = 0;
for (;;) { for (;;) {
ch = cmd_string_getc(s, &p); ch = cmd_string_getc(s, &p);
switch (ch) { switch (ch) {
case '\'': case '\'':
if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL) if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL)
goto error; goto error;
cmd_string_copy(&buf, t, &len); buf = xrealloc(buf, 1, len + strlen(t) + 1);
strlcpy(buf + len, t, strlen(t) + 1);
len += strlen(t);
xfree(t);
break; break;
case '"': case '"':
if ((t = cmd_string_string(s, &p, '"', 1)) == NULL) if ((t = cmd_string_string(s, &p, '"', 1)) == NULL)
goto error; goto error;
cmd_string_copy(&buf, t, &len); buf = xrealloc(buf, 1, len + strlen(t) + 1);
strlcpy(buf + len, t, strlen(t) + 1);
len += strlen(t);
xfree(t);
break; break;
case '$': case '$':
if ((t = cmd_string_variable(s, &p)) == NULL) if ((t = cmd_string_variable(s, &p)) == NULL)
goto error; goto error;
cmd_string_copy(&buf, t, &len); buf = xrealloc(buf, 1, len + strlen(t) + 1);
strlcpy(buf + len, t, strlen(t) + 1);
len += strlen(t);
xfree(t);
break; break;
case '#': case '#':
/* Comment: discard rest of line. */ /* Comment: discard rest of line. */
@@ -90,11 +114,10 @@ cmd_string_split(const char *s, int *rargc, char ***rargv)
case ' ': case ' ':
case '\t': case '\t':
if (buf != NULL) { if (buf != NULL) {
buf = xrealloc(buf, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len] = '\0'; buf[len] = '\0';
argv = xreallocarray(argv, argc + 1, argv = xrealloc(argv, argc + 1, sizeof *argv);
sizeof *argv);
argv[argc++] = buf; argv[argc++] = buf;
buf = NULL; buf = NULL;
@@ -109,88 +132,57 @@ cmd_string_split(const char *s, int *rargc, char ***rargv)
whitespace = argv[0] + strcspn(argv[0], " \t"); whitespace = argv[0] + strcspn(argv[0], " \t");
if (equals == NULL || equals > whitespace) if (equals == NULL || equals > whitespace)
break; break;
environ_put(global_environ, argv[0]); environ_put(&global_environ, argv[0]);
argc--; argc--;
memmove(argv, argv + 1, argc * (sizeof *argv)); memmove(argv, argv + 1, argc * (sizeof *argv));
} }
goto done; if (argc == 0)
goto out;
*cmdlist = cmd_list_parse(argc, argv, cause);
if (*cmdlist == NULL)
goto out;
rval = 0;
goto out;
case '~': case '~':
if (buf != NULL) { if (buf == NULL) {
append = 1; if ((t = cmd_string_expand_tilde(s, &p)) == NULL)
goto error;
buf = xrealloc(buf, 1, len + strlen(t) + 1);
strlcpy(buf + len, t, strlen(t) + 1);
len += strlen(t);
xfree(t);
break; break;
} }
t = cmd_string_expand_tilde(s, &p); /* FALLTHROUGH */
if (t == NULL)
goto error;
cmd_string_copy(&buf, t, &len);
break;
default: default:
append = 1;
break;
}
if (append) {
if (len >= SIZE_MAX - 2) if (len >= SIZE_MAX - 2)
goto error; goto error;
buf = xrealloc(buf, len + 1);
buf = xrealloc(buf, 1, len + 1);
buf[len++] = ch; buf[len++] = ch;
} break;
append = 0;
}
done:
*rargc = argc;
*rargv = argv;
free(buf);
return (0);
error:
if (argv != NULL)
cmd_free_argv(argc, argv);
free(buf);
return (-1);
}
struct cmd_list *
cmd_string_parse(const char *s, const char *file, u_int line, char **cause)
{
struct cmd_list *cmdlist = NULL;
int argc;
char **argv;
*cause = NULL;
if (cmd_string_split(s, &argc, &argv) != 0)
goto error;
if (argc != 0) {
cmdlist = cmd_list_parse(argc, argv, file, line, cause);
if (cmdlist == NULL) {
cmd_free_argv(argc, argv);
goto error;
} }
} }
cmd_free_argv(argc, argv);
return (cmdlist);
error: error:
xasprintf(cause, "invalid or unknown command: %s", s); xasprintf(cause, "invalid or unknown command: %s", s);
return (NULL);
out:
if (buf != NULL)
xfree(buf);
if (argv != NULL) {
for (i = 0; i < argc; i++)
xfree(argv[i]);
xfree(argv);
}
return (rval);
} }
static void char *
cmd_string_copy(char **dst, char *src, size_t *len)
{
size_t srclen;
srclen = strlen(src);
*dst = xrealloc(*dst, *len + srclen + 1);
strlcpy(*dst + *len, src, srclen + 1);
*len += srclen;
free(src);
}
static char *
cmd_string_string(const char *s, size_t *p, char endch, int esc) cmd_string_string(const char *s, size_t *p, char endch, int esc)
{ {
int ch; int ch;
@@ -229,26 +221,30 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc)
break; break;
if ((t = cmd_string_variable(s, p)) == NULL) if ((t = cmd_string_variable(s, p)) == NULL)
goto error; goto error;
cmd_string_copy(&buf, t, &len); buf = xrealloc(buf, 1, len + strlen(t) + 1);
strlcpy(buf + len, t, strlen(t) + 1);
len += strlen(t);
xfree(t);
continue; continue;
} }
if (len >= SIZE_MAX - 2) if (len >= SIZE_MAX - 2)
goto error; goto error;
buf = xrealloc(buf, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len++] = ch; buf[len++] = ch;
} }
buf = xrealloc(buf, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len] = '\0'; buf[len] = '\0';
return (buf); return (buf);
error: error:
free(buf); if (buf != NULL)
xfree(buf);
return (NULL); return (NULL);
} }
static char * char *
cmd_string_variable(const char *s, size_t *p) cmd_string_variable(const char *s, size_t *p)
{ {
int ch, fch; int ch, fch;
@@ -282,7 +278,7 @@ cmd_string_variable(const char *s, size_t *p)
return (t); return (t);
} }
buf = xrealloc(buf, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len++] = ch; buf[len++] = ch;
for (;;) { for (;;) {
@@ -292,7 +288,7 @@ cmd_string_variable(const char *s, size_t *p)
else { else {
if (len >= SIZE_MAX - 3) if (len >= SIZE_MAX - 3)
goto error; goto error;
buf = xrealloc(buf, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len++] = ch; buf[len++] = ch;
} }
} }
@@ -303,63 +299,46 @@ cmd_string_variable(const char *s, size_t *p)
if (ch != EOF && fch != '{') if (ch != EOF && fch != '{')
cmd_string_ungetc(p); /* ch */ cmd_string_ungetc(p); /* ch */
buf = xrealloc(buf, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len] = '\0'; buf[len] = '\0';
envent = environ_find(global_environ, buf); envent = environ_find(&global_environ, buf);
free(buf); xfree(buf);
if (envent == NULL) if (envent == NULL)
return (xstrdup("")); return (xstrdup(""));
return (xstrdup(envent->value)); return (xstrdup(envent->value));
error: error:
free(buf); if (buf != NULL)
xfree(buf);
return (NULL); return (NULL);
} }
static char * char *
cmd_string_expand_tilde(const char *s, size_t *p) cmd_string_expand_tilde(const char *s, size_t *p)
{ {
struct passwd *pw; struct passwd *pw;
struct environ_entry *envent; struct environ_entry *envent;
char *home, *path, *user, *cp; char *home, *path, *username;
int last;
home = NULL; home = NULL;
if (cmd_string_getc(s, p) == '/') {
last = cmd_string_getc(s, p); envent = environ_find(&global_environ, "HOME");
if (last == EOF || last == '/' || last == ' '|| last == '\t') {
envent = environ_find(global_environ, "HOME");
if (envent != NULL && *envent->value != '\0') if (envent != NULL && *envent->value != '\0')
home = envent->value; home = envent->value;
else if ((pw = getpwuid(getuid())) != NULL) else if ((pw = getpwuid(getuid())) != NULL)
home = pw->pw_dir; home = pw->pw_dir;
} else { } else {
cmd_string_ungetc(p); cmd_string_ungetc(p);
if ((username = cmd_string_string(s, p, '/', 0)) == NULL)
cp = user = xmalloc(strlen(s)); return (NULL);
for (;;) { if ((pw = getpwnam(username)) != NULL)
last = cmd_string_getc(s, p);
if (last == EOF ||
last == '/' ||
last == ' '||
last == '\t')
break;
*cp++ = last;
}
*cp = '\0';
if ((pw = getpwnam(user)) != NULL)
home = pw->pw_dir; home = pw->pw_dir;
free(user); xfree(username);
} }
if (home == NULL) if (home == NULL)
return (NULL); return (NULL);
if (last != EOF) xasprintf(&path, "%s/", home);
xasprintf(&path, "%s%c", home, last);
else
xasprintf(&path, "%s", home);
return (path); return (path);
} }

56
cmd-suspend-client.c Normal file
View File

@@ -0,0 +1,56 @@
/* $Id$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Suspend client with SIGTSTP.
*/
int cmd_suspend_client_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_suspend_client_entry = {
"suspend-client", "suspendc",
"t:", 0, 0,
CMD_TARGET_CLIENT_USAGE,
0,
NULL,
NULL,
cmd_suspend_client_exec
};
int
cmd_suspend_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c;
if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
return (-1);
tty_stop_tty(&c->tty);
c->flags |= CLIENT_SUSPENDED;
server_write_client(c, MSG_SUSPEND, NULL, 0);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -26,51 +26,65 @@
* Swap two panes. * Swap two panes.
*/ */
static enum cmd_retval cmd_swap_pane_exec(struct cmd *, struct cmdq_item *); void cmd_swap_pane_key_binding(struct cmd *, int);
int cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_swap_pane_entry = { const struct cmd_entry cmd_swap_pane_entry = {
.name = "swap-pane", "swap-pane", "swapp",
.alias = "swapp", "dDs:t:U", 0, 0,
"[-dDU] " CMD_SRCDST_PANE_USAGE,
.args = { "dDs:t:U", 0, 0 }, 0,
.usage = "[-dDU] " CMD_SRCDST_PANE_USAGE, cmd_swap_pane_key_binding,
NULL,
.sflag = CMD_PANE_MARKED, cmd_swap_pane_exec
.tflag = CMD_PANE,
.flags = 0,
.exec = cmd_swap_pane_exec
}; };
static enum cmd_retval void
cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_swap_pane_key_binding(struct cmd *self, int key)
{ {
self->args = args_create(0);
if (key == '{')
args_set(self->args, 'U', NULL);
else if (key == '}')
args_set(self->args, 'D', NULL);
}
int
cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w; struct window *src_w, *dst_w;
struct window_pane *tmp_wp, *src_wp, *dst_wp; struct window_pane *tmp_wp, *src_wp, *dst_wp;
struct layout_cell *src_lc, *dst_lc; struct layout_cell *src_lc, *dst_lc;
u_int sx, sy, xoff, yoff; u_int sx, sy, xoff, yoff;
dst_w = item->state.tflag.wl->window; dst_wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &dst_wp);
dst_wp = item->state.tflag.wp; if (dst_wl == NULL)
src_w = item->state.sflag.wl->window; return (-1);
src_wp = item->state.sflag.wp; dst_w = dst_wl->window;
server_unzoom_window(dst_w);
if (args_has(self->args, 'D')) { if (!args_has(args, 's')) {
src_w = dst_w; src_w = dst_w;
src_wp = TAILQ_NEXT(dst_wp, entry); if (args_has(self->args, 'D')) {
if (src_wp == NULL) src_wp = TAILQ_NEXT(dst_wp, entry);
src_wp = TAILQ_FIRST(&dst_w->panes); if (src_wp == NULL)
} else if (args_has(self->args, 'U')) { src_wp = TAILQ_FIRST(&dst_w->panes);
src_w = dst_w; } else if (args_has(self->args, 'U')) {
src_wp = TAILQ_PREV(dst_wp, window_panes, entry); src_wp = TAILQ_PREV(dst_wp, window_panes, entry);
if (src_wp == NULL) if (src_wp == NULL)
src_wp = TAILQ_LAST(&dst_w->panes, window_panes); src_wp = TAILQ_LAST(&dst_w->panes, window_panes);
} else
return (0);
} else {
src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp);
if (src_wl == NULL)
return (-1);
src_w = src_wl->window;
} }
server_unzoom_window(src_w);
if (src_wp == dst_wp) if (src_wp == dst_wp)
return (CMD_RETURN_NORMAL); return (0);
tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry); tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry);
TAILQ_REMOVE(&dst_w->panes, dst_wp, entry); TAILQ_REMOVE(&dst_w->panes, dst_wp, entry);
@@ -124,5 +138,5 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
server_redraw_window(src_w); server_redraw_window(src_w);
server_redraw_window(dst_w); server_redraw_window(dst_w);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -26,56 +26,49 @@
* Swap one window with another. * Swap one window with another.
*/ */
static enum cmd_retval cmd_swap_window_exec(struct cmd *, struct cmdq_item *); int cmd_swap_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_swap_window_entry = { const struct cmd_entry cmd_swap_window_entry = {
.name = "swap-window", "swap-window", "swapw",
.alias = "swapw", "ds:t:", 0, 0,
"[-d] " CMD_SRCDST_WINDOW_USAGE,
.args = { "ds:t:", 0, 0 }, 0,
.usage = "[-d] " CMD_SRCDST_WINDOW_USAGE, NULL,
NULL,
.sflag = CMD_WINDOW_MARKED, cmd_swap_window_exec
.tflag = CMD_WINDOW,
.flags = 0,
.exec = cmd_swap_window_exec
}; };
static enum cmd_retval int
cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item) cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct args *args = self->args;
const char *target_src, *target_dst;
struct session *src, *dst; struct session *src, *dst;
struct session_group *sg_src, *sg_dst; struct session_group *sg_src, *sg_dst;
struct winlink *wl_src, *wl_dst; struct winlink *wl_src, *wl_dst;
struct window *w_src, *w_dst; struct window *w;
wl_src = item->state.sflag.wl; target_src = args_get(args, 's');
src = item->state.sflag.s; if ((wl_src = cmd_find_window(ctx, target_src, &src)) == NULL)
sg_src = session_group_contains(src); return (-1);
target_dst = args_get(args, 't');
if ((wl_dst = cmd_find_window(ctx, target_dst, &dst)) == NULL)
return (-1);
wl_dst = item->state.tflag.wl; sg_src = session_group_find(src);
dst = item->state.tflag.s; sg_dst = session_group_find(dst);
sg_dst = session_group_contains(dst); if (src != dst &&
sg_src != NULL && sg_dst != NULL && sg_src == sg_dst) {
if (src != dst && sg_src != NULL && sg_dst != NULL && ctx->error(ctx, "can't move window, sessions are grouped");
sg_src == sg_dst) { return (-1);
cmdq_error(item, "can't move window, sessions are grouped");
return (CMD_RETURN_ERROR);
} }
if (wl_dst->window == wl_src->window) if (wl_dst->window == wl_src->window)
return (CMD_RETURN_NORMAL); return (0);
w_dst = wl_dst->window; w = wl_dst->window;
TAILQ_REMOVE(&w_dst->winlinks, wl_dst, wentry); wl_dst->window = wl_src->window;
w_src = wl_src->window; wl_src->window = w;
TAILQ_REMOVE(&w_src->winlinks, wl_src, wentry);
wl_dst->window = w_src;
TAILQ_INSERT_TAIL(&w_src->winlinks, wl_dst, wentry);
wl_src->window = w_dst;
TAILQ_INSERT_TAIL(&w_dst->winlinks, wl_src, wentry);
if (!args_has(self->args, 'd')) { if (!args_has(self->args, 'd')) {
session_select(dst, wl_dst->idx); session_select(dst, wl_dst->idx);
@@ -90,5 +83,5 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
} }
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -27,98 +27,88 @@
* Switch client to a different session. * Switch client to a different session.
*/ */
static enum cmd_retval cmd_switch_client_exec(struct cmd *, void cmd_switch_client_key_binding(struct cmd *, int);
struct cmdq_item *); int cmd_switch_client_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_switch_client_entry = { const struct cmd_entry cmd_switch_client_entry = {
.name = "switch-client", "switch-client", "switchc",
.alias = "switchc", "lc:npt:r", 0, 0,
"[-lnpr] [-c target-client] [-t target-session]",
.args = { "lc:Enpt:rT:", 0, 0 }, CMD_READONLY,
.usage = "[-Elnpr] [-c target-client] [-t target-session] " cmd_switch_client_key_binding,
"[-T key-table]", NULL,
cmd_switch_client_exec
.cflag = CMD_CLIENT,
.tflag = CMD_SESSION_WITHPANE,
.flags = CMD_READONLY,
.exec = cmd_switch_client_exec
}; };
static enum cmd_retval void
cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item) cmd_switch_client_key_binding(struct cmd *self, int key)
{ {
struct args *args = self->args; self->args = args_create(0);
struct cmd_state *state = &item->state; switch (key) {
struct client *c = state->c; case '(':
struct session *s = item->state.tflag.s; args_set(self->args, 'p', NULL);
struct window_pane *wp; break;
const char *tablename; case ')':
struct key_table *table; args_set(self->args, 'n', NULL);
break;
case 'L':
args_set(self->args, 'l', NULL);
break;
}
}
if (args_has(args, 'r')) int
c->flags ^= CLIENT_READONLY; cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c;
struct session *s;
tablename = args_get(args, 'T'); if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL)
if (tablename != NULL) { return (-1);
table = key_bindings_get_table(tablename, 0);
if (table == NULL) { if (args_has(args, 'r')) {
cmdq_error(item, "table %s doesn't exist", tablename); if (c->flags & CLIENT_READONLY) {
return (CMD_RETURN_ERROR); c->flags &= ~CLIENT_READONLY;
ctx->info(ctx, "made client writable");
} else {
c->flags |= CLIENT_READONLY;
ctx->info(ctx, "made client read-only");
} }
table->references++;
key_bindings_unref_table(c->keytable);
c->keytable = table;
return (CMD_RETURN_NORMAL);
} }
s = NULL;
if (args_has(args, 'n')) { if (args_has(args, 'n')) {
if ((s = session_next_session(c->session)) == NULL) { if ((s = session_next_session(c->session)) == NULL) {
cmdq_error(item, "can't find next session"); ctx->error(ctx, "can't find next session");
return (CMD_RETURN_ERROR); return (-1);
} }
} else if (args_has(args, 'p')) { } else if (args_has(args, 'p')) {
if ((s = session_previous_session(c->session)) == NULL) { if ((s = session_previous_session(c->session)) == NULL) {
cmdq_error(item, "can't find previous session"); ctx->error(ctx, "can't find previous session");
return (CMD_RETURN_ERROR); return (-1);
} }
} else if (args_has(args, 'l')) { } else if (args_has(args, 'l')) {
if (c->last_session != NULL && session_alive(c->last_session)) if (c->last_session != NULL && session_alive(c->last_session))
s = c->last_session; s = c->last_session;
else
s = NULL;
if (s == NULL) { if (s == NULL) {
cmdq_error(item, "can't find last session"); ctx->error(ctx, "can't find last session");
return (CMD_RETURN_ERROR); return (-1);
} }
} else { } else
if (item->client == NULL) s = cmd_find_session(ctx, args_get(args, 't'), 0);
return (CMD_RETURN_NORMAL); if (s == NULL)
if (state->tflag.wl != NULL) { return (-1);
wp = state->tflag.wp;
if (wp != NULL)
window_set_active_pane(wp->window, wp);
session_set_current(s, state->tflag.wl);
}
}
if (!args_has(args, 'E')) if (c->session != NULL)
environ_update(s->options, c->environ, s->environ);
if (c->session != NULL && c->session != s)
c->last_session = c->session; c->last_session = c->session;
c->session = s; c->session = s;
if (!item->repeat) session_update_activity(s);
server_client_set_key_table(c, NULL);
status_timer_start(c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
recalculate_sizes(); recalculate_sizes();
server_check_unattached(); server_check_unattached();
server_redraw_client(c); server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS; s->curw->flags &= ~WINLINK_ALERTFLAGS;
alerts_check_session(s);
return (CMD_RETURN_NORMAL); return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,77 +18,86 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Unbind key from command. * Unbind key from command.
*/ */
static enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmdq_item *); int cmd_unbind_key_check(struct args *);
int cmd_unbind_key_exec(struct cmd *, struct cmd_ctx *);
int cmd_unbind_key_table(struct cmd *, struct cmd_ctx *, int);
const struct cmd_entry cmd_unbind_key_entry = { const struct cmd_entry cmd_unbind_key_entry = {
.name = "unbind-key", "unbind-key", "unbind",
.alias = "unbind", "acnt:", 0, 1,
"[-acn] [-t key-table] key",
.args = { "anT:", 0, 1 }, 0,
.usage = "[-an] [-T key-table] key", NULL,
cmd_unbind_key_check,
.flags = CMD_AFTERHOOK, cmd_unbind_key_exec
.exec = cmd_unbind_key_exec
}; };
static enum cmd_retval int
cmd_unbind_key_exec(struct cmd *self, struct cmdq_item *item) cmd_unbind_key_check(struct args *args)
{ {
struct args *args = self->args; if (args_has(args, 'a') && (args->argc != 0 || args_has(args, 't')))
key_code key; return (-1);
const char *tablename; if (!args_has(args, 'a') && args->argc != 1)
return (-1);
if (!args_has(args, 'a')) { return (0);
if (args->argc != 1) { }
cmdq_error(item, "missing key");
return (CMD_RETURN_ERROR); int
} cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
key = key_string_lookup_string(args->argv[0]); {
if (key == KEYC_NONE || key == KEYC_UNKNOWN) { struct args *args = self->args;
cmdq_error(item, "unknown key: %s", args->argv[0]); struct key_binding *bd;
return (CMD_RETURN_ERROR); int key;
}
} else { if (args_has(args, 'a')) {
if (args->argc != 0) { while (!RB_EMPTY(&key_bindings)) {
cmdq_error(item, "key given with -a"); bd = RB_ROOT(&key_bindings);
return (CMD_RETURN_ERROR); key_bindings_remove(bd->key);
} }
key = KEYC_UNKNOWN; return (0);
} }
if (key == KEYC_UNKNOWN) { key = key_string_lookup_string(args->argv[0]);
tablename = args_get(args, 'T'); if (key == KEYC_NONE) {
if (tablename == NULL) { ctx->error(ctx, "unknown key: %s", args->argv[0]);
key_bindings_remove_table("root"); return (-1);
key_bindings_remove_table("prefix"); }
return (CMD_RETURN_NORMAL);
} if (args_has(args, 't'))
if (key_bindings_get_table(tablename, 0) == NULL) { return (cmd_unbind_key_table(self, ctx, key));
cmdq_error(item, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR); if (!args_has(args, 'n'))
} key |= KEYC_PREFIX;
key_bindings_remove_table(tablename); key_bindings_remove(key);
return (CMD_RETURN_NORMAL); return (0);
} }
if (args_has(args, 'T')) { int
tablename = args_get(args, 'T'); cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
if (key_bindings_get_table(tablename, 0) == NULL) { {
cmdq_error(item, "table %s doesn't exist", tablename); struct args *args = self->args;
return (CMD_RETURN_ERROR); const char *tablename;
} const struct mode_key_table *mtab;
} else if (args_has(args, 'n')) struct mode_key_binding *mbind, mtmp;
tablename = "root";
else tablename = args_get(args, 't');
tablename = "prefix"; if ((mtab = mode_key_findtable(tablename)) == NULL) {
key_bindings_remove(tablename, key); ctx->error(ctx, "unknown key table: %s", tablename);
return (CMD_RETURN_NORMAL); return (-1);
}
mtmp.key = key;
mtmp.mode = !!args_has(args, 'c');
if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) {
RB_REMOVE(mode_key_tree, mtab->tree, mbind);
xfree(mbind);
}
return (0);
} }

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

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

View File

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

1397
cmd.c

File diff suppressed because it is too large Load Diff

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