1 Commits
1.5 ... 1.0

Author SHA1 Message Date
no_author
be20fc8699 This commit was manufactured by cvs2svn to create tag 'TMUX_1_0'. 2009-09-20 18:54:22 +00:00
208 changed files with 13082 additions and 19761 deletions

283
CHANGES
View File

@@ -1,284 +1,3 @@
CHANGES FROM 1.4 TO 1.5, 09 July 2011
* Support xterm mouse modes 1002 and 1003.
* Change from a per-session stack of buffers to one global stack. This renders
copy-buffer useless and makes buffer-limit now a server option.
* Fix most-recently-used choice by avoiding reset the activity timer for
unattached sessions every second.
* Add a -P option to new-window and split-window to print the new window or
pane index in target form (useful to pass it into other commands).
* Handle a # at the end of a replacement string (such as status-left)
correctly.
* Support for UTF-8 mouse input (\033[1005h) which was added in xterm 262.
If the new mouse-utf8 option is on, UTF-8 mouse input is enabled for all
UTF-8 terminals. The option defaults to on if LANG etc are set in the same
manner as the utf8 option.
* Support for HP-UX.
* Accept colours of the hex form #ffffff and translate to the nearest from the
xterm(1) 256-colour set.
* Clear the non-blocking IO flag (O_NONBLOCK) on the stdio file descriptors
before closing them (fixes things like "tmux ls && cat").
* Use TMPDIR if set.
* Fix next and previous session functions to actually work.
* Support -x and -y for new-session to specify the initial size of the window
if created detached with -d.
* Make bind-key accept characters with the top-bit-set and print them as octal.
* Set $TMUX without the session when background jobs are run.
* Simplify the way jobs work and drop the persist type, so all jobs are
fire-and-forget.
* Accept tcgetattr/tcsetattr(3) failure, fixes problems with fatal() if the
terminal disappears while locked.
* Add a -P option to detach to HUP the client's parent process (usually causing
it to exit as well).
* Support passing through escape sequences to the underlying terminal by using
DCS with a "tmux;" prefix.
* Prevent tiled producing a corrupt layout when only one column is needed.
* Give each pane created in a tmux server a unique id (starting from 0), put it
in the TMUX_PANE environment variable and accept it as a target.
* Allow a start and end line to be specified for capture-pane which may be
negative to capture part of the history.
* Add -a and -s options to lsp to list all panes in the server or session
respectively. Likewise add -s to lsw.
* Change -t on display-message to be target-pane for the #[A-Z] replacements
and add -c as target-client.
* The attach-session command now prefers the most recently used unattached
session.
* Add -s option to detach-client to detach all clients attached to a session.
* Add -t to list-clients.
* Change window with mouse wheel over status line if mouse-select-window is on.
* When mode-mouse is on, automatically enter copy mode when the mouse is
dragged or the mouse wheel is used. Also exit copy mode when the mouse wheel
is scrolled off the bottom.
* Provide #h character pair for short hostname (no domain).
* Don't use strnvis(3) for the title as it breaks UTF-8.
* Use the tsl and fsl terminfo(5) capabilities to update terminal title and
automatically fill them in on terminals with the XT capability (which means
their title setting is xterm-compatible).
* Add a new option, mouse-resize-pane. When on, panes may be resized by
dragging their borders.
* Fix crash by resetting last pane on {break,swap}-pane across windows.
* Add three new copy-mode commands - select-line, copy-line, copy-end-of-line.
* Support setting the xterm clipboard when copying from copy mode using the
xterm escape sequence for the purpose (if xterm is configured to allow it).
* Support xterm(1) cursor colour change sequences through terminfo(5) Cc
(set) and Cr (reset) extensions.
* Support DECSCUSR sequence to set the cursor style with two new terminfo(5)
extensions, Cs and Csr.
* Make the command-prompt custom prompts recognize the status-left option
character pairs.
* Add a respawn-pane command.
* Add a couple of extra xterm-style keys that gnome terminal provides.
* Allow the initial context on prompts to be set with the new -I option to
command-prompt. Include the current window and session name in the prompt
when renaming and add a new key binding ($) for rename session.
* Option bell-on-alert added to trigger the terminal bell when there is an
alert.
* Change the list-keys format so that it shows the keys using actual tmux
commands which should be able to be directly copied into the config file.
* Show full targets for lsp/lsw -a.
* Make confirm-before prompt customizable with -p option like command-prompt
and add the character pairs #W and #P to the default kill-{pane,window}
prompts.
* Avoid sending data to suspended/locked clients.
* Small memory leaks in error paths plugged.
* Vi mode improvements.
CHANGES FROM 1.3 TO 1.4, 27 December 2010
* Window bell reporting fixed.
* Show which pane is active in the list-panes output.
* Backoff reworked.
* Prevent the server from dying when switching into copy mode when already
in a different mode.
* Reset running jobs when the status line is enabled or disabled.
* Simplify xterm modifier detection.
* Avoid crashing in copy mode if the screen size is too small for the
indicator.
* Flags -n and -p added to switch-client.
* Use UTF-8 line drawing characters on UTF-8 terminals, thus fixing some
terminals (eg putty) which disable the vt100 ACS mode switching sequences
in UTF-8 mode. On terminals without ACS, use ASCII equivalents.
* New server option exit-unattached added.
* New session option destroy-unattached added.
* Fall back on normal session choice method if $TMUX exists but is invalid
rather than rejecting.
* Mark repeating keys with "(repeat)" in the key list.
* When removing a pane, don't change the active pane unless the active pane
is actually the one being removed.
* New command last-pane added.
* AIX fixes.
* Flag -a added to unbind-key.
* Add XAUTHORITY to update-environment.
* More info regarding window and pane flags is now shown in list-*.
* If VISUAL or EDITOR contains "vi" configure mode-keys and status-key to vi.
* New window option monitor-silence and session option visual-silence added.
* In the built-in layouts distribute the panes more evenly.
* Set the default value of main-pane-width to 80 instead of 81.
* Command-line flag -V added.
* Instead of keeping a per-client prompt history make it global.
* Fix rectangle copy to behave like emacs (the cursor is not part of the
selection on the right edge but on the left it is).
* Flag -l added to switch-client.
* Retrieve environment variables from the global environment rather than
getenv(3), thus allowing them to be updated during the configuration file.
* New window options other-pane-{height,width} added.
* More minor bugs fixed and manpage improvements.
CHANGES FROM 1.2 TO 1.3, 18 July 2010
* New input parser.
* Flags to move through panes -UDLR added to select-pane.
* Commands up-pane, and down-pane removed, since equivalent behaviour is now
available through the target flag (-t:+ and -t:-).
* Jump-forward/backward in copy move (based on vi's F, and f commands).
* Make paste-buffer accept a pane as a target.
* Flag -a added to new-window to insert a window after an existing one, moving
windows up if necessary.
* Merge more mode into copy mode.
* Run job commands explicitly in the global environment (which can be modified
with setenv -g), rather than with the environment tmux started with.
* Use the machine's hostname as the default title, instead of an empty string.
* Prevent double free if the window option remain-on-exit is set.
* Key string conversions rewritten.
* Mark zombie windows as dead in the choose-window list.
* Tiled layout added.
* Signal handling reworked.
* Reset SIGCHLD after fork to fix problems with some shells.
* Select-prompt command removed. Therefore, bound ' to command-prompt -p index
"select-window -t:%%" by default.
* Catch SIGHUP and terminate if running as a client, thus avoiding clients from
being left hanging around when, for instance, a SSH session is disconnected.
* Solaris 9 fixes (such as adding compat {get,set}env(3) code).
* Accept none instead of default for attributes.
* Window options window-status-alert-{alert,bg,fg} added.
* Flag -s added to the paste-buffer command to specify a custom separator.
* Allow dragging to make a selection in copy mode if the mode-mouse option is
set.
* Support the mouse scroll wheel.
* Make pipe-pane accept special character sequences (eg #I).
* Fix problems with window sizing when starting tmux from .xinitrc.
* Give tmux sockets (but not the containing folder) group permissions.
* Extend the target flags (ie -t) to accept an offset (for example -t:+2), and
make it wrap windows, and panes.
* New command choose-buffer added.
* New server option detach-on-destroy to set what happens to a client when the
session it is attached to is destroyed. If on (default), the client is
detached. Otherwise, the client is switched to the most recently active of
the remaining sessions.
* The commands load-buffer, and save-buffer now accept a dash (-) as the file
to read from stdin, or write to stdout.
* Custom layouts added.
* Additional code reduction, bug fixes, and manpage enhancements.
CHANGES FROM 1.1 TO 1.2, 10 March 2010
* Switch to libevent.
* Emulate the ri (reverse index) capability, ergo allowing tmux to at least
start on Sun consoles (TERM=sun, or sun-color).
* Assign each entry a number, or lowercase letter in choose mode, and accept
that as a shortcut key.
* Permit top-bit-set characters to be entered in the status line.
* Mark no-prefix keys with (no prefix), rather than [] in list-keys.
* New command show-messages (alias showmsgs), and new session option
message-limit, to show a per-client log of status lines messages up to the
number defined by message-limit.
* Do not interpret #() for display-message to avoid leaking commands.
* New window options window-status-format, and window-status-current-format to
control the format of each window in the status line.
* Add a -p flag to display-message to print the output, instead of displaying
it in the status line.
* Emulate il1, dl1, ich1 to run with vt100 feature set.
* New command capture-pane (alias capturep) to copy the entire pane contents
to a paste buffer.
* Avoid duplicating code by adding a -w flag to set-option, and show-options to
set, and show window options. The commands set-window-option, and
show-window-options are now aliases.
* Panes can now be referred to as top, bottom, top-left, etc.
* Add server-wide options, which can be set with set-option -s, and shown with
show-options -s.
* New server option quiet (like -q from the command line).
* New server option escape-time to set the timeout used to detect if escapes
are alone, part of a function key, or meta sequence.
* New session options pane-active-border-bg, pane-active-border-fg,
pane-border-bg, and pane-border-fg to set pane colours.
* Make split-window accept a pane target, instead of a window.
* New command join-pane (alias joinp) to split, and move an existing pane into
the space (the opposite of break-pane), thus simplifying calls to
split-window, followed by move-window.
* Permit S- prefix on keys for shift when the terminal/terminfo supports them.
* Window targets (-t flag) can now refer to the last window (!), next (+), and
previous (-) window by number.
* Mode keys to jump to the bottom/top of history, end of the next word, scroll
up/down, and reverse search in copy mode.
* New session option display-panes-active-colour to display the active pane in
a different colour with the display-panes command.
* Read the socket path from $TMUX if it's present, and -L, and -S are not
given.
* Vi-style mode keys B, W, and E to navigate between words in copy mode.
* Start in more mode when configuration file errors are detected.
* Rectangle copy support added.
* If attach-session was specified with the -r flag, make the client read-only.
* Per-window alternate-screen option.
* Make load-buffer work with FIFOs.
* New window option word-separators to set the characters considered as word
separators in copy mode.
* Permit keys in copy mode to be prefixed by a repeat count, entered with [1-9]
in vi mode, or M-[1-9] in emacs mode.
* utf8 improvements.
* As usual, additional code reduction, bug fixes, and manpage enhancements.
CHANGES FROM 1.0 TO 1.1, 05 November 2009
* New run-shell (alias run) command to run an external command without a
window, capture it's stdout, and send it to output mode.
* Ability to define multiple prefix keys.
* Internal locking mechanism removed. Instead, detach each client and run the
external command specified in the new session option lock-command (by default
lock -np), thus allowing the system password to be used.
* set-password command, and -U command line flag removed per the above change.
* Add support for -c command line flag to execute a shell command.
* New lock-client (alias lockc), and lock-session (alias locks) commands to
lock a particular client, or all clients attached to a session.
* Support C-n/C-p/C-v/M-v with emacs keys in choice mode.
* Use : for goto line rather than g in vi mode.
* Try to guess which client to use when no target client was specified. Finds
the current session, and if only one client is present, use it. Otherwise,
return the most recently used client.
* Make C-Down/C-Up in copy mode scroll the screen down/up one line without
moving the cursor.
* Scroll mode superseded by copy mode.
* New synchronize-panes window option to send all input to all other panes in
the same window.
* New lock-server session option to lock, when off (on by default), each
session when it has been idle for the lock-after-time setting. When on, the
entire server locks when all sessions have been idle for their individual
lock-after-time setting.
* Add support for grouped sessions which have independent name, options,
current window, but where the linked windows are synchronized (ie creating,
killing windows are mirrored between the sessions). A grouped session may be
created by passing -t to new-session.
* New mouse-select-pane session option to select the current pane with the
mouse.
* Queue, and run commands in the background for if-shell, status-left,
status-right, and #() by starting each once every status-interval. Adds the
capability to call some programs which would previously cause the server to
hang (eg sleep/tmux). It also avoids running commands excessively (ie if used
multiple times, it will be run only once).
* When a window is zombified and automatic-rename is on, append [dead] to the
name.
* Split list-panes (alias lsp) off from list-windows.
* New pipe-pane (alias pipep) to redirect a pane output to an external command.
* Support for automatic-renames for Solaris.
* Permit attributes to be turned off in #[] by prefixing with no (eg nobright).
* Add H/M/L in vi mode, and M-R/M-r in emacs to move the cursor to the top,
middle, and bottom of the screen.
* -a option added to kill-pane to kill all except current pane.
* The -d command line flag is now gone (can be replaced by terminal-overrides).
Just use op/AX to detect default colours.
* input/tty/utf8 improvements.
* xterm-keys rewrite.
* Additional code reduction, and bug fixes.
CHANGES FROM 0.9 TO 1.0, 20 Sept 2009
* Option to alter the format of the window title set by tmux.
@@ -1639,7 +1358,7 @@ The list of older changes is below.
(including mutt, emacs). No status bar yet and no key remapping or other
customisation.
$Id$
$Id: CHANGES,v 1.300 2009-09-20 18:54:21 nicm Exp $
LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr
LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms

267
FAQ
View File

@@ -1,115 +1,33 @@
tmux frequently asked questions
******************************************************************************
* PLEASE NOTE: most display problems are due to incorrect TERM! Before *
* reporting problems make SURE that TERM settings are correct inside and *
* outside tmux. *
* *
* Inside tmux TERM must be "screen" or similar (such as "screen-256color"). *
* Don't bother reporting problems where it isn't! *
* *
* Outside, it must match your terminal: particularly, use "rxvt" for rxvt *
* and derivatives. *
******************************************************************************
* How is tmux different from GNU screen? What else does it offer?
* How is tmux different from GNU screen?
tmux offers several advantages over screen:
tmux and GNU screen have many similarities. Some of the main differences I am
aware of are (bearing in mind I haven't used screen for a few years now):
- a clearly-defined client-server model: windows are independent entities which
may be attached simultaneously to multiple sessions and viewed from multiple
clients (terminals), as well as moved freely between sessions within the same
tmux server;
- a consistent, well-documented command interface, with the same syntax
whether used interactively, as a key binding, or from the shell;
- easily scriptable from the shell;
- multiple paste buffers;
- choice of vi or emacs key layouts;
- an option to limit the window size;
- a more usable status line syntax, with the ability to display the first line
of output of a specific command;
- a cleaner, modern, easily extended, BSD-licensed codebase.
- tmux uses a client-server model. Each server has single Unix domain socket in
/tmp and within one server there are multiple sessions which may be attached
to multiple clients (terminals).
There are still a few features screen includes that tmux omits:
This has advantages, notably: windows may be linked simultaneously to
multiple sessions; windows may be moved freely between sessions; and a client
may be switched between sessions easily (C-b D). There is one major
disadvantage: if the server crashes, game over, all sessions die. In
practice, however, tmux is quite stable and gets more so as people report any
bugs they hit :-).
This model is different from screen, where typically each new screen instance
is independent. tmux supports the same behaviour by using multiple servers
with the -L option but it is not typically recommended.
- Different command interfaces. One of the goals of tmux is that the shell
should be easily usable as a scripting language - almost all tmux commands
can be used from the shell and behave identically whether used from the
shell, from a key binding or from the command prompt. Personally I also find
tmux's command interface much more consistent and clearer, but this is
subjective.
- tmux calls window names (what you see in the status line) "names", screen
calls them "titles".
- tmux has a multiple paste buffers. Not a major one but comes in handy quite a
lot.
- tmux supports automatically renaming windows to the running application
without gross hacks using escape sequences. Its even on by default.
- tmux has a choice of vi or emacs key layouts. Again, not major, but I use
emacs so if tmux did support only one key set it would be emacs and then all
the vi users would get humpy. Key bindings may be completely reconfigured in
any case.
- tmux has an option to limit the window size.
- tmux has search in windows (C-b f).
- The window split (pane) model is different. tmux has two objects, windows and
panes; screen has just windows. This difference has several implications:
* In screen you can have a window appear in several layouts, in tmux a pane
can only be in one window (fixing this is a big todo item but quite
invasive).
* tmux layouts are immutable and do not get changed unless you modify them.
* In tmux, all panes are closed when you kill a window.
* tmux panes do not have individual names, titles and so on.
I think tmux's model is much easier to manage and navigate within a window,
but breaking panes off from and joining them to windows is more clumsy.
tmux also has support for preset pane layouts.
- tmux's status line syntax is more readable and easier to use. I think it'd be
hard for anyone to argue with this. tmux doesn't support running a command
constantly and always using the last line of its output, commands must be run
again each time.
- tmux has modern, easily extended code. Again hard to argue screen is better
if you have looked at the code.
- tmux depends on libevent. I don't see this as a disadvantage: libevent is
small and portable, and on modern systems with current package management
systems dependencies are not an issue. libevent brings advantages in code
simplicity and performance.
- screen allows the window to be bigger than the terminal and can pan around
it. tmux limits the size to the largest attached client. This is a big todo
item for tmux but it is not trivial.
- screen has builtin serial and telnet support; this is bloat and is unlikely
to be added to tmux.
- 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.
- tmux tends to be more demanding on the terminal so tends to show up terminal
and application bugs which screen does not.
- screen has wider platform support, for example IRIX, and for odd terminals.
- builtin serial and telnet support; this is bloat and is unlikely to be added
to tmux;
- wider platform support, for example IRIX and HP-UX, and for odd terminals.
* I found a bug! What do I do?
Please send bug reports by email to nicm@users.sourceforge.net or
tmux-users@lists.sourceforge.net. Please include as much of the following
information as possible:
Please send bug reports by email to nicm@users.sourceforge.net. Please
include as much of the following information as possible:
- the version of tmux you are running;
- the operating system you are using and its version;
@@ -164,17 +82,19 @@ default) to the new key. For example:
* How do I use UTF-8?
When running tmux in a UTF-8 capable terminal, UTF-8 must be turned on in tmux;
as of release 0.9, tmux attempts to autodetect a UTF-8-capable terminal by
When running tmux in a UTF-8 capable terminal, two things must be done to
enable support. UTF-8 must be turned on in tmux; this may be done separately
for each tmux window or globally by setting the "utf8" flag:
setw -g utf8 on
As of release 0.9, tmux attempts to autodetect a UTF-8-capable terminal by
checking the LC_ALL, LC_CTYPE and LANG environment variables. list-clients may
be used to check if this is detected correctly; if not, the -u command-line
flag may be specified when creating or attaching a client to a tmux session:
$ tmux -u new
Since the 1.0 release, tmux will turn on UTF-8 related options automatically
(ie status-utf8, and utf8) if the above conditions are met.
* How do I use a 256 colour terminal?
Provided the underlying terminal supports 256 colours, it is usually sufficient
@@ -236,8 +156,6 @@ the ctrl (bit 5 set, for example ^[[5~ to ^[[5^) modifier in non-xterm(1) mode;
it may be possible to configure vim to accept these, an example of how to do so
would be welcome.
vim users may also want to set the "ttyfast" option inside tmux.
* 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
@@ -283,131 +201,4 @@ on the Window -> Translation configuration page. For example, change UTF-8 to
ISO-8859-1 or CP437. It may also be necessary to adjust the way PuTTY treats
line drawing characters in the lower part of the same configuration page.
* What is the best way to display the load average? Why no #L?
It isn't possible to get the load average portably in code and it is preferable
not to add portability goop. The following works on at least Linux, *BSD and OS
X:
uptime|awk '{split(substr($0, index($0, "load")), a, ":"); print a[2]}'
* How do I attach the same session to multiple clients but with a different
current window, like screen -x?
One or more of the windows can be linked into multiple sessions manually with
link-window, or a grouped session with all the windows can be created with
new-session -t.
* Ctrl and arrow keys doesn't work in putty! What do I do?
putty inverts the sense of the cursor key mode on ctrl, which is a bit hard for
tmux to detect properly. To get ctrl keys right, change the terminfo settings
so kUP5 (Ctrl-Up etc) are the adjusted versions, and disable smkx/rmkx so tmux
doesn't change the mode. For example with this line in .tmux.conf (assuming you
have TERM set to xterm):
set -g terminal-overrides "xterm*:kLFT5=\eOD:kRIT5=\eOC:kUP5=\eOA:kDN5=\eOB:smkx@:rmkx@"
Note that this will only work in tmux 1.2 and above.
* How can I blank the tmux window?
GNU screen has a feature whereby it will blank the screen after a period of
inactivity. To do the same thing in tmux, use the lock-command setting, for
example (with GNU bash):
set -g lock-command 'tput civis && read -s -n1'
This will remove the cursor and tell the shell to quit once a key has been
pressed. For zsh, use "read -s -k1".
In addition, it's possible to have both blanking and locking (for instance via
lock(1) or vlock(1)) by using the following:
bind x set lock-command '/usr/bin/vlock' \; lock-client \; set lock-command 'tput civis && read -s -n1'
* How can I open a new window in the same directory as the current window?
One option is to just run "TMUX= tmux" in the window. However, this only works if no
command is running, so that you can input the command.
A workaround is to let tmux know about the current path through an environment
variable. To do so, use the following command:
[ -n "$TMUX" ] && tmux setenv TMUXPWD_$(tmux display -p "#I") $PWD
Which sets TMUXPWD_i (where i is the number of the current window) to the path
of the current directory. This command can be added to PS1, for example:
PS1='$([ -n "$TMUX" ] && tmux setenv TMUXPWD_$(tmux display -p "#I") $PWD)\h$ '
When a new window is created, the shell should be asked to change
directory. You can define a new binding (for example, if using GNU bash):
bind-key C-c run-shell 'tmux neww "cd $(tmux display -p "\$TMUXPWD_#I"); exec bash"'
This solution will work even if a command is currently running in the terminal,
but it will not work from a window that has just been swapped with another
because TMUXPWD_i will not be updated after a swap. However, once a new prompt
is displayed, TMUXPWD_i is updated properly.
* tmux doesn't start with "daemon failed"
tmux shows something similar to this when started:
fatal: server_start: daemon failed: No such file or directory
fatal: main_dispatch: imsg_read failed
A possible reason is that /dev/null is not a character device or is otherwise
inaccessible.
Check with:
file /dev/null
ls -l /dev/null
If it is not a character device or has incorrect permissions, it can typically
be recreated with:
cd /dev && rm null && ./MAKEDEV null
* vim displays reverse video instead of italics, while less displays italics
(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:
set -g default-terminal "screen-it"
If your terminal supports 256 colors, use:
$ 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
$Id$
$Id: FAQ,v 1.29 2009-08-08 20:46:26 nicm Exp $

65
GNUmakefile Normal file
View File

@@ -0,0 +1,65 @@
# $Id: GNUmakefile,v 1.114 2009-09-20 18:54:21 nicm Exp $
.PHONY: clean
VERSION= 1.0
#FDEBUG= 1
CC?= gcc
CFLAGS+= -DBUILD="\"$(VERSION)\""
LDFLAGS+= -L/usr/local/lib
LIBS+=
ifdef FDEBUG
CFLAGS+= -g -ggdb -DDEBUG
CFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
CFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
CFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
CFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align
endif
# This sort of sucks but gets rid of the stupid warning and should work on
# most platforms...
ifeq ($(shell (LC_ALL=C $(CC) -v 2>&1|awk '/gcc version 4|clang/') || true), )
CPPFLAGS:= -I. -I- $(CPPFLAGS)
else
CPPFLAGS:= -iquote. $(CPPFLAGS)
ifdef FDEBUG
CFLAGS+= -Wno-pointer-sign
endif
endif
PREFIX?= /usr/local
INSTALLDIR= install -d
INSTALLBIN= install -g bin -o root -m 555
INSTALLMAN= install -g bin -o root -m 444
SRCS= $(shell echo *.c|sed 's|osdep-[a-z0-9]*.c||g')
include config.mk
OBJS= $(patsubst %.c,%.o,$(SRCS))
all: tmux
tmux: $(OBJS)
$(CC) $(LDFLAGS) -o tmux $+ $(LIBS)
depend: $(SRCS)
$(CC) $(CPPFLAGS) $(CFLAGS) -MM $(SRCS) > .depend
clean:
rm -f tmux *.o *~ *.core *.log compat/*.o
clean-depend:
rm -f .depend
clean-all: clean clean-depend
rm -f config.h config.mk
install: all
$(INSTALLDIR) $(DESTDIR)$(PREFIX)/bin
$(INSTALLBIN) tmux $(DESTDIR)$(PREFIX)/bin/tmux
$(INSTALLDIR) $(DESTDIR)$(PREFIX)/man/man1
$(INSTALLMAN) tmux.1 $(DESTDIR)$(PREFIX)/man/man1/tmux.1
-include .depend

68
Makefile Normal file
View File

@@ -0,0 +1,68 @@
# $Id: Makefile,v 1.149 2009-09-20 18:54:21 nicm Exp $
.SUFFIXES: .c .o
.PHONY: clean
VERSION= 1.0
#FDEBUG= 1
CC?= cc
CFLAGS+= -DBUILD="\"$(VERSION)\""
LDFLAGS+= -L/usr/local/lib
LIBS+=
.ifdef FDEBUG
CFLAGS+= -g -ggdb -DDEBUG
CFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
CFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
CFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
CFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align
.endif
# This sort of sucks but gets rid of the stupid warning and should work on
# most platforms...
CCV!= (LC_ALL=C ${CC} -v 2>&1|awk '/gcc version 4|clang/') || true
.if empty(CCV)
CPPFLAGS:= -I. -I- -I/usr/local/include ${CPPFLAGS}
.else
CPPFLAGS:= -iquote. -I/usr/local/include ${CPPFLAGS}
.ifdef FDEBUG
CFLAGS+= -Wno-pointer-sign
.endif
.endif
PREFIX?= /usr/local
INSTALLDIR= install -d
INSTALLBIN= install -g bin -o root -m 555
INSTALLMAN= install -g bin -o root -m 444
SRCS!= echo *.c|sed 's|osdep-[a-z0-9]*.c||g'
.include "config.mk"
OBJS= ${SRCS:S/.c/.o/}
.c.o:
${CC} ${CPPFLAGS} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
all: tmux
tmux: ${OBJS}
${CC} ${LDFLAGS} -o tmux ${OBJS} ${LIBS}
depend:
mkdep ${CPPFLAGS} ${CFLAGS} ${SRCS:M*.c}
clean:
rm -f tmux *.o *~ *.core *.log compat/*.o
clean-depend:
rm -f .depend
clean-all: clean clean-depend
rm -f config.h config.mk
install: all
${INSTALLDIR} ${DESTDIR}${PREFIX}/bin
${INSTALLBIN} tmux ${DESTDIR}${PREFIX}/bin/
${INSTALLDIR} ${DESTDIR}${PREFIX}/man/man1
${INSTALLMAN} tmux.1 ${DESTDIR}${PREFIX}/man/man1/

View File

@@ -1,243 +0,0 @@
# $Id$
# Obvious program stuff.
bin_PROGRAMS = tmux
dist_man1_MANS = tmux.1
# Distribution tarball options.
EXTRA_DIST = \
CHANGES FAQ NOTES TODO examples compat \
array.h compat.h tmux.h osdep-*.c
dist-hook:
grep "^#found_debug=" configure
find $(distdir) -name .svn -type d|xargs rm -Rf
# Preprocessor flags.
CPPFLAGS += @XOPEN_DEFINES@
# glibc as usual does things ass-backwards and hides useful things by default,
# so everyone has to add this.
if IS_GLIBC
CFLAGS += -D_GNU_SOURCE
endif
# Set flags for gcc. gcc4 whines abouts silly stuff so it needs slightly
# different flags.
if IS_GCC
CFLAGS += -std=c99
if IS_DEBUG
CFLAGS += -g -ggdb -O0
CFLAGS += -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
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
# Set flags for static.
if IS_STATIC
LDFLAGS += -static
endif
# Set flags for Solaris.
if IS_SUNOS
CPPFLAGS += -D_XPG4_2 -D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS
endif
# Set flags for Sun CC.
if IS_SUNCC
CFLAGS += -erroff=E_EMPTY_DECLARATION
endif
# List of sources.
dist_tmux_SOURCES = \
arguments.c \
attributes.c \
cfg.c \
client.c \
clock.c \
cmd-attach-session.c \
cmd-bind-key.c \
cmd-break-pane.c \
cmd-capture-pane.c \
cmd-choose-buffer.c \
cmd-choose-client.c \
cmd-choose-session.c \
cmd-choose-window.c \
cmd-clear-history.c \
cmd-clock-mode.c \
cmd-command-prompt.c \
cmd-confirm-before.c \
cmd-copy-mode.c \
cmd-delete-buffer.c \
cmd-detach-client.c \
cmd-display-message.c \
cmd-display-panes.c \
cmd-find-window.c \
cmd-has-session.c \
cmd-if-shell.c \
cmd-join-pane.c \
cmd-kill-pane.c \
cmd-kill-server.c \
cmd-kill-session.c \
cmd-kill-window.c \
cmd-link-window.c \
cmd-list-buffers.c \
cmd-list-clients.c \
cmd-list-commands.c \
cmd-list-keys.c \
cmd-list-panes.c \
cmd-list-sessions.c \
cmd-list-windows.c \
cmd-list.c \
cmd-load-buffer.c \
cmd-lock-server.c \
cmd-move-window.c \
cmd-new-session.c \
cmd-new-window.c \
cmd-paste-buffer.c \
cmd-pipe-pane.c \
cmd-refresh-client.c \
cmd-rename-session.c \
cmd-rename-window.c \
cmd-resize-pane.c \
cmd-respawn-pane.c \
cmd-respawn-window.c \
cmd-rotate-window.c \
cmd-run-shell.c \
cmd-save-buffer.c \
cmd-select-layout.c \
cmd-select-pane.c \
cmd-select-window.c \
cmd-send-keys.c \
cmd-send-prefix.c \
cmd-server-info.c \
cmd-set-buffer.c \
cmd-set-environment.c \
cmd-set-option.c \
cmd-show-buffer.c \
cmd-show-environment.c \
cmd-show-messages.c \
cmd-show-options.c \
cmd-source-file.c \
cmd-split-window.c \
cmd-start-server.c \
cmd-string.c \
cmd-suspend-client.c \
cmd-swap-pane.c \
cmd-swap-window.c \
cmd-switch-client.c \
cmd-unbind-key.c \
cmd-unlink-window.c \
cmd.c \
colour.c \
environ.c \
grid-utf8.c \
grid-view.c \
grid.c \
input-keys.c \
input.c \
job.c \
key-bindings.c \
key-string.c \
layout-custom.c \
layout-set.c \
layout.c \
log.c \
mode-key.c \
names.c \
options-table.c \
options.c \
paste.c \
resize.c \
screen-redraw.c \
screen-write.c \
screen.c \
server-client.c \
server-fn.c \
server-window.c \
server.c \
session.c \
signal.c \
status.c \
tmux.c \
tty-acs.c \
tty-keys.c \
tty-term.c \
tty.c \
utf8.c \
window-choose.c \
window-clock.c \
window-copy.c \
window.c \
xmalloc.c \
xterm-keys.c
nodist_tmux_SOURCES = osdep-@PLATFORM@.c
# Pile in all the compat/ stuff that is needed.
if NO_FORKPTY
nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c
endif
if NO_IMSG
nodist_tmux_SOURCES += compat/imsg.c compat/imsg-buffer.c
endif
if NO_CLOSEFROM
nodist_tmux_SOURCES += compat/closefrom.c
endif
if NO_DAEMON
nodist_tmux_SOURCES += compat/daemon.c
endif
if NO_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
# Update SF web site.
upload-index.html: update-index.html
scp www/index.html www/main.css www/images/*.png \
${USER},tmux@web.sf.net:/home/groups/t/tm/tmux/htdocs
rm -f www/index.html www/images/small-*
update-index.html:
(cd www/images && \
rm -f small-* && \
for i in *.png; do \
convert "$$i" -resize 200x150 "small-$$i"; \
done \
)
sed "s/%%VERSION%%/${VERSION}/g" www/index.html.in >www/index.html

47
NOTES
View File

@@ -4,14 +4,15 @@ 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
This 0.9 release runs on OpenBSD, FreeBSD, NetBSD, Linux and OS X and may still
run on Solaris and AIX (although they hasn't been tested in a while). It is
usable, although there remain a number of missing features and some remaining
bugs are expected.
Since the 1.2 release that tmux depends on libevent. Download it from:
http://www.monkey.org/~provos/libevent/
If upgrading from 0.5, PLEASE NOTE the following configuration file changes: it
is now required to pass the -g flag to set-option or set-window-option to set
global options; remain-by-default and utf8-default are now gone, use global
window options (set-window-option -g) instead.
tmux consists of a server part and multiple clients. The server is created when
required and runs continuously unless killed by the user. Clients access the
@@ -24,10 +25,36 @@ windows into several simultaneously displayed panes; and to bind and unbind
command keys (invoked preceded by a prefix key, by default ctrl-b). Please see
the tmux(1) man page for further information.
The following is a summary of major features implemented in this version:
- Basic multiplexing, window switching, attaching and detaching.
- Window listing and renaming.
- Key binding.
- Handling of client terminal resize.
- Terminal emulation sufficient to handle most curses applications.
- A optional status line (enabled by default).
- Window history and copy and paste.
- Support for VT100 line drawing characters.
- A large command set.
- Vertical window splitting and layout.
- Automatic server locking on inactivity.
- A configuration file.
- UTF-8 support.
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.
are missing it may refuse to run, or not behave correctly. Known working are
TERM=screen (tmux in screen), xterm, xterm-color and rxvt. Note that TERM=xterm
does not support colour on OpenBSD. screen ignores this, tmux does not: use
xterm-color or rxvt for colour.
tmux supports UTF-8. To use it, the utf8 option must be set on each window;
this may be turned on for all windows by setting it as a global option, see
tmux(1) and the FAQ file. As of 0.9, tmux attempts to autodetect a
UTF-8-capable terminal by checking the LC_ALL, LC_CTYPE and LANG environment
variables. list-clients may be used to check if this is detected correctly; if
not, the -u command-line flag may be specified.
A Vim syntax file is available in the examples directory. To install it:
@@ -54,12 +81,6 @@ 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$
$Id: NOTES,v 1.49 2009-07-06 18:53:24 nicm Exp $

168
TODO
View File

@@ -1,140 +1,106 @@
- window creation/idle time
- better errors when creating new windows/sessions (how?)
- implicitly add exec to the commands for new windows (switch to disable it)?
- bring back detach-session to detach all clients on a session?
- it would be nice to have multichar commands eg C-b K K
- commands:
extend list-clients to list clients attached to a session (-a for all?)
bring back detach-session to detach all clients on a session?
- allow fnmatch for -c, so that you can, eg, detach all clients
- garbage collect window history (100 lines at a time?) if it hasn't been used
in $x time
in $x time (need window creation/use times)
- lift SHRT_MAX limits for history?
- better mode features: search
- flags to centre screen in window
- better terminal emulation
- activity/bell should be per-window not per-link? what if it is cur win in
session not being watched?
- next prev word etc in command prompt
- next prev word etc in command prompt; also ^K
- many more info() displays for various things
- backspace should perhaps wrap backwards over newlines which were not moved
down by a newline: screen and the OS X terminal does this but xterm and most
others do not. this might be hard: a flag for each grid line (top bit of size
maybe)? a single flag is insufficient as can't then tell when to /stop/
unwrapping
- input.c is too complicated. simplify?
- use a better termcap internally instead of screen, perhaps xterm
- kill all but current pane
- fix rxvt cursor fg issue (text under cursor can have non-white fg)
- client sx/sy should be in tty, then can let the terminal wrap at edge
to allow xterm to pick up it should be one line for its c/p
- should be able to move to a hidden pane and it would be moved into view. pane
number in status line/top-right would be cool for this
- support other mouse modes (highlight etc) and use it in copy mode
- set-remain-on-exit is a bit of a hack, some way to do it generically?
- set-option should be set-session-option and should be overall global options
for stuff like mode keys?
also quiet, utf8 and maybe other flags?
-g is a bit unexpected in conf file
- clear window title on exit
- the output code (tty.c) could do with optimisation depending on term
capibilities
- would be nice to be able to use "--" to mark start of command w/ neww etc
to avoid quoting
- goto line and search history in copy/scroll modes
- clone session command
- make command sequences more usable: don't require space after ;, handle
errors better
- key to switch to copy mode from scroll mode
- attach should have a flag to create session if it doesn't exist
- rename split-window -> split-pane??
- fix UTF-8 guesswork on sparc64, improve tty checks
- choice and more mode would be better per client than per window?
- hooks to which commands may be attached, for example: tmux add-hook
"new-session" if-shell "[ -e $HOME/.tmux-session.conf ]" source-file
$HOME/.tmux-session.conf
- get it passing all the vttest tests that don't require resizing the terminal
- esc seq to set window title should be documented and should set
automatic-rename
- way to set socket path from config file
- XXX once env stuff is in, default-path and VISUAL/EDITOR should be picked up
when session is started
- what about utmp etc? can tmux update it like screen? setgid?
- H/M/L commands in copy mode with vi-keys, for jumping to the top/middle/last
line on the screen
- split list-windows into separate list-windows and list-panes
- warts on current naming:
- display-time but message-fg/bg/attr
- list-* vs show-*
- server-info
- up-pane/down-pane/swap-pane -U/swap-pane -D vs next-*/previous-*
- split-window -> split-pane??
- pcvt25 doesn't work properly, why? (bce?)
- tidy up and prioritise todo list ;-)
- it is only possible to specify 8 colours to fg/bg options; should be able to
set 256 as well
- neww and attach can create a session if none exists?
would work fine with config file since
- a way for force-width/height to apply to only one pane (how?)
- **** a command to run something without a window and send any output to the
window-more. if no output, info() a line saying "'%s' returned %d". so i can
bind mpc control commands to function keys ;-)
- command to list what is actually running in each window with command line,
pid (need some adaption of the osdep code)
- string option to change/remove the symbols (*-+ etc) in status line
- support for bce
- it would be nice if the start/end line keys in copy mode were aware of
wrapped lines
- per session locking
- some way to force a screen to use the entire terminal even if it is forced
to be smaller by other clients. pan smaller terminal? (like screen F)
-- idea of a "view" onto a window, need base x/y offsets for redraw
-- idea of a "view" onto a window, need base x/y offsets
for redraw
- a window option which means data is echoed to all panes in a window
- support running tmux from inside tmux [#(), if-shell] --
generic system-like function which may take a callback
also sets up environment (TMUX) and has a timeout
for #(): command schedular, status line queues it with a time, run in
main loop, and uses most recent result -- can also be used for persistent
commands which never exit just continually output
for if-shell, callback??
- handle resize better in copy mode
- way to copy stuff that is off screen due to resize
- fix line wrapping c&p problems in xterm etc
- a way to address panes by name ("top-left") and position ("0,0")
- ability to specify multiple prefix keys
- commands should be able to succeed or fail and have || or && for command
lists
- some way to KEEP a command running continually and just use its LAST line of
output
- UTF-8 to a non-UTF-8 terminal should not be able to balls up
the terminal - www/ruby-addressable; make regress
- support esc-esc to quit in modes
- fix ctrl+F1-F4 output. to what?
- better utf8 support: window names, prompt input, message display
- session history for client and last-session command
- option to change status line colour when current window is in a mode?
- option to move copy mode indicator into status line
- list-buffer/show-buffer should display UTF-8
- selection behaviour closer to vi in vi mode
- live update: server started with -U connects to server, requests sessions and
windows, receives fds
- command to show a tree of sessions-windows-panes (active marked with *)
- sort out inheriting config from shell on new sessions/windows:
should pick up default-path/termios/etc from client if possible,
else leave empty/default
- link panes into multiple windows
- bells should be passed between sessions with visual-bell etc
- use screen-256color when started on 256 colour terminal??
- if-shell/run-shell should block further command execution in the same command
sequence until its shell exits, to allow them to be used from the config file
- better session sharing: create-socket command to create socket somewhere (-r
flag for readonly)
- allow buffer to be specified when copying in copy mode
- multiline status line (no?)
- flag for absolute pane size to resize-pane
- sanity check input to socket
- support title stack, both internally and externally
http://docs.freebsd.org/cgi/getmsg.cgi?fetch=1149299+0+archive/2010/freebsd-questions/20100207.freebsd-questions
- command to show status line information briefly when it is off
- some way to pad # stuff with spaces, #!2T maybe
- a binding to "scroll down and exit at bottom" copy mode
- some way to pass keystrokes in copy mode through to underlying window
- last window update time and # replacement for it for display-message
- find-window across sessions - other ways to make session handling easier?
- ' and " should be parsed the same (eg "\e" vs '\e') in config and command
prompt?
- command to toggle selection not to move it in copy-mode
- why are alerts per-winlink? try per window?
- audit of escape sequence support vs xterm
- support binding keys to mouse (mouse-select-pane -> mouse-keys or something,
mouse click == select-pane -t %%, mouse scroll up == copy-mode)
- something for -t "last window in session" so a session can be used as a stack
- synchronous commands - client sends cmd and blocks, neww/splitw saves client
ptr then when program inside died, sends MSG_SOMETHING with wait status to
client
- documentation improvements - rlpowell's tutorial - build instructions
- bind commands to key sequences? -- make it so ALL keys go through a table,
first an implicit table in which C-b is the only default binding to a
command that says "next key from $othertable" and so on. means -n can
go away as well
- monitor, bell etc should monitor /all/ panes in the window not just one
- a history of commands that can be reversed (reverse member of each command,
and a buffer) info() when changing to same window
- way to add dest for break-pane; maybe some easier way to unbreak-pane
- case insensitive searching
- pane-index option like base-index
- option to move status line to top
- configurable borders and empty space filler for when panes < window?
- mouse-select-pane will screw up with !MODE_MOUSE_STANDARD (it sets the
flag on w/o checking the others before calling tty_update_mode)
- 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 %%'"
- else part for if-shell
- add general internal format for lists (key=value) and a way to output them in
different representations, use for list-windows, etc etc. see message id
20110221205346.GA1580@yelena.nicm.ath.cx
- numeric prefix in copy mode should be paste buffer for C-w
- named buffers and allow gaps in the stack
- npage/ppage/dc/ic should have aliases for more typical names
- get rid of separate UTF-8 cell stuff: add 1 byte to cell and store BMP as
uint16_t+3 bits of flags. anything <=0xffff is Unicode, higher are used to
build tree of combined characters/non-BMP (LRU dropped when full)
- entry in FAQ about what to do when someone does mkdir /tmp/tmux-1000
- show size under pane number in display-panes mode
- monitor-activity is broken in several ways with multiple clients
- monitor-activity should be more powerful (eg set a region)
- maybe a way to put pane names instead of window names in status line
- Support for borderless panes
- run-shell/if-shell should support status_replace stuff
- wait-pane command or another way to make it synchronous/wait for command to
finish
- way to get command window was started with (part of format stuff?)
- last-pane across sessions
- attach should take a pane and select it as well as attaching
* We need a tmux terminfo entry to document the extensions we are using in
upstream terminfo. Must NOT change (only add or remove) anything from
TERM=screen so we can fallback!
- support the mouse wheel to scroll through history

View File

@@ -1,222 +0,0 @@
/* $Id$ */
/*
* Copyright (c) 2010 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"
/* Create an arguments set with no flags. */
struct args *
args_create(int argc, ...)
{
struct args *args;
va_list ap;
int i;
args = xcalloc(1, sizeof *args);
if ((args->flags = bit_alloc(SCHAR_MAX)) == NULL)
fatal("bit_alloc failed");
args->argc = argc;
if (argc == 0)
args->argv = NULL;
else
args->argv = xcalloc(argc, sizeof *args->argv);
va_start(ap, argc);
for (i = 0; i < argc; i++)
args->argv[i] = xstrdup(va_arg(ap, char *));
va_end(ap);
return (args);
}
/* Parse an argv and argc into a new argument set. */
struct args *
args_parse(const char *template, int argc, char **argv)
{
struct args *args;
char *ptr;
int opt;
args = xcalloc(1, sizeof *args);
if ((args->flags = bit_alloc(SCHAR_MAX)) == NULL)
fatal("bit_alloc failed");
optreset = 1;
optind = 1;
while ((opt = getopt(argc, argv, template)) != -1) {
if (opt < 0 || opt >= SCHAR_MAX)
continue;
if (opt == '?' || (ptr = strchr(template, opt)) == NULL) {
xfree(args->flags);
xfree(args);
return (NULL);
}
bit_set(args->flags, opt);
if (ptr[1] == ':') {
if (args->values[opt] != NULL)
xfree(args->values[opt]);
args->values[opt] = xstrdup(optarg);
}
}
argc -= optind;
argv += optind;
args->argc = argc;
args->argv = cmd_copy_argv(argc, argv);
return (args);
}
/* Free an arguments set. */
void
args_free(struct args *args)
{
u_int i;
cmd_free_argv(args->argc, args->argv);
for (i = 0; i < SCHAR_MAX; i++) {
if (args->values[i] != NULL)
xfree(args->values[i]);
}
xfree(args->flags);
xfree(args);
}
/* Print a set of arguments. */
size_t
args_print(struct args *args, char *buf, size_t len)
{
size_t off;
int i;
const char *quotes;
/* There must be at least one byte at the start. */
if (len == 0)
return (0);
off = 0;
/* Process the flags first. */
buf[off++] = '-';
for (i = 0; i < SCHAR_MAX; i++) {
if (!bit_test(args->flags, i) || args->values[i] != NULL)
continue;
if (off == len - 1) {
buf[off] = '\0';
return (len);
}
buf[off++] = i;
buf[off] = '\0';
}
if (off == 1)
buf[--off] = '\0';
/* Then the flags with arguments. */
for (i = 0; i < SCHAR_MAX; i++) {
if (!bit_test(args->flags, i) || args->values[i] == NULL)
continue;
if (off >= len) {
/* snprintf will have zero terminated. */
return (len);
}
if (strchr(args->values[i], ' ') != NULL)
quotes = "\"";
else
quotes = "";
off += xsnprintf(buf + off, len - off, "%s-%c %s%s%s",
off != 0 ? " " : "", i, quotes, args->values[i], quotes);
}
/* And finally the argument vector. */
for (i = 0; i < args->argc; i++) {
if (off >= len) {
/* snprintf will have zero terminated. */
return (len);
}
if (strchr(args->argv[i], ' ') != NULL)
quotes = "\"";
else
quotes = "";
off += xsnprintf(buf + off, len - off, "%s%s%s%s",
off != 0 ? " " : "", quotes, args->argv[i], quotes);
}
return (off);
}
/* Return if an argument is present. */
int
args_has(struct args *args, u_char ch)
{
return (bit_test(args->flags, ch));
}
/* Set argument value. */
void
args_set(struct args *args, u_char ch, const char *value)
{
if (args->values[ch] != NULL)
xfree(args->values[ch]);
if (value != NULL)
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. */
const char *
args_get(struct args *args, u_char ch)
{
return (args->values[ch]);
}
/* Convert an argument value to a number. */
long long
args_strtonum(struct args *args,
u_char ch, long long minval, long long maxval, char **cause)
{
const char *errstr;
long long ll;
if (!args_has(args, ch)) {
*cause = xstrdup("missing");
return (0);
}
ll = strtonum(args->values[ch], minval, maxval, &errstr);
if (errstr != NULL) {
*cause = xstrdup(errstr);
return (0);
}
*cause = NULL;
return (ll);
}

10
array.h
View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: array.h,v 1.7 2008-09-29 16:58:02 nicm Exp $ */
/*
* Copyright (c) 2006 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -19,8 +19,6 @@
#ifndef ARRAY_H
#define ARRAY_H
#define ARRAY_INITIALIZER { NULL, 0, 0 }
#define ARRAY_DECL(n, c) \
struct n { \
c *list; \
@@ -47,7 +45,7 @@
} \
} while (0)
#define ARRAY_EMPTY(a) (((void *) (a)) == NULL || (a)->num == 0)
#define ARRAY_EMPTY(a) ((a) == NULL || (a)->num == 0)
#define ARRAY_LENGTH(a) ((a)->num)
#define ARRAY_DATA(a) ((a)->list)
@@ -87,7 +85,7 @@
ARRAY_ITEMSIZE(a) * ((a)->num - (i) - 1)); \
} \
(a)->num--; \
if ((a)->num == 0) \
if ((a)->num == 0) \
ARRAY_FREE(a); \
} while (0)
@@ -104,7 +102,7 @@
#define ARRAY_CONCAT(a, b) do { \
ARRAY_ENSURE(a, (b)->num); \
memcpy((a)->list + (a)->num, (b)->list, (b)->num * ARRAY_ITEMSIZE(a)); \
memcpy((a)->list + (a)->num, (b)->list, (b)->num * ARRAY_ITEMSIZE(a)) \
(a)->num += (b)->num; \
} while (0)

View File

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

View File

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

54
buffer-poll.c Normal file
View File

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

139
buffer.c Normal file
View File

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

64
cfg.c
View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cfg.c,v 1.22 2009-08-24 16:27:03 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -33,17 +33,13 @@
void printflike2 cfg_print(struct cmd_ctx *, const char *, ...);
void printflike2 cfg_error(struct cmd_ctx *, const char *, ...);
char *cfg_cause;
int cfg_finished;
struct causelist cfg_causes = ARRAY_INITIALIZER;
char *cfg_cause;
/* ARGSUSED */
void printflike2
cfg_print(unused struct cmd_ctx *ctx, unused const char *fmt, ...)
{
}
/* ARGSUSED */
void printflike2
cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...)
{
@@ -54,42 +50,23 @@ cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...)
va_end(ap);
}
void printflike2
cfg_add_cause(struct causelist *causes, const char *fmt, ...)
{
char *cause;
va_list ap;
va_start(ap, fmt);
xvasprintf(&cause, fmt, ap);
va_end(ap);
ARRAY_ADD(causes, cause);
}
/*
* Load configuration file. Returns -1 for an error with a list of messages in
* causes. Note that causes must be initialised by the caller!
*/
int
load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)
load_cfg(const char *path, struct cmd_ctx *ctxin, char **cause)
{
FILE *f;
FILE *f;
u_int n;
char *buf, *line, *cause;
char *buf, *line, *ptr;
size_t len;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
int retval;
if ((f = fopen(path, "rb")) == NULL) {
cfg_add_cause(causes, "%s: %s", path, strerror(errno));
return (-1);
xasprintf(cause, "%s: %s", path, strerror(errno));
return (1);
}
n = 0;
line = NULL;
retval = 0;
while ((buf = fgetln(f, &len))) {
if (buf[len - 1] == '\n')
buf[len - 1] = '\0';
@@ -101,12 +78,10 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)
}
n++;
if (cmd_string_parse(buf, &cmdlist, &cause) != 0) {
if (cause == NULL)
if (cmd_string_parse(buf, &cmdlist, cause) != 0) {
if (*cause == NULL)
continue;
cfg_add_cause(causes, "%s: %u: %s", path, n, cause);
xfree(cause);
continue;
goto error;
}
if (cmdlist == NULL)
continue;
@@ -127,17 +102,26 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)
ctx.info = cfg_print;
cfg_cause = NULL;
if (cmd_list_exec(cmdlist, &ctx) == 1)
retval = 1;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist);
if (cfg_cause != NULL) {
cfg_add_cause(causes, "%s: %d: %s", path, n, cfg_cause);
xfree(cfg_cause);
*cause = cfg_cause;
goto error;
}
}
if (line != NULL)
xfree(line);
fclose(f);
return (retval);
return (0);
error:
if (line != NULL)
xfree(line);
fclose(f);
xasprintf(&ptr, "%s: %s at line %u", path, *cause, n);
xfree(*cause);
*cause = ptr;
return (1);
}

90
client-fn.c Normal file
View File

@@ -0,0 +1,90 @@
/* $Id: client-fn.c,v 1.10 2009-08-14 21:04:04 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
void
client_fill_session(struct msg_command_data *data)
{
char *env, *ptr1, *ptr2, buf[256];
size_t len;
const char *errstr;
long long ll;
data->pid = -1;
if ((env = getenv("TMUX")) == NULL)
return;
if ((ptr2 = strrchr(env, ',')) == NULL || ptr2 == env)
return;
for (ptr1 = ptr2 - 1; ptr1 > env && *ptr1 != ','; ptr1--)
;
if (*ptr1 != ',')
return;
ptr1++;
ptr2++;
len = ptr2 - ptr1 - 1;
if (len > (sizeof buf) - 1)
return;
memcpy(buf, ptr1, len);
buf[len] = '\0';
ll = strtonum(buf, 0, LONG_MAX, &errstr);
if (errstr != NULL)
return;
data->pid = ll;
ll = strtonum(ptr2, 0, UINT_MAX, &errstr);
if (errstr != NULL)
return;
data->idx = ll;
}
void
client_write_server(
struct client_ctx *cctx, enum msgtype type, void *buf, size_t len)
{
imsg_compose(&cctx->ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
}
void
client_suspend(void)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART;
act.sa_handler = SIG_DFL;
if (sigaction(SIGTSTP, &act, NULL) != 0)
fatal("sigaction failed");
act.sa_handler = sighandler;
if (sigaction(SIGCONT, &act, NULL) != 0)
fatal("sigaction failed");
kill(getpid(), SIGTSTP);
}

596
client.c
View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: client.c,v 1.70 2009-09-03 21:06:30 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -17,452 +17,290 @@
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <errno.h>
#include <event.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "tmux.h"
struct imsgbuf client_ibuf;
struct event client_event;
const char *client_exitmsg;
int client_exitval;
enum msgtype client_exittype;
int client_attached;
void client_send_environ(struct client_ctx *);
void client_handle_winch(struct client_ctx *);
int client_connect(char *, int);
void client_send_identify(int);
void client_send_environ(void);
void client_write_server(enum msgtype, void *, size_t);
void client_update_event(void);
void client_signal(int, short, void *);
void client_callback(int, short, void *);
int client_dispatch_attached(void);
int client_dispatch_wait(void *);
/* Connect client to server. */
int
client_connect(char *path, int start_server)
client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags)
{
struct sockaddr_un sa;
size_t size;
int fd;
struct sockaddr_un sa;
struct stat sb;
struct msg_identify_data data;
struct winsize ws;
size_t size;
int fd, fd2, mode;
char *name, *term;
#ifdef HAVE_SETPROCTITLE
char rpathbuf[MAXPATHLEN];
#endif
#ifdef HAVE_SETPROCTITLE
if (realpath(path, rpathbuf) == NULL)
strlcpy(rpathbuf, path, sizeof rpathbuf);
setproctitle("client (%s)", rpathbuf);
#endif
if (lstat(path, &sb) != 0) {
if (cmdflags & CMD_STARTSERVER && errno == ENOENT) {
if ((fd = server_start(path)) == -1)
goto start_failed;
goto server_started;
}
goto not_found;
}
if (!S_ISSOCK(sb.st_mode)) {
errno = ENOTSOCK;
goto not_found;
}
memset(&sa, 0, sizeof sa);
sa.sun_family = AF_UNIX;
size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
if (size >= sizeof sa.sun_path) {
errno = ENAMETOOLONG;
return (-1);
goto not_found;
}
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
fatal("socket failed");
fatal("socket");
if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
if (!start_server)
goto failed;
switch (errno) {
case ECONNREFUSED:
if (unlink(path) != 0)
goto failed;
/* FALLTHROUGH */
case ENOENT:
if ((fd = server_start()) == -1)
goto failed;
break;
default:
goto failed;
if (errno == ECONNREFUSED) {
if (unlink(path) != 0 || !(cmdflags & CMD_STARTSERVER))
goto not_found;
if ((fd = server_start(path)) == -1)
goto start_failed;
goto server_started;
}
goto not_found;
}
setblocking(fd, 0);
return (fd);
server_started:
if ((mode = fcntl(fd, F_GETFL)) == -1)
fatal("fcntl failed");
if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed");
imsg_init(&cctx->ibuf, fd);
failed:
close(fd);
return (-1);
}
/* Client main loop. */
int
client_main(int argc, char **argv, int flags)
{
struct cmd *cmd;
struct cmd_list *cmdlist;
struct msg_command_data cmddata;
int cmdflags, fd;
pid_t ppid;
enum msgtype msg;
char *cause;
/* Set up the initial command. */
cmdflags = 0;
if (shell_cmd != NULL) {
msg = MSG_SHELL;
cmdflags = CMD_STARTSERVER;
} else if (argc == 0) {
msg = MSG_COMMAND;
cmdflags = CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST;
} else {
msg = MSG_COMMAND;
/*
* It sucks parsing the command string twice (in client and
* later in server) but it is necessary to get the start server
* flag.
*/
if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
log_warnx("%s", cause);
return (1);
}
cmdflags &= ~CMD_STARTSERVER;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
if (cmd->entry->flags & CMD_STARTSERVER)
cmdflags |= CMD_STARTSERVER;
if (cmd->entry->flags & CMD_SENDENVIRON)
cmdflags |= CMD_SENDENVIRON;
if (cmd->entry->flags & CMD_CANTNEST)
cmdflags |= CMD_CANTNEST;
}
cmd_list_free(cmdlist);
}
/*
* Check if this could be a nested session, if the command can't nest:
* if the socket path matches $TMUX, this is probably the same server.
*/
if (shell_cmd == NULL && environ_path != NULL &&
cmdflags & CMD_CANTNEST && strcmp(socket_path, environ_path) == 0) {
log_warnx("sessions should be nested with care. "
"unset $TMUX to force.");
return (1);
}
/* Initialise the client socket and start the server. */
fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER);
if (fd == -1) {
log_warn("failed to connect to server");
return (1);
}
/* Set process title, log and signals now this is the client. */
#ifdef HAVE_SETPROCTITLE
setproctitle("client (%s)", socket_path);
#endif
logfile("client");
/* Create imsg. */
imsg_init(&client_ibuf, fd);
event_set(&client_event, fd, EV_READ, client_callback, shell_cmd);
/* Establish signal handlers. */
set_signals(client_signal);
/* Send initial environment. */
if (cmdflags & CMD_SENDENVIRON)
client_send_environ();
client_send_identify(flags);
client_send_environ(cctx);
if (isatty(STDIN_FILENO)) {
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
fatal("ioctl(TIOCGWINSZ)");
data.flags = flags;
data.sx = ws.ws_col;
data.sy = ws.ws_row;
/* Send first command. */
if (msg == MSG_COMMAND) {
/* Fill in command line arguments. */
cmddata.pid = environ_pid;
cmddata.idx = environ_idx;
if (getcwd(data.cwd, sizeof data.cwd) == NULL)
*data.cwd = '\0';
/* Prepare command for server. */
cmddata.argc = argc;
if (cmd_pack_argv(
argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) {
log_warnx("command too long");
return (1);
*data.term = '\0';
if ((term = getenv("TERM")) != NULL) {
if (strlcpy(data.term,
term, sizeof data.term) >= sizeof data.term)
*data.term = '\0';
}
client_write_server(msg, &cmddata, sizeof cmddata);
} else if (msg == MSG_SHELL)
client_write_server(msg, NULL, 0);
*data.tty = '\0';
if ((name = ttyname(STDIN_FILENO)) == NULL)
fatal("ttyname failed");
if (strlcpy(data.tty, name, sizeof data.tty) >= sizeof data.tty)
fatalx("ttyname failed");
/* Set the event and dispatch. */
client_update_event();
event_dispatch();
/* Print the exit message, if any, and exit. */
if (client_attached) {
if (client_exitmsg != NULL && !login_shell)
printf("[%s]\n", client_exitmsg);
ppid = getppid();
if (client_exittype == MSG_DETACHKILL && ppid > 1)
kill(ppid, SIGHUP);
fd2 = dup(STDIN_FILENO);
imsg_compose(&cctx->ibuf, MSG_IDENTIFY,
PROTOCOL_VERSION, -1, fd2, &data, sizeof data);
}
return (client_exitval);
return (0);
start_failed:
log_warnx("server failed to start");
return (1);
not_found:
log_warn("server not found");
return (1);
}
/* Send identify message to server with the file descriptors. */
void
client_send_identify(int flags)
client_send_environ(struct client_ctx *cctx)
{
struct msg_identify_data data;
char *term;
int fd;
data.flags = flags;
if (getcwd(data.cwd, sizeof data.cwd) == NULL)
*data.cwd = '\0';
term = getenv("TERM");
if (term == NULL ||
strlcpy(data.term, term, sizeof data.term) >= sizeof data.term)
*data.term = '\0';
if ((fd = dup(STDIN_FILENO)) == -1)
fatal("dup failed");
imsg_compose(&client_ibuf,
MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
if ((fd = dup(STDOUT_FILENO)) == -1)
fatal("dup failed");
imsg_compose(&client_ibuf,
MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0);
if ((fd = dup(STDERR_FILENO)) == -1)
fatal("dup failed");
imsg_compose(&client_ibuf,
MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0);
}
/* Forward entire environment to server. */
void
client_send_environ(void)
{
struct msg_environ_data data;
char **var;
struct msg_environ_data data;
for (var = environ; *var != NULL; var++) {
for (var = environ; *var != NULL; var++) {
if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var)
continue;
client_write_server(MSG_ENVIRON, &data, sizeof data);
client_write_server(cctx, MSG_ENVIRON, &data, sizeof data);
}
}
/* Write a message to the server without a file descriptor. */
void
client_write_server(enum msgtype type, void *buf, size_t len)
{
imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
}
/* Update client event based on whether it needs to read or read and write. */
void
client_update_event(void)
{
short events;
event_del(&client_event);
events = EV_READ;
if (client_ibuf.w.queued > 0)
events |= EV_WRITE;
event_set(
&client_event, client_ibuf.fd, events, client_callback, shell_cmd);
event_add(&client_event, NULL);
}
/* Callback to handle signals in the client. */
/* ARGSUSED */
void
client_signal(int sig, unused short events, unused void *data)
{
struct sigaction sigact;
int status;
if (!client_attached) {
switch (sig) {
case SIGCHLD:
waitpid(WAIT_ANY, &status, WNOHANG);
break;
case SIGTERM:
event_loopexit(NULL);
break;
}
} else {
switch (sig) {
case SIGHUP:
client_exitmsg = "lost tty";
client_exitval = 1;
client_write_server(MSG_EXITING, NULL, 0);
break;
case SIGTERM:
client_exitmsg = "terminated";
client_exitval = 1;
client_write_server(MSG_EXITING, NULL, 0);
break;
case SIGWINCH:
client_write_server(MSG_RESIZE, NULL, 0);
break;
case SIGCONT:
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
client_write_server(MSG_WAKEUP, NULL, 0);
break;
}
}
client_update_event();
}
/* Callback for client imsg read events. */
/* ARGSUSED */
void
client_callback(unused int fd, short events, void *data)
{
ssize_t n;
int retval;
if (events & EV_READ) {
if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
goto lost_server;
if (client_attached)
retval = client_dispatch_attached();
else
retval = client_dispatch_wait(data);
if (retval != 0) {
event_loopexit(NULL);
return;
}
}
if (events & EV_WRITE) {
if (msgbuf_write(&client_ibuf.w) < 0)
goto lost_server;
}
client_update_event();
return;
lost_server:
client_exitmsg = "lost server";
client_exitval = 1;
event_loopexit(NULL);
}
/* Dispatch imsgs when in wait state (before MSG_READY). */
int
client_dispatch_wait(void *data)
client_main(struct client_ctx *cctx)
{
struct imsg imsg;
ssize_t n, datalen;
struct msg_shell_data shelldata;
struct msg_exit_data exitdata;
const char *shellcmd = data;
struct pollfd pfd;
int n, nfds;
if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
fatalx("imsg_read failed");
siginit();
logfile("client");
/*
* imsg_read in the first client poll loop (before the terminal has
* been initialiased) may have read messages into the buffer after the
* MSG_READY switched to here. Process anything outstanding now so poll
* doesn't hang waiting for messages that have already arrived.
*/
if (client_msg_dispatch(cctx) != 0)
goto out;
for (;;) {
if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
fatalx("imsg_get failed");
if (n == 0)
return (0);
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
if (sigterm)
client_write_server(cctx, MSG_EXITING, NULL, 0);
if (sigchld) {
waitpid(WAIT_ANY, NULL, WNOHANG);
sigchld = 0;
}
if (sigwinch)
client_handle_winch(cctx);
if (sigcont) {
siginit();
client_write_server(cctx, MSG_WAKEUP, NULL, 0);
sigcont = 0;
}
switch (imsg.hdr.type) {
case MSG_EXIT:
case MSG_SHUTDOWN:
if (datalen != sizeof exitdata) {
if (datalen != 0)
fatalx("bad MSG_EXIT size");
} else {
memcpy(&exitdata, imsg.data, sizeof exitdata);
client_exitval = exitdata.retcode;
pfd.fd = cctx->ibuf.fd;
pfd.events = POLLIN;
if (cctx->ibuf.w.queued > 0)
pfd.events |= POLLOUT;
if ((nfds = poll(&pfd, 1, INFTIM)) == -1) {
if (errno == EAGAIN || errno == EINTR)
continue;
fatal("poll failed");
}
if (nfds == 0)
continue;
if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL))
fatalx("socket error");
if (pfd.revents & POLLIN) {
if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) {
cctx->exittype = CCTX_DIED;
break;
}
imsg_free(&imsg);
return (-1);
case MSG_READY:
if (datalen != 0)
fatalx("bad MSG_READY size");
client_attached = 1;
break;
case MSG_VERSION:
if (datalen != 0)
fatalx("bad MSG_VERSION size");
log_warnx("protocol version mismatch (client %u, "
"server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
client_exitval = 1;
imsg_free(&imsg);
return (-1);
case MSG_SHELL:
if (datalen != sizeof shelldata)
fatalx("bad MSG_SHELL size");
memcpy(&shelldata, imsg.data, sizeof shelldata);
shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
clear_signals(0);
shell_exec(shelldata.shell, shellcmd);
/* NOTREACHED */
default:
fatalx("unexpected message");
if (client_msg_dispatch(cctx) != 0)
break;
}
imsg_free(&imsg);
if (pfd.revents & POLLOUT) {
if (msgbuf_write(&cctx->ibuf.w) < 0) {
cctx->exittype = CCTX_DIED;
break;
}
}
}
out:
if (sigterm) {
printf("[terminated]\n");
return (1);
}
switch (cctx->exittype) {
case CCTX_DIED:
printf("[lost server]\n");
return (0);
case CCTX_SHUTDOWN:
printf("[server exited]\n");
return (0);
case CCTX_EXIT:
if (cctx->errstr != NULL) {
printf("[error: %s]\n", cctx->errstr);
return (1);
}
printf("[exited]\n");
return (0);
case CCTX_DETACH:
printf("[detached]\n");
return (0);
default:
printf("[unknown error]\n");
return (1);
}
}
/* Dispatch imsgs in attached state (after MSG_READY). */
/* ARGSUSED */
int
client_dispatch_attached(void)
void
client_handle_winch(struct client_ctx *cctx)
{
struct imsg imsg;
struct msg_lock_data lockdata;
struct sigaction sigact;
ssize_t n, datalen;
struct msg_resize_data data;
struct winsize ws;
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
fatal("ioctl failed");
data.sx = ws.ws_col;
data.sy = ws.ws_row;
client_write_server(cctx, MSG_RESIZE, &data, sizeof data);
sigwinch = 0;
}
int
client_msg_dispatch(struct client_ctx *cctx)
{
struct imsg imsg;
struct msg_print_data printdata;
ssize_t n, datalen;
for (;;) {
if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1)
fatalx("imsg_get failed");
if (n == 0)
return (0);
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
log_debug("client got %d", imsg.hdr.type);
switch (imsg.hdr.type) {
case MSG_DETACHKILL:
case MSG_DETACH:
if (datalen != 0)
fatalx("bad MSG_DETACH size");
client_exittype = imsg.hdr.type;
if (imsg.hdr.type == MSG_DETACHKILL)
client_exitmsg = "detached and SIGHUP";
else
client_exitmsg = "detached";
client_write_server(MSG_EXITING, NULL, 0);
client_write_server(cctx, MSG_EXITING, NULL, 0);
cctx->exittype = CCTX_DETACH;
break;
case MSG_ERROR:
if (datalen != sizeof printdata)
fatalx("bad MSG_ERROR size");
memcpy(&printdata, imsg.data, sizeof printdata);
printdata.msg[(sizeof printdata.msg) - 1] = '\0';
/* Error string used after exit message from server. */
cctx->errstr = xstrdup(printdata.msg);
imsg_free(&imsg);
return (-1);
case MSG_EXIT:
if (datalen != 0 &&
datalen != sizeof (struct msg_exit_data))
if (datalen != 0)
fatalx("bad MSG_EXIT size");
client_write_server(MSG_EXITING, NULL, 0);
client_exitmsg = "exited";
client_write_server(cctx, MSG_EXITING, NULL, 0);
cctx->exittype = CCTX_EXIT;
break;
case MSG_EXITED:
if (datalen != 0)
@@ -474,30 +312,14 @@ client_dispatch_attached(void)
if (datalen != 0)
fatalx("bad MSG_SHUTDOWN size");
client_write_server(MSG_EXITING, NULL, 0);
client_exitmsg = "server exited";
client_exitval = 1;
client_write_server(cctx, MSG_EXITING, NULL, 0);
cctx->exittype = CCTX_SHUTDOWN;
break;
case MSG_SUSPEND:
if (datalen != 0)
fatalx("bad MSG_SUSPEND size");
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_DFL;
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
kill(getpid(), SIGTSTP);
break;
case MSG_LOCK:
if (datalen != sizeof lockdata)
fatalx("bad MSG_LOCK size");
memcpy(&lockdata, imsg.data, sizeof lockdata);
lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0';
system(lockdata.cmd);
client_write_server(MSG_UNLOCK, NULL, 0);
client_suspend();
break;
default:
fatalx("unexpected message");

12
clock.c
View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: clock.c,v 1.7 2009-09-11 14:13:52 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -97,7 +97,7 @@ const char clock_table[14][5][5] = {
};
void
clock_draw(struct screen_write_ctx *ctx, int colour, int style)
clock_draw(struct screen_write_ctx *ctx, u_int colour, int style)
{
struct screen *s = ctx->s;
struct grid_cell gc;
@@ -134,13 +134,13 @@ clock_draw(struct screen_write_ctx *ctx, int colour, int style)
for (ptr = tim; *ptr != '\0'; ptr++) {
if (*ptr >= '0' && *ptr <= '9')
idx = *ptr - '0';
else if (*ptr == ':')
else if (*ptr == ':')
idx = 10;
else if (*ptr == 'A')
else if (*ptr == 'A')
idx = 11;
else if (*ptr == 'P')
else if (*ptr == 'P')
idx = 12;
else if (*ptr == 'M')
else if (*ptr == 'M')
idx = 13;
else {
x += 6;

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-attach-session.c,v 1.32 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,38 +28,38 @@ int cmd_attach_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_attach_session_entry = {
"attach-session", "attach",
"drt:", 0, 0,
"[-dr] " CMD_TARGET_SESSION_USAGE,
CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON,
NULL,
NULL,
cmd_attach_session_exec
"[-d] " CMD_TARGET_SESSION_USAGE,
CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, CMD_CHFLAG('d'),
cmd_target_init,
cmd_target_parse,
cmd_attach_session_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s;
struct client *c;
const char *update;
char *overrides, *cause;
u_int i;
struct cmd_target_data *data = self->data;
struct session *s;
struct client *c;
const char *update;
char *overrides, *cause;
u_int i;
if (RB_EMPTY(&sessions)) {
if (ARRAY_LENGTH(&sessions) == 0) {
ctx->error(ctx, "no sessions");
return (-1);
}
if ((s = cmd_find_session(ctx, args_get(args, 't'), 1)) == NULL)
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (ctx->cmdclient == NULL && ctx->curclient == NULL)
return (0);
if (ctx->cmdclient == NULL) {
if (args_has(self->args, 'd')) {
/*
if (data->chflags & CMD_CHFLAG('d')) {
/*
* Can't use server_write_session in case attaching to
* the same session as currently attached to.
*/
@@ -72,9 +72,8 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
server_write_client(c, MSG_DETACH, NULL, 0);
}
}
ctx->curclient->session = s;
session_update_activity(s);
server_redraw_client(ctx->curclient);
} else {
if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) {
@@ -90,14 +89,10 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1);
}
if (args_has(self->args, 'r'))
ctx->cmdclient->flags |= CLIENT_READONLY;
if (args_has(self->args, 'd'))
if (data->chflags & CMD_CHFLAG('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");
@@ -106,7 +101,6 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
server_redraw_client(ctx->cmdclient);
}
recalculate_sizes();
server_update_socket();
return (1); /* 1 means don't tell command client to exit */
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-bind-key.c,v 1.25 2009-07-28 23:19:06 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,87 +26,135 @@
* Bind a key to a command, this recurses through cmd_*.
*/
int cmd_bind_key_check(struct args *);
int cmd_bind_key_parse(struct cmd *, int, char **, char **);
int cmd_bind_key_exec(struct cmd *, struct cmd_ctx *);
void cmd_bind_key_free(struct cmd *);
size_t cmd_bind_key_print(struct cmd *, char *, size_t);
int cmd_bind_key_table(struct cmd *, struct cmd_ctx *, int);
int cmd_bind_key_table(struct cmd *, struct cmd_ctx *);
struct cmd_bind_key_data {
int key;
int can_repeat;
struct cmd_list *cmdlist;
int command_key;
char *tablename;
char *modecmd;
};
const struct cmd_entry cmd_bind_key_entry = {
"bind-key", "bind",
"cnrt:", 1, -1,
"[-cnr] [-t key-table] key command [arguments]",
0,
0, 0,
NULL,
cmd_bind_key_check,
cmd_bind_key_exec
cmd_bind_key_parse,
cmd_bind_key_exec,
cmd_bind_key_free,
cmd_bind_key_print
};
int
cmd_bind_key_check(struct args *args)
cmd_bind_key_parse(struct cmd *self, int argc, char **argv, char **cause)
{
if (args_has(args, 't')) {
if (args->argc != 2)
return (-1);
struct cmd_bind_key_data *data;
int opt, no_prefix = 0;
self->data = data = xmalloc(sizeof *data);
data->can_repeat = 0;
data->cmdlist = NULL;
data->command_key = 0;
data->tablename = NULL;
data->modecmd = NULL;
while ((opt = getopt(argc, argv, "cnrt:")) != -1) {
switch (opt) {
case 'c':
data->command_key = 1;
break;
case 'n':
no_prefix = 1;
break;
case 'r':
data->can_repeat = 1;
break;
case 't':
data->tablename = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (argc < 1)
goto usage;
if ((data->key = key_string_lookup_string(argv[0])) == KEYC_NONE) {
xasprintf(cause, "unknown key: %s", argv[0]);
goto error;
}
if (!no_prefix)
data->key |= KEYC_PREFIX;
argc--;
argv++;
if (data->tablename != NULL) {
if (argc != 1)
goto usage;
data->modecmd = xstrdup(argv[0]);
} else {
if (args->argc < 2)
return (-1);
if ((data->cmdlist = cmd_list_parse(argc, argv, cause)) == NULL)
goto error;
}
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
error:
self->entry->free(self);
return (-1);
}
int
cmd_bind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
{
struct cmd_bind_key_data *data = self->data;
if (data == NULL)
return (0);
if (data->tablename != NULL)
return (cmd_bind_key_table(self, ctx));
key_bindings_add(data->key, data->can_repeat, data->cmdlist);
data->cmdlist = NULL; /* avoid free */
return (0);
}
int
cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx)
cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
char *cause;
struct cmd_list *cmdlist;
int key;
key = key_string_lookup_string(args->argv[0]);
if (key == KEYC_NONE) {
ctx->error(ctx, "unknown key: %s", args->argv[0]);
return (-1);
}
if (args_has(args, 't'))
return (cmd_bind_key_table(self, ctx, key));
cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, &cause);
if (cmdlist == NULL) {
ctx->error(ctx, "%s", cause);
xfree(cause);
return (-1);
}
if (!args_has(args, 'n'))
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;
struct cmd_bind_key_data *data = self->data;
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);
if ((mtab = mode_key_findtable(data->tablename)) == NULL) {
ctx->error(ctx, "unknown key table: %s", data->tablename);
return (-1);
}
cmd = mode_key_fromstring(mtab->cmdstr, args->argv[1]);
cmd = mode_key_fromstring(mtab->cmdstr, data->modecmd);
if (cmd == MODEKEY_NONE) {
ctx->error(ctx, "unknown command: %s", args->argv[1]);
ctx->error(ctx, "unknown command: %s", data->modecmd);
return (-1);
}
mtmp.key = key;
mtmp.mode = !!args_has(args, 'c');
mtmp.key = data->key & ~KEYC_PREFIX;
mtmp.mode = data->command_key ? 1 : 0;
if ((mbind = SPLAY_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) {
mbind->cmd = cmd;
return (0);
@@ -118,3 +166,36 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
SPLAY_INSERT(mode_key_tree, mtab->tree, mbind);
return (0);
}
void
cmd_bind_key_free(struct cmd *self)
{
struct cmd_bind_key_data *data = self->data;
if (data->cmdlist != NULL)
cmd_list_free(data->cmdlist);
if (data->tablename != NULL)
xfree(data->tablename);
if (data->modecmd != NULL)
xfree(data->modecmd);
xfree(data);
}
size_t
cmd_bind_key_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_bind_key_data *data = self->data;
size_t off = 0;
const char *skey;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len) {
skey = key_string_lookup_key(data->key);
off += xsnprintf(buf + off, len - off, " %s ", skey);
}
if (off < len)
off += cmd_list_print(data->cmdlist, buf + off, len - off);
return (off);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-break-pane.c,v 1.8 2009-08-16 19:16:27 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,18 +30,19 @@ int cmd_break_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_break_pane_entry = {
"break-pane", "breakp",
"dt:", 0, 0,
"[-d] " CMD_TARGET_PANE_USAGE,
0,
NULL,
NULL,
cmd_break_pane_exec
CMD_TARGET_PANE_USAGE " [-d]",
0, CMD_CHFLAG('d'),
cmd_target_init,
cmd_target_parse,
cmd_break_pane_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct session *s;
struct window_pane *wp;
@@ -49,7 +50,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
char *cause;
int base_idx;
if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL)
if ((wl = cmd_find_pane(ctx, data->target, &s, &wp)) == NULL)
return (-1);
if (window_count_panes(wl->window) == 1) {
@@ -57,33 +58,26 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1);
}
w = wl->window;
TAILQ_REMOVE(&w->panes, wp, entry);
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);
TAILQ_REMOVE(&wl->window->panes, wp, entry);
if (wl->window->active == wp) {
wl->window->active = TAILQ_PREV(wp, window_panes, entry);
if (wl->window->active == NULL)
wl->window->active = TAILQ_NEXT(wp, entry);
}
layout_close_pane(wp);
w = wp->window = window_create1(s->sx, s->sy);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp;
w->name = default_window_name(w);
w = wp->window = window_create1(s->sx, s->sy);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp;
w->name = default_window_name(w);
layout_init(w);
base_idx = options_get_number(&s->options, "base-index");
wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */
if (!args_has(self->args, 'd'))
session_select(s, wl->idx);
wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */
if (!(data->chflags & CMD_CHFLAG('d')))
session_select(s, wl->idx);
server_redraw_session(s);
server_status_session_group(s);
return (0);
}

View File

@@ -1,123 +0,0 @@
/* $Id$ */
/*
* Copyright (c) 2009 Jonathan Alvarado <radobobo@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Write the entire contents of a pane to a buffer.
*/
int cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_capture_pane_entry = {
"capture-pane", "capturep",
"b:E:S:t:", 0, 0,
"[-b buffer-index] [-E end-line] [-S start-line] [-t target-pane]",
0,
NULL,
NULL,
cmd_capture_pane_exec
};
int
cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct window_pane *wp;
char *buf, *line, *cause;
struct screen *s;
struct grid *gd;
int buffer, n;
u_int i, limit, top, bottom, tmp;
size_t len, linelen;
if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
return (-1);
s = &wp->base;
gd = s->grid;
buf = NULL;
len = 0;
n = args_strtonum(args, 'S', SHRT_MIN, SHRT_MAX, &cause);
if (cause != NULL) {
top = gd->hsize;
xfree(cause);
} else if (n < 0 && (u_int) -n > gd->hsize)
top = 0;
else
top = gd->hsize + n;
if (top > gd->hsize + gd->sy - 1)
top = gd->hsize + gd->sy - 1;
n = args_strtonum(args, 'E', SHRT_MIN, SHRT_MAX, &cause);
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;
if (bottom < top) {
tmp = bottom;
bottom = top;
top = tmp;
}
for (i = top; i <= bottom; i++) {
line = grid_string_cells(s->grid, 0, i, screen_size_x(s));
linelen = strlen(line);
buf = xrealloc(buf, 1, len + linelen + 1);
memcpy(buf + len, line, linelen);
len += linelen;
buf[len++] = '\n';
xfree(line);
}
limit = options_get_number(&global_options, "buffer-limit");
if (!args_has(args, 'b')) {
paste_add(&global_buffers, buf, len, limit);
return (0);
}
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
ctx->error(ctx, "buffer %s", cause);
xfree(cause);
return (-1);
}
if (paste_replace(&global_buffers, buffer, buf, len) != 0) {
ctx->error(ctx, "no buffer %d", buffer);
xfree(buf);
return (-1);
}
return (0);
}

View File

@@ -1,143 +0,0 @@
/* $Id$ */
/*
* Copyright (c) 2010 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 buffer.
*/
int cmd_choose_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_choose_buffer_callback(void *, int);
void cmd_choose_buffer_free(void *);
const struct cmd_entry cmd_choose_buffer_entry = {
"choose-buffer", NULL,
"t:", 0, 1,
CMD_TARGET_WINDOW_USAGE " [template]",
0,
NULL,
NULL,
cmd_choose_buffer_exec
};
struct cmd_choose_buffer_data {
struct client *client;
char *template;
};
int
cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_choose_buffer_data *cdata;
struct winlink *wl;
struct paste_buffer *pb;
u_int idx;
char *tmp;
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 (paste_get_top(&global_buffers) == NULL)
return (0);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (0);
idx = 0;
while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) {
tmp = paste_print(pb, 50);
window_choose_add(wl->window->active, idx - 1,
"%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp);
xfree(tmp);
}
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++;
window_choose_ready(wl->window->active,
0, cmd_choose_buffer_callback, cmd_choose_buffer_free, cdata);
return (0);
}
void
cmd_choose_buffer_callback(void *data, int idx)
{
struct cmd_choose_buffer_data *cdata = data;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *template, *cause, tmp[16];
if (idx == -1)
return;
if (cdata->client->flags & CLIENT_DEAD)
return;
xsnprintf(tmp, sizeof tmp, "%u", idx);
template = cmd_template_replace(cdata->template, tmp, 1);
if (cmd_string_parse(template, &cmdlist, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(cdata->client, "%s", cause);
xfree(cause);
}
xfree(template);
return;
}
xfree(template);
ctx.msgdata = NULL;
ctx.curclient = cdata->client;
ctx.error = key_bindings_error;
ctx.print = key_bindings_print;
ctx.info = key_bindings_info;
ctx.cmdclient = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist);
}
void
cmd_choose_buffer_free(void *data)
{
struct cmd_choose_buffer_data *cdata = data;
cdata->client->references--;
xfree(cdata->template);
xfree(cdata);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-choose-client.c,v 1.3 2009-09-07 23:59:19 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -33,12 +33,13 @@ void cmd_choose_client_free(void *);
const struct cmd_entry cmd_choose_client_entry = {
"choose-client", NULL,
"t:", 0, 1,
CMD_TARGET_WINDOW_USAGE " [template]",
0,
NULL,
NULL,
cmd_choose_client_exec
CMD_ARG01, 0,
cmd_target_init,
cmd_target_parse,
cmd_choose_client_exec,
cmd_target_free,
cmd_target_print
};
struct cmd_choose_client_data {
@@ -49,7 +50,7 @@ struct cmd_choose_client_data {
int
cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct cmd_choose_client_data *cdata;
struct winlink *wl;
struct client *c;
@@ -60,7 +61,7 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1);
}
if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
@@ -82,8 +83,8 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx)
}
cdata = xmalloc(sizeof *cdata);
if (args->argc != 0)
cdata->template = xstrdup(args->argv[0]);
if (data->arg != NULL)
cdata->template = xstrdup(data->arg);
else
cdata->template = xstrdup("detach-client -t '%%'");
cdata->client = ctx->curclient;

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-choose-session.c,v 1.13 2009-09-07 23:59:19 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -33,12 +33,13 @@ 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
CMD_ARG01, 0,
cmd_target_init,
cmd_target_parse,
cmd_choose_session_exec,
cmd_target_free,
cmd_target_print
};
struct cmd_choose_session_data {
@@ -49,48 +50,41 @@ struct cmd_choose_session_data {
int
cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct cmd_choose_session_data *cdata;
struct winlink *wl;
struct session *s;
struct session_group *sg;
u_int idx, sgidx, cur;
char tmp[64];
u_int i, idx, cur;
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)
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (0);
cur = idx = 0;
RB_FOREACH(s, sessions, &sessions) {
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
if (s == ctx->curclient->session)
cur = idx;
idx++;
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,
window_choose_add(wl->window->active, i,
"%s: %u windows [%ux%u]%s", s->name,
winlink_count(&s->windows), s->sx, s->sy,
tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)");
s->flags & SESSION_UNATTACHED ? "" : " (attached)");
}
cdata = xmalloc(sizeof *cdata);
if (args->argc != 0)
cdata->template = xstrdup(args->argv[0]);
if (data->arg != NULL)
cdata->template = xstrdup(data->arg);
else
cdata->template = xstrdup("switch-client -t '%%'");
cdata->client = ctx->curclient;
@@ -116,7 +110,9 @@ cmd_choose_session_callback(void *data, int idx)
if (cdata->client->flags & CLIENT_DEAD)
return;
s = session_find_by_index(idx);
if ((u_int) idx > ARRAY_LENGTH(&sessions) - 1)
return;
s = ARRAY_ITEM(&sessions, idx);
if (s == NULL)
return;
template = cmd_template_replace(cdata->template, s->name, 1);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-choose-window.c,v 1.17 2009-09-07 23:59:19 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -33,12 +33,13 @@ 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
CMD_ARG01, 0,
cmd_target_init,
cmd_target_parse,
cmd_choose_window_exec,
cmd_target_free,
cmd_target_print
};
struct cmd_choose_window_data {
@@ -50,13 +51,13 @@ struct cmd_choose_window_data {
int
cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct cmd_choose_window_data *cdata;
struct session *s;
struct winlink *wl, *wm;
struct window *w;
u_int idx, cur;
char *flags, *title;
char flag, *title;
const char *left, *right;
if (ctx->curclient == NULL) {
@@ -65,7 +66,7 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
}
s = ctx->curclient->session;
if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
@@ -79,7 +80,18 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
cur = idx;
idx++;
flags = window_printable_flags(s, wm);
flag = ' ';
if (session_alert_has(s, wm, WINDOW_ACTIVITY))
flag = '#';
else if (session_alert_has(s, wm, WINDOW_BELL))
flag = '!';
else if (session_alert_has(s, wm, WINDOW_CONTENT))
flag = '+';
else if (wm == s->curw)
flag = '*';
else if (wm == SLIST_FIRST(&s->lastw))
flag = '-';
title = w->active->screen->title;
if (wm == wl)
title = w->active->base.title;
@@ -89,17 +101,14 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
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" : "",
wm->idx, "%3d: %s%c [%ux%u] (%u panes)%s%s%s",
wm->idx, w->name, flag, w->sx, w->sy, window_count_panes(w),
left, title, right);
xfree(flags);
}
cdata = xmalloc(sizeof *cdata);
if (args->argc != 0)
cdata->template = xstrdup(args->argv[0]);
if (data->arg != NULL)
cdata->template = xstrdup(data->arg);
else
cdata->template = xstrdup("select-window -t '%%'");
cdata->session = s;
@@ -107,29 +116,30 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
cdata->client = ctx->curclient;
cdata->client->references++;
window_choose_ready(wl->window->active,
window_choose_ready(wl->window->active,
cur, cmd_choose_window_callback, cmd_choose_window_free, cdata);
return (0);
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;
if (cdata->session->flags & SESSION_DEAD)
return;
if (cdata->client->session != cdata->session)
return;
xasprintf(&target, "%s:%d", s->name, idx);
xasprintf(&target, "%s:%d", cdata->session->name, idx);
template = cmd_template_replace(cdata->template, target, 1);
xfree(target);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-clear-history.c,v 1.7 2009-07-30 21:04:40 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,22 +28,23 @@ int cmd_clear_history_exec(struct cmd *, struct cmd_ctx *);
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
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_clear_history_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_clear_history_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct window_pane *wp;
struct grid *gd;
if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
return (-1);
gd = wp->base.grid;

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-clock-mode.c,v 1.6 2009-08-20 11:37:46 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,21 +28,22 @@ int cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_clock_mode_entry = {
"clock-mode", NULL,
"t:", 0, 0,
CMD_TARGET_PANE_USAGE,
0,
NULL,
NULL,
cmd_clock_mode_exec
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_clock_mode_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_clock_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct window_pane *wp;
if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
return (-1);
window_pane_set_mode(wp, &window_clock_mode);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-command-prompt.c,v 1.25 2009-08-25 13:53:39 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -20,7 +20,6 @@
#include <ctype.h>
#include <string.h>
#include <time.h>
#include "tmux.h"
@@ -28,27 +27,34 @@
* Prompt for command in client.
*/
void cmd_command_prompt_key_binding(struct cmd *, int);
int cmd_command_prompt_check(struct args *);
int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *);
void cmd_command_prompt_init(struct cmd *, int);
int cmd_command_prompt_parse(struct cmd *, int, char **, char **);
int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *);
void cmd_command_prompt_free(struct cmd *);
size_t cmd_command_prompt_print(struct cmd *, char *, size_t);
int cmd_command_prompt_callback(void *, const char *);
void cmd_command_prompt_free(void *);
int cmd_command_prompt_callback(void *, const char *);
void cmd_command_prompt_cfree(void *);
const struct cmd_entry cmd_command_prompt_entry = {
"command-prompt", NULL,
"I:p:t:", 0, 1,
"[-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " [template]",
0,
cmd_command_prompt_key_binding,
NULL,
cmd_command_prompt_exec
CMD_TARGET_CLIENT_USAGE " [-p prompts] [template]",
0, 0,
cmd_command_prompt_init,
cmd_command_prompt_parse,
cmd_command_prompt_exec,
cmd_command_prompt_free,
cmd_command_prompt_print
};
struct cmd_command_prompt_data {
char *prompts;
char *target;
char *template;
};
struct cmd_command_prompt_cdata {
struct client *c;
char *inputs;
char *next_input;
char *next_prompt;
char *prompts;
char *template;
@@ -56,44 +62,78 @@ struct cmd_command_prompt_cdata {
};
void
cmd_command_prompt_key_binding(struct cmd *self, int key)
cmd_command_prompt_init(struct cmd *self, int key)
{
struct cmd_command_prompt_data *data;
self->data = data = xmalloc(sizeof *data);
data->prompts = NULL;
data->target = NULL;
data->template = NULL;
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");
data->template = xstrdup("rename-window '%%'");
break;
case '.':
self->args = args_create(1, "move-window -t '%%'");
data->template = xstrdup("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);
data->template = xstrdup("find-window '%%'");
break;
}
}
int
cmd_command_prompt_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_command_prompt_data *data;
int opt;
self->entry->init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "p:t:")) != -1) {
switch (opt) {
case 'p':
if (data->prompts == NULL)
data->prompts = xstrdup(optarg);
break;
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (argc != 0 && argc != 1)
goto usage;
if (argc == 1)
data->template = xstrdup(argv[0]);
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
int
cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
const char *inputs, *prompts;
struct cmd_command_prompt_data *data = self->data;
struct cmd_command_prompt_cdata *cdata;
struct client *c;
char *prompt, *ptr, *input = NULL;
char *prompt, *ptr;
size_t n;
if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
if (c->prompt_string != NULL)
@@ -102,47 +142,67 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
cdata = xmalloc(sizeof *cdata);
cdata->c = c;
cdata->idx = 1;
cdata->inputs = NULL;
cdata->next_input = NULL;
cdata->next_prompt = NULL;
cdata->prompts = NULL;
cdata->template = NULL;
if (args->argc != 0)
cdata->template = xstrdup(args->argv[0]);
if (data->template != NULL)
cdata->template = xstrdup(data->template);
else
cdata->template = xstrdup("%1");
if ((prompts = args_get(args, 'p')) != NULL)
cdata->prompts = xstrdup(prompts);
else if (args->argc != 0) {
n = strcspn(cdata->template, " ,");
xasprintf(&cdata->prompts, "(%.*s) ", (int) n, cdata->template);
if (data->prompts != NULL)
cdata->prompts = xstrdup(data->prompts);
else if (data->template != NULL) {
n = strcspn(data->template, " ,");
xasprintf(&cdata->prompts, "(%.*s) ", (int) n, data->template);
} else
cdata->prompts = xstrdup(":");
/* Get first prompt. */
cdata->next_prompt = cdata->prompts;
ptr = strsep(&cdata->next_prompt, ",");
if (prompts == NULL)
if (data->prompts == NULL)
prompt = xstrdup(ptr);
else
xasprintf(&prompt, "%s ", ptr);
/* Get initial prompt input. */
if ((inputs = args_get(args, 'I')) != NULL) {
cdata->inputs = xstrdup(inputs);
cdata->next_input = cdata->inputs;
input = strsep(&cdata->next_input, ",");
}
status_prompt_set(c, prompt, input, cmd_command_prompt_callback,
cmd_command_prompt_free, cdata, 0);
status_prompt_set(c, prompt, cmd_command_prompt_callback,
cmd_command_prompt_cfree, cdata, 0);
xfree(prompt);
return (0);
}
void
cmd_command_prompt_free(struct cmd *self)
{
struct cmd_command_prompt_data *data = self->data;
if (data->prompts != NULL)
xfree(data->prompts);
if (data->target != NULL)
xfree(data->target);
if (data->template != NULL)
xfree(data->template);
xfree(data);
}
size_t
cmd_command_prompt_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_command_prompt_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->prompts != NULL)
off += cmd_prarg(buf + off, len - off, " -p ", data->prompts);
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
if (off < len && data->template != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->template);
return (off);
}
int
cmd_command_prompt_callback(void *data, const char *s)
{
@@ -150,31 +210,24 @@ cmd_command_prompt_callback(void *data, const char *s)
struct client *c = cdata->c;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *cause, *new_template, *prompt, *ptr;
char *input = NULL;
char *cause, *newtempl, *prompt, *ptr;
if (s == NULL)
return (0);
new_template = cmd_template_replace(cdata->template, s, cdata->idx);
newtempl = cmd_template_replace(cdata->template, s, cdata->idx);
xfree(cdata->template);
cdata->template = new_template;
cdata->template = newtempl;
/*
* Check if there are more prompts; if so, get its respective input
* and update the prompt data.
*/
if ((ptr = strsep(&cdata->next_prompt, ",")) != NULL) {
xasprintf(&prompt, "%s ", ptr);
input = strsep(&cdata->next_input, ",");
status_prompt_update(c, prompt, input);
status_prompt_update(c, prompt);
xfree(prompt);
cdata->idx++;
return (1);
}
if (cmd_string_parse(new_template, &cmdlist, &cause) != 0) {
if (cmd_string_parse(newtempl, &cmdlist, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(c, "%s", cause);
@@ -201,12 +254,10 @@ cmd_command_prompt_callback(void *data, const char *s)
}
void
cmd_command_prompt_free(void *data)
cmd_command_prompt_cfree(void *data)
{
struct cmd_command_prompt_cdata *cdata = data;
if (cdata->inputs != NULL)
xfree(cdata->inputs);
if (cdata->prompts != NULL)
xfree(cdata->prompts);
if (cdata->template != NULL)

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-confirm-before.c,v 1.11 2009-08-24 16:24:18 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -25,20 +25,21 @@
* Asks for confirmation before executing a command.
*/
void cmd_confirm_before_key_binding(struct cmd *, int);
int cmd_confirm_before_exec(struct cmd *, struct cmd_ctx *);
void cmd_confirm_before_init(struct cmd *, int);
int cmd_confirm_before_callback(void *, const char *);
void cmd_confirm_before_free(void *);
const struct cmd_entry cmd_confirm_before_entry = {
"confirm-before", "confirm",
"p:t:", 1, 1,
"[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
0,
cmd_confirm_before_key_binding,
NULL,
cmd_confirm_before_exec
CMD_TARGET_CLIENT_USAGE " command",
CMD_ARG1, 0,
cmd_confirm_before_init,
cmd_target_parse,
cmd_confirm_before_exec,
cmd_target_free,
cmd_target_print
};
struct cmd_confirm_before_data {
@@ -47,19 +48,19 @@ struct cmd_confirm_before_data {
};
void
cmd_confirm_before_key_binding(struct cmd *self, int key)
cmd_confirm_before_init(struct cmd *self, int key)
{
struct cmd_target_data *data;
cmd_target_init(self, key);
data = self->data;
switch (key) {
case '&':
self->args = args_create(1, "kill-window");
args_set(self->args, 'p', "kill-window #W? (y/n)");
data->arg = xstrdup("kill-window");
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);
data->arg = xstrdup("kill-pane");
break;
}
}
@@ -67,37 +68,33 @@ cmd_confirm_before_key_binding(struct cmd *self, int key)
int
cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct cmd_confirm_before_data *cdata;
struct client *c;
char *cmd, *copy, *new_prompt, *ptr;
const char *prompt;
char *buf, *cmd, *ptr;
if (ctx->curclient == NULL) {
ctx->error(ctx, "must be run interactively");
return (-1);
}
if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
if ((prompt = args_get(args, 'p')) != NULL)
xasprintf(&new_prompt, "%s ", prompt);
else {
ptr = copy = xstrdup(args->argv[0]);
cmd = strsep(&ptr, " \t");
xasprintf(&new_prompt, "Confirm '%s'? (y/n) ", cmd);
xfree(copy);
}
ptr = xstrdup(data->arg);
if ((cmd = strtok(ptr, " \t")) == NULL)
cmd = ptr;
xasprintf(&buf, "Confirm '%s'? (y/n) ", cmd);
xfree(ptr);
cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(args->argv[0]);
cdata->cmd = xstrdup(data->arg);
cdata->c = c;
status_prompt_set(cdata->c, new_prompt, NULL,
status_prompt_set(cdata->c, buf,
cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
PROMPT_SINGLE);
xfree(new_prompt);
xfree(buf);
return (1);
}

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

@@ -0,0 +1,204 @@
/* $Id: cmd-copy-buffer.c,v 1.4 2009-09-07 23:48:54 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Copies a session paste buffer to another session.
*/
int cmd_copy_buffer_parse(struct cmd *, int, char **, char **);
int cmd_copy_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_copy_buffer_free(struct cmd *);
void cmd_copy_buffer_init(struct cmd *, int);
size_t cmd_copy_buffer_print(struct cmd *, char *, size_t);
struct cmd_copy_buffer_data {
char *dst_session;
char *src_session;
int dst_idx;
int src_idx;
};
const struct cmd_entry cmd_copy_buffer_entry = {
"copy-buffer", "copyb",
"[-a src-index] [-b dst-index] [-s src-session] [-t dst-session]",
0, 0,
cmd_copy_buffer_init,
cmd_copy_buffer_parse,
cmd_copy_buffer_exec,
cmd_copy_buffer_free,
cmd_copy_buffer_print
};
void
cmd_copy_buffer_init(struct cmd *self, unused int arg)
{
struct cmd_copy_buffer_data *data;
self->data = data = xmalloc(sizeof *data);
data->dst_session = NULL;
data->src_session = NULL;
data->dst_idx = -1;
data->src_idx = -1;
}
int
cmd_copy_buffer_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_copy_buffer_data *data;
const char *errstr;
int n, opt;
self->entry->init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "a:b:s:t:")) != -1) {
switch (opt) {
case 'a':
if (data->src_idx == -1) {
n = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr != NULL) {
xasprintf(cause, "buffer %s", errstr);
goto error;
}
data->src_idx = n;
}
break;
case 'b':
if (data->dst_idx == -1) {
n = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr != NULL) {
xasprintf(cause, "buffer %s", errstr);
goto error;
}
data->dst_idx = n;
}
break;
case 's':
if (data->src_session == NULL)
data->src_session = xstrdup(optarg);
break;
case 't':
if (data->dst_session == NULL)
data->dst_session = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
error:
self->entry->free(self);
return (-1);
}
int
cmd_copy_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_copy_buffer_data *data = self->data;
struct paste_buffer *pb;
struct paste_stack *dst_ps, *src_ps;
u_char *pdata;
struct session *dst_session, *src_session;
u_int limit;
if ((dst_session = cmd_find_session(ctx, data->dst_session)) == NULL ||
(src_session = cmd_find_session(ctx, data->src_session)) == NULL)
return (-1);
dst_ps = &dst_session->buffers;
src_ps = &src_session->buffers;
if (data->src_idx == -1) {
if ((pb = paste_get_top(src_ps)) == NULL) {
ctx->error(ctx, "no buffers");
return (-1);
}
} else {
if ((pb = paste_get_index(src_ps, data->src_idx)) == NULL) {
ctx->error(ctx, "no buffer %d", data->src_idx);
return (-1);
}
}
limit = options_get_number(&dst_session->options, "buffer-limit");
pdata = xmalloc(pb->size);
memcpy(pdata, pb->data, pb->size);
if (data->dst_idx == -1)
paste_add(dst_ps, pdata, pb->size, limit);
else if (paste_replace(dst_ps, data->dst_idx, pdata, pb->size) != 0) {
ctx->error(ctx, "no buffer %d", data->dst_idx);
xfree(pdata);
return (-1);
}
return (0);
}
void
cmd_copy_buffer_free(struct cmd *self)
{
struct cmd_copy_buffer_data *data = self->data;
if (data->dst_session != NULL)
xfree(data->dst_session);
if (data->src_session != NULL)
xfree(data->src_session);
xfree(data);
}
size_t
cmd_copy_buffer_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_copy_buffer_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->src_idx != -1) {
off += xsnprintf(buf + off, len - off, " -a %d",
data->src_idx);
}
if (off < len && data->dst_idx != -1) {
off += xsnprintf(buf + off, len - off, " -b %d",
data->dst_idx);
}
if (off < len && data->src_session != NULL) {
off += cmd_prarg(buf + off, len - off, " -s ",
data->src_session);
}
if (off < len && data->dst_session != NULL) {
off += cmd_prarg(buf + off, len - off, " -t ",
data->dst_session);
}
return (off);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-copy-mode.c,v 1.23 2009-08-20 11:37:46 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,40 +24,30 @@
* Enter copy mode.
*/
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 = {
"copy-mode", NULL,
"t:u", 0, 0,
"[-u] " CMD_TARGET_PANE_USAGE,
0,
cmd_copy_mode_key_binding,
NULL,
cmd_copy_mode_exec
0, CMD_CHFLAG('u'),
cmd_target_init,
cmd_target_parse,
cmd_copy_mode_exec,
cmd_target_free,
NULL
};
void
cmd_copy_mode_key_binding(struct cmd *self, int key)
{
self->args = args_create(0);
if (key == KEYC_PPAGE)
args_set(self->args, 'u', NULL);
}
int
cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct window_pane *wp;
if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
return (-1);
if (window_pane_set_mode(wp, &window_copy_mode) != 0)
return (0);
window_copy_init_from_pane(wp);
if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
window_pane_set_mode(wp, &window_copy_mode);
if (wp->mode == &window_copy_mode && data->chflags & CMD_CHFLAG('u'))
window_copy_pageup(wp);
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-delete-buffer.c,v 1.7 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,35 +30,28 @@ 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
CMD_BUFFER_SESSION_USAGE,
0, 0,
cmd_buffer_init,
cmd_buffer_parse,
cmd_delete_buffer_exec,
cmd_buffer_free,
cmd_buffer_print
};
int
cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
char *cause;
int buffer;
struct cmd_buffer_data *data = self->data;
struct session *s;
if (!args_has(args, 'b')) {
paste_free_top(&global_buffers);
return (0);
}
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
ctx->error(ctx, "buffer %s", cause);
xfree(cause);
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
}
if (paste_free_index(&global_buffers, buffer) != 0) {
ctx->error(ctx, "no buffer %d", buffer);
if (data->buffer == -1)
paste_free_top(&s->buffers);
else if (paste_free_index(&s->buffers, data->buffer) != 0) {
ctx->error(ctx, "no buffer %d", data->buffer);
return (-1);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-detach-client.c,v 1.9 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,45 +28,25 @@ int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_detach_client_entry = {
"detach-client", "detach",
"s:t:P", 0, 0,
"[-P] [-s target-session] " CMD_TARGET_CLIENT_USAGE,
CMD_READONLY,
NULL,
NULL,
cmd_detach_client_exec
CMD_TARGET_CLIENT_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_detach_client_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c;
struct session *s;
enum msgtype msgtype;
u_int i;
struct cmd_target_data *data = self->data;
struct client *c;
if (args_has(args, 'P'))
msgtype = MSG_DETACHKILL;
else
msgtype = MSG_DETACH;
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
if (args_has(args, 's')) {
s = cmd_find_session(ctx, args_get(args, 's'), 0);
if (s == NULL)
return (-1);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c != NULL && c->session == s)
server_write_client(c, msgtype, NULL, 0);
}
} else {
c = cmd_find_client(ctx, args_get(args, 't'));
if (c == NULL)
return (-1);
server_write_client(c, msgtype, NULL, 0);
}
server_write_client(c, MSG_DETACH, NULL, 0);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-display-message.c,v 1.2 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -30,48 +30,33 @@ int cmd_display_message_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_display_message_entry = {
"display-message", "display",
"c:pt:", 0, 1,
"[-p] [-c target-client] [-t target-pane] [message]",
0,
NULL,
NULL,
cmd_display_message_exec
CMD_TARGET_CLIENT_USAGE " [message]",
CMD_ARG01, 0,
cmd_target_init,
cmd_target_parse,
cmd_display_message_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct client *c;
struct session *s;
struct winlink *wl;
struct window_pane *wp;
const char *template;
char *msg;
if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL)
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
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;
}
if (args->argc == 0)
if (data->arg == NULL)
template = "[#S] #I:#W, current pane #P - (%H:%M %d-%b-%y)";
else
template = args->argv[0];
template = data->arg;
msg = status_replace(c, s, wl, wp, template, time(NULL), 0);
if (args_has(self->args, 'p'))
ctx->print(ctx, "%s", msg);
else
status_message_set(c, "%s", msg);
msg = status_replace(c->session, template, time(NULL));
status_message_set(c, "%s", msg);
xfree(msg);
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-display-panes.c,v 1.1 2009-08-31 22:30:15 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,21 +28,22 @@ int cmd_display_panes_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_display_panes_entry = {
"display-panes", "displayp",
"t:", 0, 0,
CMD_TARGET_CLIENT_USAGE,
0,
NULL,
NULL,
cmd_display_panes_exec
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_display_panes_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_display_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c;
struct cmd_target_data *data = self->data;
struct client *c;
if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
server_set_identify(c);

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

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

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-find-window.c,v 1.13 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,26 +30,26 @@
int cmd_find_window_exec(struct cmd *, struct cmd_ctx *);
void cmd_find_window_callback(void *, int);
void cmd_find_window_free(void *);
const struct cmd_entry cmd_find_window_entry = {
"find-window", "findw",
"t:", 1, 1,
CMD_TARGET_WINDOW_USAGE " match-string",
0,
NULL,
NULL,
cmd_find_window_exec
CMD_ARG1, 0,
cmd_target_init,
cmd_target_parse,
cmd_find_window_exec,
cmd_target_free,
cmd_target_print
};
struct cmd_find_window_data {
struct session *session;
u_int session;
};
int
cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct cmd_find_window_data *cdata;
struct session *s;
struct winlink *wl, *wm;
@@ -57,7 +57,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
struct window_pane *wp;
ARRAY_DECL(, u_int) list_idx;
ARRAY_DECL(, char *) list_ctx;
char *str, *sres, *sctx, *searchstr;
char *sres, *sctx, *searchstr;
u_int i, line;
if (ctx->curclient == NULL) {
@@ -66,15 +66,13 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
}
s = ctx->curclient->session;
if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
str = args->argv[0];
ARRAY_INIT(&list_idx);
ARRAY_INIT(&list_ctx);
xasprintf(&searchstr, "*%s*", str);
xasprintf(&searchstr, "*%s*", data->arg);
RB_FOREACH(wm, winlinks, &s->windows) {
i = 0;
TAILQ_FOREACH(wp, &wm->window->panes, entry) {
@@ -83,7 +81,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
if (fnmatch(searchstr, wm->window->name, 0) == 0)
sctx = xstrdup("");
else {
sres = window_pane_search(wp, str, &line);
sres = window_pane_search(wp, data->arg, &line);
if (sres == NULL &&
fnmatch(searchstr, wp->base.title, 0) != 0)
continue;
@@ -107,7 +105,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
xfree(searchstr);
if (ARRAY_LENGTH(&list_idx) == 0) {
ctx->error(ctx, "no windows matching: %s", str);
ctx->error(ctx, "no windows matching: %s", data->arg);
ARRAY_FREE(&list_idx);
ARRAY_FREE(&list_ctx);
return (-1);
@@ -136,11 +134,11 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
}
cdata = xmalloc(sizeof *cdata);
cdata->session = s;
cdata->session->references++;
if (session_index(s, &cdata->session) != 0)
fatalx("session not found");
window_choose_ready(wl->window->active,
0, cmd_find_window_callback, cmd_find_window_free, cdata);
window_choose_ready(
wl->window->active, 0, cmd_find_window_callback, xfree, cdata);
out:
ARRAY_FREE(&list_idx);
@@ -153,24 +151,12 @@ void
cmd_find_window_callback(void *data, int idx)
{
struct cmd_find_window_data *cdata = data;
struct session *s = cdata->session;
struct session *s;
if (idx == -1)
return;
if (!session_alive(s))
return;
if (session_select(s, idx) == 0) {
server_redraw_session(s);
if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) {
s = ARRAY_ITEM(&sessions, cdata->session);
if (s != NULL && session_select(s, idx) == 0)
server_redraw_session(s);
recalculate_sizes();
}
}
void
cmd_find_window_free(void *data)
{
struct cmd_find_window_data *cdata = data;
cdata->session->references--;
xfree(cdata);
}

418
cmd-generic.c Normal file
View File

@@ -0,0 +1,418 @@
/* $Id: cmd-generic.c,v 1.34 2009-08-26 22:13:52 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
int cmd_getopt(int, char **, const char *, uint64_t);
int cmd_flags(int, uint64_t, uint64_t *);
size_t cmd_print_flags(char *, size_t, size_t, uint64_t);
int cmd_fill_argument(int, char **, char **, int, char **);
size_t
cmd_prarg(char *buf, size_t len, const char *prefix, char *arg)
{
if (strchr(arg, ' ') != NULL)
return (xsnprintf(buf, len, "%s\"%s\"", prefix, arg));
return (xsnprintf(buf, len, "%s%s", prefix, arg));
}
/* Prepend flags from chflags onto flagstr and call getopt. */
int
cmd_getopt(int argc, char **argv, const char *flagstr, uint64_t chflags)
{
u_char ch;
char buf[128];
size_t len, off;
*buf = '\0';
len = sizeof buf;
off = 0;
for (ch = 0; ch < 26; ch++) {
if (chflags & CMD_CHFLAG('a' + ch))
off += xsnprintf(buf + off, len - off, "%c", 'a' + ch);
if (chflags & CMD_CHFLAG('A' + ch))
off += xsnprintf(buf + off, len - off, "%c", 'A' + ch);
}
strlcat(buf, flagstr, sizeof buf);
return (getopt(argc, argv, buf));
}
/*
* If this option is expected (in ichflags), set it in ochflags, otherwise
* return -1.
*/
int
cmd_flags(int opt, uint64_t ichflags, uint64_t *ochflags)
{
u_char ch;
for (ch = 0; ch < 26; ch++) {
if (opt == 'a' + ch && ichflags & CMD_CHFLAG(opt)) {
(*ochflags) |= CMD_CHFLAG(opt);
return (0);
}
if (opt == 'A' + ch && ichflags & CMD_CHFLAG(opt)) {
(*ochflags) |= CMD_CHFLAG(opt);
return (0);
}
}
return (-1);
}
/* Print the flags supported in chflags. */
size_t
cmd_print_flags(char *buf, size_t len, size_t off, uint64_t chflags)
{
u_char ch;
size_t boff = off;
if (chflags == 0)
return (0);
off += xsnprintf(buf + off, len - off, " -");
for (ch = 0; ch < 26; ch++) {
if (chflags & CMD_CHFLAG('a' + ch))
off += xsnprintf(buf + off, len - off, "%c", 'a' + ch);
if (chflags & CMD_CHFLAG('A' + ch))
off += xsnprintf(buf + off, len - off, "%c", 'A' + ch);
}
return (off - boff);
}
int
cmd_fill_argument(int flags, char **arg, char **arg2, int argc, char **argv)
{
*arg = NULL;
*arg2 = NULL;
if (flags & CMD_ARG1) {
if (argc != 1)
return (-1);
*arg = xstrdup(argv[0]);
return (0);
}
if (flags & CMD_ARG01) {
if (argc != 0 && argc != 1)
return (-1);
if (argc == 1)
*arg = xstrdup(argv[0]);
return (0);
}
if (flags & CMD_ARG2) {
if (argc != 2)
return (-1);
*arg = xstrdup(argv[0]);
*arg2 = xstrdup(argv[1]);
return (0);
}
if (flags & CMD_ARG12) {
if (argc != 1 && argc != 2)
return (-1);
*arg = xstrdup(argv[0]);
if (argc == 2)
*arg2 = xstrdup(argv[1]);
return (0);
}
if (argc != 0)
return (-1);
return (0);
}
void
cmd_target_init(struct cmd *self, unused int key)
{
struct cmd_target_data *data;
self->data = data = xmalloc(sizeof *data);
data->chflags = 0;
data->target = NULL;
data->arg = NULL;
data->arg2 = NULL;
}
int
cmd_target_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_target_data *data;
const struct cmd_entry *entry = self->entry;
int opt;
/* Don't use the entry version since it may be dependent on key. */
cmd_target_init(self, 0);
data = self->data;
while ((opt = cmd_getopt(argc, argv, "t:", entry->chflags)) != -1) {
if (cmd_flags(opt, entry->chflags, &data->chflags) == 0)
continue;
switch (opt) {
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (cmd_fill_argument(
self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0)
goto usage;
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
void
cmd_target_free(struct cmd *self)
{
struct cmd_target_data *data = self->data;
if (data->target != NULL)
xfree(data->target);
if (data->arg != NULL)
xfree(data->arg);
if (data->arg2 != NULL)
xfree(data->arg2);
xfree(data);
}
size_t
cmd_target_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_target_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
off += cmd_print_flags(buf, len, off, data->chflags);
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
if (off < len && data->arg != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->arg);
if (off < len && data->arg2 != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->arg2);
return (off);
}
void
cmd_srcdst_init(struct cmd *self, unused int key)
{
struct cmd_srcdst_data *data;
self->data = data = xmalloc(sizeof *data);
data->chflags = 0;
data->src = NULL;
data->dst = NULL;
data->arg = NULL;
data->arg2 = NULL;
}
int
cmd_srcdst_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_srcdst_data *data;
const struct cmd_entry *entry = self->entry;
int opt;
cmd_srcdst_init(self, 0);
data = self->data;
while ((opt = cmd_getopt(argc, argv, "s:t:", entry->chflags)) != -1) {
if (cmd_flags(opt, entry->chflags, &data->chflags) == 0)
continue;
switch (opt) {
case 's':
if (data->src == NULL)
data->src = xstrdup(optarg);
break;
case 't':
if (data->dst == NULL)
data->dst = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (cmd_fill_argument(
self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0)
goto usage;
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
void
cmd_srcdst_free(struct cmd *self)
{
struct cmd_srcdst_data *data = self->data;
if (data->src != NULL)
xfree(data->src);
if (data->dst != NULL)
xfree(data->dst);
if (data->arg != NULL)
xfree(data->arg);
if (data->arg2 != NULL)
xfree(data->arg2);
xfree(data);
}
size_t
cmd_srcdst_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_srcdst_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
off += cmd_print_flags(buf, len, off, data->chflags);
if (off < len && data->src != NULL)
off += xsnprintf(buf + off, len - off, " -s %s", data->src);
if (off < len && data->dst != NULL)
off += xsnprintf(buf + off, len - off, " -t %s", data->dst);
if (off < len && data->arg != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->arg);
if (off < len && data->arg2 != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->arg2);
return (off);
}
void
cmd_buffer_init(struct cmd *self, unused int key)
{
struct cmd_buffer_data *data;
self->data = data = xmalloc(sizeof *data);
data->chflags = 0;
data->target = NULL;
data->buffer = -1;
data->arg = NULL;
data->arg2 = NULL;
}
int
cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_buffer_data *data;
const struct cmd_entry *entry = self->entry;
int opt, n;
const char *errstr;
cmd_buffer_init(self, 0);
data = self->data;
while ((opt = cmd_getopt(argc, argv, "b:t:", entry->chflags)) != -1) {
if (cmd_flags(opt, entry->chflags, &data->chflags) == 0)
continue;
switch (opt) {
case 'b':
if (data->buffer == -1) {
n = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr != NULL) {
xasprintf(cause, "buffer %s", errstr);
goto error;
}
data->buffer = n;
}
break;
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (cmd_fill_argument(
self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0)
goto usage;
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
error:
self->entry->free(self);
return (-1);
}
void
cmd_buffer_free(struct cmd *self)
{
struct cmd_buffer_data *data = self->data;
if (data->target != NULL)
xfree(data->target);
if (data->arg != NULL)
xfree(data->arg);
if (data->arg2 != NULL)
xfree(data->arg2);
xfree(data);
}
size_t
cmd_buffer_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_buffer_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
off += cmd_print_flags(buf, len, off, data->chflags);
if (off < len && data->buffer != -1)
off += xsnprintf(buf + off, len - off, " -b %d", data->buffer);
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
if (off < len && data->arg != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->arg);
if (off < len && data->arg2 != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->arg2);
return (off);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-has-session.c,v 1.14 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,20 +28,21 @@ int cmd_has_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_has_session_entry = {
"has-session", "has",
"t:", 0, 0,
CMD_TARGET_SESSION_USAGE,
0,
NULL,
NULL,
cmd_has_session_exec
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_has_session_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_has_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
if (cmd_find_session(ctx, args_get(args, 't'), 0) == NULL)
if (cmd_find_session(ctx, data->target) == NULL)
return (-1);
return (0);

View File

@@ -1,8 +1,7 @@
/* $Id$ */
/* $Id: cmd-if-shell.c,v 1.4 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
* Copyright (c) 2009 Nicholas Marriott <nicm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,8 +17,9 @@
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -28,85 +28,124 @@
* Executes a tmux command if a shell command returns true.
*/
int cmd_if_shell_parse(struct cmd *, int, char **, char **);
int cmd_if_shell_exec(struct cmd *, struct cmd_ctx *);
void cmd_if_shell_free(struct cmd *);
void cmd_if_shell_init(struct cmd *, int);
size_t cmd_if_shell_print(struct cmd *, char *, size_t);
void cmd_if_shell_callback(struct job *);
void cmd_if_shell_free(void *);
struct cmd_if_shell_data {
char *cmd;
char *sh_cmd;
};
const struct cmd_entry cmd_if_shell_entry = {
"if-shell", "if",
"", 2, 2,
"shell-command command",
0,
NULL,
NULL,
cmd_if_shell_exec
0, 0,
cmd_if_shell_init,
cmd_if_shell_parse,
cmd_if_shell_exec,
cmd_if_shell_free,
cmd_if_shell_print
};
struct cmd_if_shell_data {
char *cmd;
struct cmd_ctx ctx;
};
void
cmd_if_shell_init(struct cmd *self, unused int arg)
{
struct cmd_if_shell_data *data;
self->data = data = xmalloc(sizeof *data);
data->cmd = NULL;
data->sh_cmd = NULL;
}
int
cmd_if_shell_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_if_shell_data *data;
int opt;
self->entry->init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "")) != -1) {
switch (opt) {
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (argc != 2)
goto usage;
data->sh_cmd = xstrdup(argv[0]);
data->cmd = xstrdup(argv[1]);
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
int
cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_if_shell_data *cdata;
const char *shellcmd = args->argv[0];
cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(args->argv[1]);
memcpy(&cdata->ctx, ctx, sizeof cdata->ctx);
if (ctx->cmdclient != NULL)
ctx->cmdclient->references++;
if (ctx->curclient != NULL)
ctx->curclient->references++;
job_run(shellcmd, cmd_if_shell_callback, cmd_if_shell_free, cdata);
return (1); /* don't let client exit */
}
void
cmd_if_shell_callback(struct job *job)
{
struct cmd_if_shell_data *cdata = job->data;
struct cmd_ctx *ctx = &cdata->ctx;
struct cmd_if_shell_data *data = self->data;
struct cmd_list *cmdlist;
char *cause;
int ret;
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
return;
if ((ret = system(data->sh_cmd)) < 0) {
ctx->error(ctx, "system error: %s", strerror(errno));
return (-1);
} else if (ret != 0)
return (0);
if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) {
if (cmd_string_parse(data->cmd, &cmdlist, &cause) != 0) {
if (cause != NULL) {
ctx->error(ctx, "%s", cause);
xfree(cause);
}
return;
return (-1);
}
if (cmd_list_exec(cmdlist, ctx) < 0) {
cmd_list_free(cmdlist);
return (-1);
}
cmd_list_exec(cmdlist, ctx);
cmd_list_free(cmdlist);
return (0);
}
void
cmd_if_shell_free(void *data)
cmd_if_shell_free(struct cmd *self)
{
struct cmd_if_shell_data *cdata = data;
struct cmd_ctx *ctx = &cdata->ctx;
struct msg_exit_data exitdata;
struct cmd_if_shell_data *data = self->data;
if (ctx->cmdclient != NULL) {
ctx->cmdclient->references--;
exitdata.retcode = ctx->cmdclient->retcode;
ctx->cmdclient->flags |= CLIENT_EXIT;
}
if (ctx->curclient != NULL)
ctx->curclient->references--;
xfree(cdata->cmd);
xfree(cdata);
if (data->cmd != NULL)
xfree(data->cmd);
if (data->sh_cmd != NULL)
xfree(data->sh_cmd);
xfree(data);
}
size_t
cmd_if_shell_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_if_shell_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->sh_cmd != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->sh_cmd);
if (off < len && data->cmd != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->cmd);
return (off);
}

View File

@@ -1,145 +0,0 @@
/* $Id$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include "tmux.h"
/*
* Join a pane into another (like split/swap/kill).
*/
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 = {
"join-pane", "joinp",
"dhvp:l:s:t:", 0, 0,
"[-dhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]",
0,
cmd_join_pane_key_binding,
NULL,
cmd_join_pane_exec
};
void
cmd_join_pane_key_binding(struct cmd *self, int key)
{
switch (key) {
case '%':
self->args = args_create(0);
args_set(self->args, 'h', NULL);
break;
default:
self->args = args_create(0);
break;
}
}
int
cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *dst_s;
struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w;
struct window_pane *src_wp, *dst_wp;
char *cause;
int size, percentage, dst_idx;
enum layout_type type;
struct layout_cell *lc;
dst_wl = cmd_find_pane(ctx, args_get(args, 't'), &dst_s, &dst_wp);
if (dst_wl == NULL)
return (-1);
dst_w = dst_wl->window;
dst_idx = dst_wl->idx;
src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp);
if (src_wl == NULL)
return (-1);
src_w = src_wl->window;
if (src_w == dst_w) {
ctx->error(ctx, "can't join a pane to its own window");
return (-1);
}
type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT;
size = -1;
if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
ctx->error(ctx, "size %s", cause);
xfree(cause);
return (-1);
}
} else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, 100, &cause);
if (cause != NULL) {
ctx->error(ctx, "percentage %s", cause);
xfree(cause);
return (-1);
}
if (type == LAYOUT_TOPBOTTOM)
size = (dst_wp->sy * percentage) / 100;
else
size = (dst_wp->sx * percentage) / 100;
}
if ((lc = layout_split_pane(dst_wp, type, size)) == NULL) {
ctx->error(ctx, "create pane failed: pane too small");
return (-1);
}
layout_close_pane(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);
if (window_count_panes(src_w) == 0)
server_kill_window(src_w);
src_wp->window = dst_w;
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
layout_assign_pane(lc, src_wp);
recalculate_sizes();
server_redraw_window(src_w);
server_redraw_window(dst_w);
if (!args_has(args, 'd')) {
window_set_active_pane(dst_w, src_wp);
session_select(dst_s, dst_idx);
server_redraw_session(dst_s);
} else
server_status_session(dst_s);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-kill-pane.c,v 1.12 2009-07-30 20:45:20 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,46 +30,33 @@ int cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_pane_entry = {
"kill-pane", "killp",
"at:", 0, 0,
"[-a] " CMD_TARGET_PANE_USAGE,
0,
NULL,
NULL,
cmd_kill_pane_exec
CMD_TARGET_PANE_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_kill_pane_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct window_pane *loopwp, *nextwp, *wp;
struct window_pane *wp;
if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL)
if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL)
return (-1);
if (window_count_panes(wl->window) == 1) {
/* Only one pane, kill the window. */
server_kill_window(wl->window);
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 {
layout_close_pane(wp);
window_remove_pane(wl->window, wp);
}
layout_close_pane(wp);
window_remove_pane(wl->window, wp);
server_redraw_window(wl->window);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-kill-server.c,v 1.8 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,19 +31,19 @@ int cmd_kill_server_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_server_entry = {
"kill-server", NULL,
"", 0, 0,
"",
0,
0, 0,
NULL,
NULL,
cmd_kill_server_exec
cmd_kill_server_exec,
NULL,
NULL
};
/* ARGSUSED */
int
cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
{
kill(getpid(), SIGTERM);
sigterm = 1;
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-kill-session.c,v 1.14 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,24 +31,35 @@ int cmd_kill_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_session_entry = {
"kill-session", NULL,
"t:", 0, 0,
CMD_TARGET_SESSION_USAGE,
0,
NULL,
NULL,
cmd_kill_session_exec
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_kill_session_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s;
struct cmd_target_data *data = self->data;
struct session *s;
struct client *c;
u_int i;
if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
server_destroy_session(s);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c->session == s) {
c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0);
}
}
recalculate_sizes();
session_destroy(s);
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-kill-window.c,v 1.19 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,25 +28,25 @@ int cmd_kill_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_window_entry = {
"kill-window", "killw",
"t:", 0, 0,
CMD_TARGET_WINDOW_USAGE,
0,
NULL,
NULL,
cmd_kill_window_exec
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_kill_window_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct winlink *wl;
struct cmd_target_data *data = self->data;
struct winlink *wl;
if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
server_kill_window(wl->window);
recalculate_sizes();
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $Id$ */
/* $Id: cmd-last-window.c,v 1.18 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2011 Nicholas Marriott <nicm@users.sourceforge.net>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,18 +18,41 @@
#include <sys/types.h>
#include <event.h>
#include "tmux.h"
char *
osdep_get_name(unused int fd, unused char *tty)
{
return (NULL);
}
/*
* Move to last window.
*/
struct event_base *
osdep_event_init(void)
int cmd_last_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_last_window_entry = {
"last-window", "last",
CMD_TARGET_SESSION_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_last_window_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_last_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
return (event_init());
struct cmd_target_data *data = self->data;
struct session *s;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (session_last(s) == 0)
server_redraw_session(s);
else {
ctx->error(ctx, "no last window");
return (-1);
}
recalculate_sizes();
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-link-window.c,v 1.32 2009-08-16 19:16:27 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,35 +30,68 @@ 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
0, CMD_CHFLAG('d')|CMD_CHFLAG('k'),
cmd_srcdst_init,
cmd_srcdst_parse,
cmd_link_window_exec,
cmd_srcdst_free,
cmd_srcdst_print
};
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;
struct cmd_srcdst_data *data = self->data;
struct session *dst;
struct winlink *wl_src, *wl_dst;
char *cause;
int idx;
if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL)
if ((wl_src = cmd_find_window(ctx, data->src, NULL)) == NULL)
return (-1);
if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2)
if ((idx = cmd_find_index(ctx, data->dst, &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);
wl_dst = NULL;
if (idx != -1)
wl_dst = winlink_find_by_index(&dst->windows, idx);
if (wl_dst != NULL) {
if (wl_dst->window == wl_src->window)
return (0);
if (data->chflags & CMD_CHFLAG('k')) {
/*
* Can't use session_detach as it will destroy session
* if this makes it empty.
*/
session_alert_cancel(dst, wl_dst);
winlink_stack_remove(&dst->lastw, wl_dst);
winlink_remove(&dst->windows, wl_dst);
/* Force select/redraw if current. */
if (wl_dst == dst->curw) {
data->chflags &= ~CMD_CHFLAG('d');
dst->curw = NULL;
}
}
}
if (idx == -1)
idx = -1 - options_get_number(&dst->options, "base-index");
wl_dst = session_attach(dst, wl_src->window, idx, &cause);
if (wl_dst == NULL) {
ctx->error(ctx, "create session failed: %s", cause);
xfree(cause);
return (-1);
}
if (data->chflags & CMD_CHFLAG('d'))
server_status_session(dst);
else {
session_select(dst, wl_dst->idx);
server_redraw_session(dst);
}
recalculate_sizes();
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-list-buffers.c,v 1.12 2009-09-07 23:48:54 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,28 +30,48 @@ int cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_buffers_entry = {
"list-buffers", "lsb",
"", 0, 0,
"",
0,
NULL,
NULL,
cmd_list_buffers_exec
CMD_TARGET_SESSION_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_list_buffers_exec,
cmd_target_free,
cmd_target_print
};
/* ARGSUSED */
int
cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx)
cmd_list_buffers_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct session *s;
struct paste_buffer *pb;
u_int idx;
char *tmp;
char tmp[51 * 4 + 1];
size_t size, len;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
idx = 0;
while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) {
tmp = paste_print(pb, 50);
ctx->print(ctx,
"%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp);
xfree(tmp);
while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) {
size = pb->size;
/* Translate the first 50 characters. */
len = size;
if (len > 50)
len = 50;
strvisx(tmp, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL);
/*
* If the first 50 characterswere encoded as a longer string,
* or there is definitely more data, add "...".
*/
if (size > 50 || strlen(tmp) > 50) {
tmp[50 - 3] = '\0';
strlcat(tmp, "...", sizeof tmp);
}
ctx->print(ctx, "%u: %zu bytes: \"%s\"", idx - 1, size, tmp);
}
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-list-clients.c,v 1.18 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,31 +31,22 @@ int cmd_list_clients_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_clients_entry = {
"list-clients", "lsc",
"t:", 0, 0,
CMD_TARGET_SESSION_USAGE,
0,
"",
0, 0,
NULL,
NULL,
cmd_list_clients_exec
cmd_list_clients_exec,
NULL,
NULL
};
/* ARGSUSED */
int
cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx)
cmd_list_clients_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c;
struct session *s;
u_int i;
const char *s_utf8;
if (args_has(args, 't')) {
s = cmd_find_session(ctx, args_get(args, 't'), 0);
if (s == NULL)
return (-1);
} else
s = NULL;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
@@ -65,9 +56,6 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx)
s_utf8 = " (utf8)";
else
s_utf8 = "";
if (s != NULL && s != c->session)
continue;
ctx->print(ctx, "%s: %s [%ux%u %s]%s", c->tty.path,
c->session->name, c->tty.sx, c->tty.sy,
c->tty.termname, s_utf8);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-list-commands.c,v 1.5 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,15 +28,15 @@ int cmd_list_commands_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_commands_entry = {
"list-commands", "lscm",
"", 0, 0,
"",
0,
0, 0,
NULL,
NULL,
cmd_list_commands_exec
cmd_list_commands_exec,
NULL,
NULL
};
/* ARGSUSED */
int
cmd_list_commands_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-list-keys.c,v 1.20 2009-07-28 23:19:06 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -32,43 +32,36 @@ int cmd_list_keys_table(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_keys_entry = {
"list-keys", "lsk",
"t:", 0, 0,
"[-t key-table]",
0,
NULL,
NULL,
cmd_list_keys_exec
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_list_keys_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct key_binding *bd;
const char *key;
char tmp[BUFSIZ], flags[8];
size_t used;
char tmp[BUFSIZ], keytmp[64];
int width, keywidth;
if (args_has(args, 't'))
if (data->target != NULL)
return (cmd_list_keys_table(self, ctx));
width = 0;
*flags = '\0';
SPLAY_FOREACH(bd, key_bindings, &key_bindings) {
key = key_string_lookup_key(bd->key & ~KEYC_PREFIX);
if (key == NULL)
continue;
keywidth = strlen(key);
if (!(bd->key & KEYC_PREFIX)) {
if (bd->can_repeat)
keywidth += 4;
else
keywidth += 3;
} else if (bd->can_repeat)
keywidth += 3;
keywidth = strlen(key) + 1;
if (!(bd->key & KEYC_PREFIX))
keywidth += 2;
if (keywidth > width)
width = keywidth;
}
@@ -78,21 +71,13 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
if (key == NULL)
continue;
*tmp = '\0';
cmd_list_print(bd->cmdlist, tmp, sizeof tmp);
if (!(bd->key & KEYC_PREFIX)) {
if (bd->can_repeat)
xsnprintf(flags, sizeof flags, "-rn ");
else
xsnprintf(flags, sizeof flags, "-n ");
} else if (bd->can_repeat)
xsnprintf(flags, sizeof flags, "-r ");
used = xsnprintf(tmp, sizeof tmp, "%s%*s ",
flags, (int) (width - strlen(flags)), key);
if (used >= sizeof tmp)
continue;
cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used);
ctx->print(ctx, "bind-key %s", tmp);
xsnprintf(keytmp, sizeof keytmp, "[%s]", key);
key = keytmp;
}
ctx->print(ctx, "%*s: %s", width, key, tmp);
}
return (0);
@@ -101,30 +86,24 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
int
cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
const char *tablename;
struct cmd_target_data *data = self->data;
const struct mode_key_table *mtab;
struct mode_key_binding *mbind;
const char *key, *cmdstr, *mode;
int width, keywidth, any_mode;
int width, keywidth;
tablename = args_get(args, 't');
if ((mtab = mode_key_findtable(tablename)) == NULL) {
ctx->error(ctx, "unknown key table: %s", tablename);
if ((mtab = mode_key_findtable(data->target)) == NULL) {
ctx->error(ctx, "unknown key table: %s", data->target);
return (-1);
}
width = 0;
any_mode = 0;
SPLAY_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);
keywidth = strlen(key) + 1;
if (keywidth > width)
width = keywidth;
}
@@ -136,13 +115,10 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx)
mode = "";
if (mbind->mode != 0)
mode = "c";
mode = "(command mode) ";
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);
}
if (cmdstr != NULL)
ctx->print(ctx, "%*s: %s%s", width, key, mode, cmdstr);
}
return (0);

View File

@@ -1,137 +0,0 @@
/* $Id$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <unistd.h>
#include "tmux.h"
/*
* List panes on given window.
*/
int cmd_list_panes_exec(struct cmd *, struct cmd_ctx *);
void cmd_list_panes_server(struct cmd_ctx *);
void cmd_list_panes_session(struct session *, struct cmd_ctx *, int);
void cmd_list_panes_window(
struct session *, struct winlink *, struct cmd_ctx *, int);
const struct cmd_entry cmd_list_panes_entry = {
"list-panes", "lsp",
"ast:", 0, 0,
"[-as] [-t target]",
0,
NULL,
NULL,
cmd_list_panes_exec
};
int
cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s;
struct winlink *wl;
if (args_has(args, 'a'))
cmd_list_panes_server(ctx);
else if (args_has(args, 's')) {
s = cmd_find_session(ctx, args_get(args, 't'), 0);
if (s == NULL)
return (-1);
cmd_list_panes_session(s, ctx, 1);
} else {
wl = cmd_find_window(ctx, args_get(args, 't'), &s);
if (wl == NULL)
return (-1);
cmd_list_panes_window(s, wl, ctx, 0);
}
return (0);
}
void
cmd_list_panes_server(struct cmd_ctx *ctx)
{
struct session *s;
RB_FOREACH(s, sessions, &sessions)
cmd_list_panes_session(s, ctx, 2);
}
void
cmd_list_panes_session(struct session *s, struct cmd_ctx *ctx, int type)
{
struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows)
cmd_list_panes_window(s, wl, ctx, type);
}
void
cmd_list_panes_window(
struct session *s, struct winlink *wl, struct cmd_ctx *ctx, int type)
{
struct window_pane *wp;
struct grid *gd;
struct grid_line *gl;
u_int i, n;
unsigned long long size;
n = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
gd = wp->base.grid;
size = 0;
for (i = 0; i < gd->hsize; i++) {
gl = &gd->linedata[i];
size += gl->cellsize * sizeof *gl->celldata;
size += gl->utf8size * sizeof *gl->utf8data;
}
size += gd->hsize * sizeof *gd->linedata;
switch (type) {
case 0:
ctx->print(ctx,
"%u: [%ux%u] [history %u/%u, %llu bytes] %%%u%s%s",
n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size,
wp->id, wp == wp->window->active ? " (active)" : "",
wp->fd == -1 ? " (dead)" : "");
break;
case 1:
ctx->print(ctx,
"%d.%u: [%ux%u] [history %u/%u, %llu bytes] "
"%%%u%s%s", wl->idx,
n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size,
wp->id, wp == wp->window->active ? " (active)" : "",
wp->fd == -1 ? " (dead)" : "");
break;
case 2:
ctx->print(ctx,
"%s:%d.%u: [%ux%u] [history %u/%u, %llu bytes] "
"%%%u%s%s", s->name, wl->idx,
n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size,
wp->id, wp == wp->window->active ? " (active)" : "",
wp->fd == -1 ? " (dead)" : "");
break;
}
n++;
}
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-list-sessions.c,v 1.21 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,41 +30,35 @@
int cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_sessions_entry = {
"list-sessions", "ls",
"", 0, 0,
"",
0,
"list-sessions", "ls", "",
0, 0,
NULL,
NULL,
cmd_list_sessions_exec
cmd_list_sessions_exec,
NULL,
NULL
};
/* ARGSUSED */
int
cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{
struct session *s;
struct session_group *sg;
char *tim, tmp[64];
u_int idx;
time_t t;
struct session *s;
char *tim;
u_int i;
time_t t;
RB_FOREACH(s, sessions, &sessions) {
sg = session_group_find(s);
if (sg == NULL)
*tmp = '\0';
else {
idx = session_group_index(sg);
xsnprintf(tmp, sizeof tmp, " (group %u)", idx);
}
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
t = s->creation_time.tv_sec;
t = s->tv.tv_sec;
tim = ctime(&t);
*strchr(tim, '\n') = '\0';
ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s%s",
ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s",
s->name, winlink_count(&s->windows), tim, s->sx, s->sy,
tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)");
s->flags & SESSION_UNATTACHED ? "" : " (attached)");
}
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-list-windows.c,v 1.40 2009-08-09 17:28:23 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,65 +28,60 @@
int cmd_list_windows_exec(struct cmd *, struct cmd_ctx *);
void cmd_list_windows_server(struct cmd_ctx *);
void cmd_list_windows_session(struct session *, struct cmd_ctx *, int);
const struct cmd_entry cmd_list_windows_entry = {
"list-windows", "lsw",
"at:", 0, 0,
"[-a] " CMD_TARGET_SESSION_USAGE,
0,
NULL,
NULL,
cmd_list_windows_exec
CMD_TARGET_SESSION_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_list_windows_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s;
struct cmd_target_data *data = self->data;
struct session *s;
struct winlink *wl;
struct window *w;
struct window_pane *wp;
struct grid *gd;
struct grid_line *gl;
u_int i;
unsigned long long size;
const char *name;
if (args_has(args, 'a'))
cmd_list_windows_server(ctx);
else {
s = cmd_find_session(ctx, args_get(args, 't'), 0);
if (s == NULL)
return (-1);
cmd_list_windows_session(s, ctx, 0);
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
RB_FOREACH(wl, winlinks, &s->windows) {
w = wl->window;
ctx->print(ctx,
"%3d: %s [%ux%u]", wl->idx, w->name, w->sx, w->sy);
TAILQ_FOREACH(wp, &w->panes, entry) {
gd = wp->base.grid;
size = 0;
for (i = 0; i < gd->hsize; i++) {
gl = &gd->linedata[i];
size += gl->cellsize * sizeof *gl->celldata;
size += gl->utf8size * sizeof *gl->utf8data;
}
size += gd->hsize * sizeof *gd->linedata;
name = NULL;
if (wp->fd != -1)
name = ttyname(wp->fd);
if (name == NULL)
name = "unknown";
ctx->print(ctx,
" %s [%ux%u] [history %u/%u, %llu bytes]",
name, wp->sx, wp->sy, gd->hsize, gd->hlimit, size);
}
}
return (0);
}
void
cmd_list_windows_server(struct cmd_ctx *ctx)
{
struct session *s;
RB_FOREACH(s, sessions, &sessions)
cmd_list_windows_session(s, ctx, 1);
}
void
cmd_list_windows_session(struct session *s, struct cmd_ctx *ctx, int type)
{
struct winlink *wl;
char *layout;
RB_FOREACH(wl, winlinks, &s->windows) {
layout = layout_dump(wl->window);
if (type) {
ctx->print(ctx, "%s:%d: %s [%ux%u] [layout %s]%s",
s->name, wl->idx, wl->window->name, wl->window->sx,
wl->window->sy, layout,
wl == s->curw ? " (active)" : "");
} else {
ctx->print(ctx, "%d: %s [%ux%u] [layout %s]%s",
wl->idx, wl->window->name, wl->window->sx,
wl->window->sy, layout,
wl == s->curw ? " (active)" : "");
}
xfree(layout);
}
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-list.c,v 1.6 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -29,52 +29,47 @@ cmd_list_parse(int argc, char **argv, char **cause)
struct cmd *cmd;
int i, lastsplit;
size_t arglen, new_argc;
char **copy_argv, **new_argv;
copy_argv = cmd_copy_argv(argc, argv);
char **new_argv;
cmdlist = xmalloc(sizeof *cmdlist);
cmdlist->references = 1;
TAILQ_INIT(&cmdlist->list);
TAILQ_INIT(cmdlist);
lastsplit = 0;
for (i = 0; i < argc; i++) {
arglen = strlen(copy_argv[i]);
if (arglen == 0 || copy_argv[i][arglen - 1] != ';')
arglen = strlen(argv[i]);
if (arglen == 0 || argv[i][arglen - 1] != ';')
continue;
copy_argv[i][arglen - 1] = '\0';
argv[i][arglen - 1] = '\0';
if (arglen > 1 && copy_argv[i][arglen - 2] == '\\') {
copy_argv[i][arglen - 2] = ';';
if (arglen > 1 && argv[i][arglen - 2] == '\\') {
argv[i][arglen - 2] = ';';
continue;
}
new_argc = i - lastsplit;
new_argv = copy_argv + lastsplit;
new_argv = argv + lastsplit;
if (arglen != 1)
new_argc++;
cmd = cmd_parse(new_argc, new_argv, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
TAILQ_INSERT_TAIL(cmdlist, cmd, qentry);
lastsplit = i + 1;
}
if (lastsplit != argc) {
cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit, cause);
cmd = cmd_parse(argc - lastsplit, argv + lastsplit, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
TAILQ_INSERT_TAIL(cmdlist, cmd, qentry);
}
cmd_free_argv(argc, copy_argv);
return (cmdlist);
bad:
cmd_list_free(cmdlist);
cmd_free_argv(argc, copy_argv);
return (NULL);
}
@@ -82,36 +77,13 @@ int
cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx)
{
struct cmd *cmd;
int n, retval;
int n;
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;
}
}
TAILQ_FOREACH(cmd, cmdlist, qentry) {
if ((n = cmd_exec(cmd, ctx)) != 0)
return (n);
}
return (retval);
return (0);
}
void
@@ -119,12 +91,9 @@ cmd_list_free(struct cmd_list *cmdlist)
{
struct cmd *cmd;
if (--cmdlist->references != 0)
return;
while (!TAILQ_EMPTY(&cmdlist->list)) {
cmd = TAILQ_FIRST(&cmdlist->list);
TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
while (!TAILQ_EMPTY(cmdlist)) {
cmd = TAILQ_FIRST(cmdlist);
TAILQ_REMOVE(cmdlist, cmd, qentry);
cmd_free(cmd);
}
xfree(cmdlist);
@@ -137,7 +106,7 @@ cmd_list_print(struct cmd_list *cmdlist, char *buf, size_t len)
size_t off;
off = 0;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
TAILQ_FOREACH(cmd, cmdlist, qentry) {
if (off >= len)
break;
off += cmd_print(cmd, buf + off, len - off);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-load-buffer.c,v 1.10 2009-09-07 23:48:54 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -17,9 +17,9 @@
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -31,144 +31,70 @@
*/
int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_load_buffer_callback(struct client *, void *);
const struct cmd_entry cmd_load_buffer_entry = {
"load-buffer", "loadb",
"b:", 1, 1,
CMD_BUFFER_USAGE " path",
0,
NULL,
NULL,
cmd_load_buffer_exec
CMD_BUFFER_SESSION_USAGE " path",
CMD_ARG1, 0,
cmd_buffer_init,
cmd_buffer_parse,
cmd_load_buffer_exec,
cmd_buffer_free,
cmd_buffer_print
};
int
cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c = ctx->cmdclient;
FILE *f;
const char *path;
char *pdata, *new_pdata, *cause;
size_t psize;
u_int limit;
int ch, buffer;
int *buffer_ptr;
struct cmd_buffer_data *data = self->data;
struct session *s;
struct stat sb;
FILE *f;
u_char *buf;
u_int limit;
if (!args_has(args, 'b'))
buffer = -1;
else {
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
ctx->error(ctx, "buffer %s", cause);
xfree(cause);
return (-1);
}
}
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
path = args->argv[0];
if (strcmp(path, "-") == 0) {
if (c == NULL) {
ctx->error(ctx, "%s: can't read from stdin", path);
return (-1);
}
if (c->flags & CLIENT_TERMINAL) {
ctx->error(ctx, "%s: stdin is a tty", path);
return (-1);
}
if (c->stdin_fd == -1) {
ctx->error(ctx, "%s: can't read from stdin", path);
return (-1);
}
buffer_ptr = xmalloc(sizeof *buffer_ptr);
*buffer_ptr = buffer;
c->stdin_data = buffer_ptr;
c->stdin_callback = cmd_load_buffer_callback;
c->references++;
bufferevent_enable(c->stdin_event, EV_READ);
return (1);
}
if ((f = fopen(path, "rb")) == NULL) {
ctx->error(ctx, "%s: %s", path, strerror(errno));
if (stat(data->arg, &sb) < 0) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1);
}
pdata = NULL;
psize = 0;
while ((ch = getc(f)) != EOF) {
/* Do not let the server die due to memory exhaustion. */
if ((new_pdata = realloc(pdata, psize + 2)) == NULL) {
ctx->error(ctx, "realloc error: %s", strerror(errno));
goto error;
}
pdata = new_pdata;
pdata[psize++] = ch;
if ((f = fopen(data->arg, "rb")) == NULL) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1);
}
if (ferror(f)) {
ctx->error(ctx, "%s: read error", path);
goto error;
/*
* We don't want to die due to memory exhaustion, hence xmalloc can't
* be used here.
*/
if ((buf = malloc(sb.st_size + 1)) == NULL) {
ctx->error(ctx, "malloc error: %s", strerror(errno));
fclose(f);
return (-1);
}
if (fread(buf, 1, sb.st_size, f) != (size_t) sb.st_size) {
ctx->error(ctx, "%s: fread error", data->arg);
xfree(buf);
fclose(f);
return (-1);
}
if (pdata != NULL)
pdata[psize] = '\0';
fclose(f);
limit = options_get_number(&global_options, "buffer-limit");
if (buffer == -1) {
paste_add(&global_buffers, pdata, psize, limit);
limit = options_get_number(&s->options, "buffer-limit");
if (data->buffer == -1) {
paste_add(&s->buffers, buf, sb.st_size, limit);
return (0);
}
if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) {
ctx->error(ctx, "no buffer %d", buffer);
if (paste_replace(&s->buffers, data->buffer, buf, sb.st_size) != 0) {
ctx->error(ctx, "no buffer %d", data->buffer);
xfree(buf);
return (-1);
}
return (0);
error:
if (pdata != NULL)
xfree(pdata);
if (f != NULL)
fclose(f);
return (-1);
}
void
cmd_load_buffer_callback(struct client *c, void *data)
{
int *buffer = data;
char *pdata;
size_t psize;
u_int limit;
/*
* 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;
}
bufferevent_read(c->stdin_event, pdata, psize);
pdata[psize] = '\0';
limit = options_get_number(&global_options, "buffer-limit");
if (*buffer == -1)
paste_add(&global_buffers, pdata, psize, limit);
else if (paste_replace(&global_buffers, *buffer, pdata, psize) != 0) {
/* No context so can't use server_client_msg_error. */
evbuffer_add_printf(
c->stderr_event->output, "no buffer %d\n", *buffer);
bufferevent_enable(c->stderr_event, EV_WRITE);
}
xfree(data);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-lock-server.c,v 1.6 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -25,61 +25,26 @@
#include "tmux.h"
/*
* Lock commands.
* Lock server.
*/
int cmd_lock_server_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_lock_server_entry = {
"lock-server", "lock",
"", 0, 0,
"",
0,
0, 0,
NULL,
NULL,
cmd_lock_server_exec,
NULL,
NULL,
cmd_lock_server_exec
};
const struct cmd_entry cmd_lock_session_entry = {
"lock-session", "locks",
"t:", 0, 0,
CMD_TARGET_SESSION_USAGE,
0,
NULL,
NULL,
cmd_lock_server_exec
};
const struct cmd_entry cmd_lock_client_entry = {
"lock-client", "lockc",
"t:", 0, 0,
CMD_TARGET_CLIENT_USAGE,
0,
NULL,
NULL,
cmd_lock_server_exec
};
/* ARGSUSED */
int
cmd_lock_server_exec(struct cmd *self, unused struct cmd_ctx *ctx)
cmd_lock_server_exec(unused 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)
server_lock();
else if (self->entry == &cmd_lock_session_entry) {
if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
return (-1);
server_lock_session(s);
} else {
if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
return (-1);
server_lock_client(c);
}
recalculate_sizes();
server_lock();
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-move-window.c,v 1.9 2009-08-16 19:16:27 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,36 +30,82 @@ int cmd_move_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_move_window_entry = {
"move-window", "movew",
"dks:t:", 0, 0,
"[-dk] " CMD_SRCDST_WINDOW_USAGE,
0,
NULL,
NULL,
cmd_move_window_exec
0, CMD_CHFLAG('d')|CMD_CHFLAG('k'),
cmd_srcdst_init,
cmd_srcdst_parse,
cmd_move_window_exec,
cmd_srcdst_free,
cmd_srcdst_print
};
int
cmd_move_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;
struct cmd_srcdst_data *data = self->data;
struct session *src, *dst;
struct winlink *wl_src, *wl_dst;
struct client *c;
u_int i;
int destroyed, idx;
char *cause;
if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL)
if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL)
return (-1);
if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2)
if ((idx = cmd_find_index(ctx, data->dst, &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 move window: %s", cause);
wl_dst = NULL;
if (idx != -1)
wl_dst = winlink_find_by_index(&dst->windows, idx);
if (wl_dst != NULL) {
if (wl_dst->window == wl_src->window)
return (0);
if (data->chflags & CMD_CHFLAG('k')) {
/*
* Can't use session_detach as it will destroy session
* if this makes it empty.
*/
session_alert_cancel(dst, wl_dst);
winlink_stack_remove(&dst->lastw, wl_dst);
winlink_remove(&dst->windows, wl_dst);
/* Force select/redraw if current. */
if (wl_dst == dst->curw) {
data->chflags &= ~CMD_CHFLAG('d');
dst->curw = NULL;
}
}
}
if (idx == -1)
idx = -1 - options_get_number(&dst->options, "base-index");
wl_dst = session_attach(dst, wl_src->window, idx, &cause);
if (wl_dst == NULL) {
ctx->error(ctx, "attach window failed: %s", cause);
xfree(cause);
return (-1);
}
server_unlink_window(src, wl);
destroyed = session_detach(src, wl_src);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != src)
continue;
if (destroyed) {
c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0);
} else
server_redraw_client(c);
}
if (data->chflags & CMD_CHFLAG('d'))
server_status_session(dst);
else {
session_select(dst, wl_dst->idx);
server_redraw_session(dst);
}
recalculate_sizes();
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-new-session.c,v 1.66 2009-09-16 12:36:27 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,8 +18,6 @@
#include <sys/types.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
@@ -30,63 +28,103 @@
* Create a new session and attach to the current terminal unless -d is given.
*/
int cmd_new_session_check(struct args *);
int cmd_new_session_parse(struct cmd *, int, char **, char **);
int cmd_new_session_exec(struct cmd *, struct cmd_ctx *);
void cmd_new_session_free(struct cmd *);
void cmd_new_session_init(struct cmd *, int);
size_t cmd_new_session_print(struct cmd *, char *, size_t);
struct cmd_new_session_data {
char *newname;
char *winname;
char *cmd;
int flag_detached;
};
const struct cmd_entry cmd_new_session_entry = {
"new-session", "new",
"dn:s:t:x:y:", 0, 1,
"[-d] [-n window-name] [-s session-name] [-t target-session] "
"[-x width] [-y height] [command]",
CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON,
NULL,
cmd_new_session_check,
cmd_new_session_exec
"[-d] [-n window-name] [-s session-name] [command]",
CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, 0,
cmd_new_session_init,
cmd_new_session_parse,
cmd_new_session_exec,
cmd_new_session_free,
cmd_new_session_print
};
int
cmd_new_session_check(struct args *args)
void
cmd_new_session_init(struct cmd *self, unused int arg)
{
if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n')))
return (-1);
struct cmd_new_session_data *data;
self->data = data = xmalloc(sizeof *data);
data->flag_detached = 0;
data->newname = NULL;
data->winname = NULL;
data->cmd = NULL;
}
int
cmd_new_session_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_new_session_data *data;
int opt;
self->entry->init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "ds:n:")) != -1) {
switch (opt) {
case 'd':
data->flag_detached = 1;
break;
case 's':
if (data->newname == NULL)
data->newname = xstrdup(optarg);
break;
case 'n':
if (data->winname == NULL)
data->winname = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (argc != 0 && argc != 1)
goto usage;
if (argc == 1)
data->cmd = xstrdup(argv[0]);
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
int
cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s, *old_s, *groupwith;
struct window *w;
struct window_pane *wp;
struct environ env;
struct termios tio, *tiop;
struct passwd *pw;
const char *newname, *target, *update, *cwd, *errstr;
char *overrides, *cmd, *cause;
int detached, idx;
u_int sx, sy, i;
struct cmd_new_session_data *data = self->data;
struct session *s;
struct window *w;
struct environ env;
struct termios tio, *tiop;
const char *update;
char *overrides, *cmd, *cwd, *cause;
int detached, idx;
u_int sx, sy;
newname = args_get(args, 's');
if (newname != NULL) {
if (!session_check_name(newname)) {
ctx->error(ctx, "bad session name: %s", newname);
return (-1);
}
if (session_find(newname) != NULL) {
ctx->error(ctx, "duplicate session: %s", newname);
return (-1);
}
if (data->newname != NULL && session_find(data->newname) != NULL) {
ctx->error(ctx, "duplicate session: %s", data->newname);
return (-1);
}
target = args_get(args, 't');
if (target != NULL) {
groupwith = cmd_find_session(ctx, target, 0);
if (groupwith == NULL)
return (-1);
} else
groupwith = NULL;
/*
* There are three cases:
*
@@ -106,7 +144,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
*/
/* Set -d if no client. */
detached = args_has(args, 'd');
detached = data->flag_detached;
if (ctx->cmdclient == NULL && ctx->curclient == NULL)
detached = 1;
@@ -132,8 +170,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
ctx->error(ctx, "not a terminal");
return (-1);
}
overrides =
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);
@@ -145,34 +183,13 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
/* 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 = "/";
}
else
cwd = options_get_string(&global_s_options, "default-path");
/* Find new session size. */
if (detached) {
sx = 80;
sy = 24;
if (args_has(args, 'x')) {
sx = strtonum(
args_get(args, 'x'), 1, USHRT_MAX, &errstr);
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);
}
}
} else if (ctx->cmdclient != NULL) {
sx = ctx->cmdclient->tty.sx;
sy = ctx->cmdclient->tty.sy;
@@ -188,10 +205,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
sy = 1;
/* Figure out the command for the new window. */
if (target != NULL)
cmd = NULL;
else if (args->argc != 0)
cmd = args->argv[0];
if (data->cmd != NULL)
cmd = data->cmd;
else
cmd = options_get_string(&global_s_options, "default-command");
@@ -203,7 +218,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
/* Create the new session. */
idx = -1 - options_get_number(&global_s_options, "base-index");
s = session_create(newname, cmd, cwd, &env, tiop, idx, sx, sy, &cause);
s = session_create(
data->newname, cmd, cwd, &env, tiop, idx, sx, sy, &cause);
if (s == NULL) {
ctx->error(ctx, "create session failed: %s", cause);
xfree(cause);
@@ -212,66 +228,64 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
environ_free(&env);
/* Set the initial window name if one given. */
if (cmd != NULL && args_has(args, 'n')) {
if (data->winname != NULL) {
w = s->curw->window;
xfree(w->name);
w->name = xstrdup(args_get(args, 'n'));
w->name = xstrdup(data->winname);
options_set_number(&w->options, "automatic-rename", 0);
}
/*
* If a target session is given, this is to be part of a session group,
* so add it to the group and synchronize.
*/
if (groupwith != NULL) {
session_group_add(groupwith, s);
session_group_synchronize_to(s);
session_select(s, RB_ROOT(&s->windows)->idx);
}
/*
* Set the client to the new session. If a command client exists, it is
* taking this session and needs to get MSG_READY and stay around.
*/
if (!detached) {
if (!detached) {
if (ctx->cmdclient != NULL) {
server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
old_s = ctx->cmdclient->session;
if (old_s != NULL)
ctx->cmdclient->last_session = old_s;
ctx->cmdclient->session = s;
session_update_activity(s);
ctx->cmdclient->session = s;
server_redraw_client(ctx->cmdclient);
} else {
old_s = ctx->curclient->session;
if (old_s != NULL)
ctx->curclient->last_session = old_s;
ctx->curclient->session = s;
session_update_activity(s);
ctx->curclient->session = s;
server_redraw_client(ctx->curclient);
}
}
recalculate_sizes();
server_update_socket();
/*
* If there are still configuration file errors to display, put the new
* session's current window into more mode and display them now.
*/
if (cfg_finished && !ARRAY_EMPTY(&cfg_causes)) {
wp = s->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp);
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
cause = ARRAY_ITEM(&cfg_causes, i);
window_copy_add(wp, "%s", cause);
xfree(cause);
}
ARRAY_FREE(&cfg_causes);
}
return (!detached); /* 1 means don't tell command client to exit */
}
void
cmd_new_session_free(struct cmd *self)
{
struct cmd_new_session_data *data = self->data;
if (data->newname != NULL)
xfree(data->newname);
if (data->winname != NULL)
xfree(data->winname);
if (data->cmd != NULL)
xfree(data->cmd);
xfree(data);
}
size_t
cmd_new_session_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_new_session_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->flag_detached)
off += xsnprintf(buf + off, len - off, " -d");
if (off < len && data->newname != NULL)
off += cmd_prarg(buf + off, len - off, " -s ", data->newname);
if (off < len && data->winname != NULL)
off += cmd_prarg(buf + off, len - off, " -n ", data->winname);
if (off < len && data->cmd != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->cmd);
return (off);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-new-window.c,v 1.37 2009-08-16 19:16:27 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,101 +26,181 @@
* Create a new window.
*/
int cmd_new_window_parse(struct cmd *, int, char **, char **);
int cmd_new_window_exec(struct cmd *, struct cmd_ctx *);
void cmd_new_window_free(struct cmd *);
void cmd_new_window_init(struct cmd *, int);
size_t cmd_new_window_print(struct cmd *, char *, size_t);
struct cmd_new_window_data {
char *target;
char *name;
char *cmd;
int flag_detached;
int flag_kill;
};
const struct cmd_entry cmd_new_window_entry = {
"new-window", "neww",
"adkn:Pt:", 0, 1,
"[-adk] [-n window-name] [-t target-window] [command]",
0,
NULL,
NULL,
cmd_new_window_exec
"[-dk] [-n window-name] [-t target-window] [command]",
0, 0,
cmd_new_window_init,
cmd_new_window_parse,
cmd_new_window_exec,
cmd_new_window_free,
cmd_new_window_print
};
void
cmd_new_window_init(struct cmd *self, unused int arg)
{
struct cmd_new_window_data *data;
self->data = data = xmalloc(sizeof *data);
data->target = NULL;
data->name = NULL;
data->cmd = NULL;
data->flag_detached = 0;
data->flag_kill = 0;
}
int
cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_new_window_data *data;
int opt;
self->entry->init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "dkt:n:")) != -1) {
switch (opt) {
case 'd':
data->flag_detached = 1;
break;
case 'k':
data->flag_kill = 1;
break;
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
case 'n':
if (data->name == NULL)
data->name = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (argc != 0 && argc != 1)
goto usage;
if (argc == 1)
data->cmd = xstrdup(argv[0]);
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
int
cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s;
struct winlink *wl;
char *cmd, *cwd, *cause;
int idx, last, detached;
struct cmd_new_window_data *data = self->data;
struct session *s;
struct winlink *wl;
char *cmd, *cwd, *cause;
int idx;
if (args_has(args, 'a')) {
wl = cmd_find_window(ctx, args_get(args, 't'), &s);
if (wl == NULL)
return (-1);
idx = wl->idx + 1;
if (data == NULL)
return (0);
/* Find the next free index. */
for (last = idx; last < INT_MAX; last++) {
if (winlink_find_by_index(&s->windows, last) == NULL)
break;
}
if (last == INT_MAX) {
ctx->error(ctx, "no free window indexes");
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 {
if ((idx = cmd_find_index(ctx, args_get(args, 't'), &s)) == -2)
return (-1);
}
detached = args_has(args, 'd');
if ((idx = cmd_find_index(ctx, data->target, &s)) == -2)
return (-1);
wl = NULL;
if (idx != -1)
wl = winlink_find_by_index(&s->windows, idx);
if (wl != NULL && args_has(args, 'k')) {
/*
* Can't use session_detach as it will destroy session if this
* makes it empty.
*/
wl->flags &= ~WINLINK_ALERTFLAGS;
winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl);
if (wl != NULL) {
if (data->flag_kill) {
/*
* Can't use session_detach as it will destroy session
* if this makes it empty.
*/
session_alert_cancel(s, wl);
winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl);
/* Force select/redraw if current. */
if (wl == s->curw) {
detached = 0;
s->curw = NULL;
/* Force select/redraw if current. */
if (wl == s->curw) {
data->flag_detached = 0;
s->curw = NULL;
}
}
}
if (args->argc == 0)
cmd = data->cmd;
if (cmd == NULL)
cmd = options_get_string(&s->options, "default-command");
if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL)
cwd = options_get_string(&s->options, "default-path");
else
cmd = args->argv[0];
cwd = options_get_string(&s->options, "default-path");
if (*cwd == '\0') {
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
cwd = ctx->cmdclient->cwd;
else
cwd = s->cwd;
}
cwd = ctx->cmdclient->cwd;
if (idx == -1)
idx = -1 - options_get_number(&s->options, "base-index");
wl = session_new(s, args_get(args, 'n'), cmd, cwd, idx, &cause);
wl = session_new(s, data->name, cmd, cwd, idx, &cause);
if (wl == NULL) {
ctx->error(ctx, "create window failed: %s", cause);
xfree(cause);
return (-1);
}
if (!detached) {
if (!data->flag_detached) {
session_select(s, wl->idx);
server_redraw_session_group(s);
server_redraw_session(s);
} else
server_status_session_group(s);
server_status_session(s);
if (args_has(args, 'P'))
ctx->print(ctx, "%s:%u", s->name, wl->idx);
return (0);
}
void
cmd_new_window_free(struct cmd *self)
{
struct cmd_new_window_data *data = self->data;
if (data->target != NULL)
xfree(data->target);
if (data->name != NULL)
xfree(data->name);
if (data->cmd != NULL)
xfree(data->cmd);
xfree(data);
}
size_t
cmd_new_window_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_new_window_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->flag_detached)
off += xsnprintf(buf + off, len - off, " -d");
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
if (off < len && data->name != NULL)
off += cmd_prarg(buf + off, len - off, " -n ", data->name);
if (off < len && data->cmd != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->cmd);
return (off);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-next-layout.c,v 1.5 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,47 +18,37 @@
#include <sys/types.h>
#include <string.h>
#include <time.h>
#include "tmux.h"
/*
* Show client message log.
* Switch window to next layout.
*/
int cmd_show_messages_exec(struct cmd *, struct cmd_ctx *);
int cmd_next_layout_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_show_messages_entry = {
"show-messages", "showmsgs",
"t:", 0, 0,
CMD_TARGET_CLIENT_USAGE,
0,
NULL,
NULL,
cmd_show_messages_exec
const struct cmd_entry cmd_next_layout_entry = {
"next-layout", "nextl",
CMD_TARGET_WINDOW_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_next_layout_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx)
cmd_next_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c;
struct message_entry *msg;
char *tim;
u_int i;
struct cmd_target_data *data = self->data;
struct winlink *wl;
u_int layout;
if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) {
msg = &ARRAY_ITEM(&c->message_log, i);
tim = ctime(&msg->msg_time);
*strchr(tim, '\n') = '\0';
ctx->print(ctx, "%s %s", tim, msg->msg);
}
layout = layout_set_next(wl->window);
ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
return (0);
}

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

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

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-paste-buffer.c,v 1.20 2009-09-07 23:48:54 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -28,94 +27,74 @@
*/
int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_paste_buffer_filter(
struct window_pane *, const char *, size_t, const char *);
void cmd_paste_buffer_lf2cr(struct buffer *, const char *, size_t);
const struct cmd_entry cmd_paste_buffer_entry = {
"paste-buffer", "pasteb",
"db:rs:t:", 0, 0,
"[-dr] [-s separator] [-b buffer-index] [-t target-pane]",
0,
NULL,
NULL,
cmd_paste_buffer_exec
"[-dr] " CMD_BUFFER_WINDOW_USAGE,
0, CMD_CHFLAG('d')|CMD_CHFLAG('r'),
cmd_buffer_init,
cmd_buffer_parse,
cmd_paste_buffer_exec,
cmd_buffer_free,
cmd_buffer_print
};
int
cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_buffer_data *data = self->data;
struct winlink *wl;
struct window_pane *wp;
struct session *s;
struct paste_buffer *pb;
const char *sepstr;
char *cause;
int buffer;
if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
wp = wl->window->active;
if (!args_has(args, 'b'))
buffer = -1;
if (data->buffer == -1)
pb = paste_get_top(&s->buffers);
else {
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
ctx->error(ctx, "buffer %s", cause);
xfree(cause);
if ((pb = paste_get_index(&s->buffers, data->buffer)) == NULL) {
ctx->error(ctx, "no buffer %d", data->buffer);
return (-1);
}
}
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');
if (sepstr == NULL) {
if (args_has(args, 'r'))
sepstr = "\n";
else
sepstr = "\r";
}
cmd_paste_buffer_filter(wp, pb->data, pb->size, sepstr);
if (pb != NULL && *pb->data != '\0') {
/* -r means raw data without LF->CR conversion. */
if (data->chflags & CMD_CHFLAG('r'))
buffer_write(wp->out, pb->data, pb->size);
else
cmd_paste_buffer_lf2cr(wp->out, pb->data, pb->size);
}
/* Delete the buffer if -d. */
if (args_has(args, 'd')) {
if (buffer == -1)
paste_free_top(&global_buffers);
if (data->chflags & CMD_CHFLAG('d')) {
if (data->buffer == -1)
paste_free_top(&s->buffers);
else
paste_free_index(&global_buffers, buffer);
paste_free_index(&s->buffers, data->buffer);
}
return (0);
return (0);
}
/* Add bytes to a buffer and filter '\n' according to separator. */
/* Add bytes to a buffer but change every '\n' to '\r'. */
void
cmd_paste_buffer_filter(
struct window_pane *wp, const char *data, size_t size, const char *sep)
cmd_paste_buffer_lf2cr(struct buffer *b, const char *data, size_t size)
{
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);
buffer_write(b, data, lf - data);
buffer_write8(b, '\r');
data = lf + 1;
}
if (end != data)
bufferevent_write(wp->event, data, end - data);
buffer_write(b, data, end - data);
}

View File

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

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-previous-layout.c,v 1.4 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,18 +18,37 @@
#include <sys/types.h>
#include <event.h>
#include "tmux.h"
char *
osdep_get_name(unused int fd, unused char *tty)
{
return (NULL);
}
/*
* Switch window to previous layout.
*/
struct event_base *
osdep_event_init(void)
int cmd_previous_layout_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_previous_layout_entry = {
"previous-layout", "prevl",
CMD_TARGET_WINDOW_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_previous_layout_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_previous_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
{
return (event_init());
struct cmd_target_data *data = self->data;
struct winlink *wl;
u_int layout;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
layout = layout_set_previous(wl->window);
ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
return (0);
}

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

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

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-refresh-client.c,v 1.10 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,21 +28,22 @@ int cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_refresh_client_entry = {
"refresh-client", "refresh",
"t:", 0, 0,
CMD_TARGET_CLIENT_USAGE,
0,
NULL,
NULL,
cmd_refresh_client_exec
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_refresh_client_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c;
struct cmd_target_data *data = self->data;
struct client *c;
if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
server_redraw_client(c);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-rename-session.c,v 1.18 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,38 +30,26 @@ int cmd_rename_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_rename_session_entry = {
"rename-session", "rename",
"t:", 1, 1,
CMD_TARGET_SESSION_USAGE " new-name",
0,
NULL,
NULL,
cmd_rename_session_exec
CMD_ARG1, 0,
cmd_target_init,
cmd_target_parse,
cmd_rename_session_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s;
const char *newname;
struct cmd_target_data *data = self->data;
struct session *s;
newname = args->argv[0];
if (!session_check_name(newname)) {
ctx->error(ctx, "bad session name: %s", newname);
return (-1);
}
if (session_find(newname) != NULL) {
ctx->error(ctx, "duplicate session: %s", newname);
return (-1);
}
if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
RB_REMOVE(sessions, &sessions, s);
xfree(s->name);
s->name = xstrdup(newname);
RB_INSERT(sessions, &sessions, s);
s->name = xstrdup(data->arg);
server_status_session(s);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-rename-window.c,v 1.29 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,29 +30,30 @@ int cmd_rename_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_rename_window_entry = {
"rename-window", "renamew",
"t:", 1, 1,
CMD_TARGET_WINDOW_USAGE " new-name",
0,
NULL,
NULL,
cmd_rename_window_exec
CMD_ARG1, 0,
cmd_target_init,
cmd_target_parse,
cmd_rename_window_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s;
struct winlink *wl;
struct cmd_target_data *data = self->data;
struct session *s;
struct winlink *wl;
if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL)
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
xfree(wl->window->name);
wl->window->name = xstrdup(args->argv[0]);
wl->window->name = xstrdup(data->arg);
options_set_number(&wl->window->options, "automatic-rename", 0);
server_status_window(wl->window);
server_status_session(s);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-resize-pane.c,v 1.12 2009-07-30 20:45:20 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,91 +26,87 @@
* Increase or decrease pane size.
*/
void cmd_resize_pane_key_binding(struct cmd *, int);
void cmd_resize_pane_init(struct cmd *, int);
int cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_resize_pane_entry = {
"resize-pane", "resizep",
"DLRt:U", 0, 1,
"[-DLRU] " CMD_TARGET_PANE_USAGE " [adjustment]",
0,
cmd_resize_pane_key_binding,
NULL,
cmd_resize_pane_exec
"[-DU] " CMD_TARGET_PANE_USAGE " [adjustment]",
CMD_ARG01,
CMD_CHFLAG('D')|CMD_CHFLAG('L')|CMD_CHFLAG('R')|CMD_CHFLAG('U'),
cmd_resize_pane_init,
cmd_target_parse,
cmd_resize_pane_exec,
cmd_target_free,
cmd_target_print
};
void
cmd_resize_pane_key_binding(struct cmd *self, int key)
cmd_resize_pane_init(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;
struct cmd_target_data *data;
cmd_target_init(self, key);
data = self->data;
if (key == (KEYC_UP | KEYC_CTRL))
data->chflags |= CMD_CHFLAG('U');
if (key == (KEYC_DOWN | KEYC_CTRL))
data->chflags |= CMD_CHFLAG('D');
if (key == (KEYC_LEFT | KEYC_CTRL))
data->chflags |= CMD_CHFLAG('L');
if (key == (KEYC_RIGHT | KEYC_CTRL))
data->chflags |= CMD_CHFLAG('R');
if (key == (KEYC_UP | KEYC_ESCAPE)) {
data->chflags |= CMD_CHFLAG('U');
data->arg = xstrdup("5");
}
if (key == (KEYC_DOWN | KEYC_ESCAPE)) {
data->chflags |= CMD_CHFLAG('D');
data->arg = xstrdup("5");
}
if (key == (KEYC_LEFT | KEYC_ESCAPE)) {
data->chflags |= CMD_CHFLAG('L');
data->arg = xstrdup("5");
}
if (key == (KEYC_RIGHT | KEYC_ESCAPE)) {
data->chflags |= CMD_CHFLAG('R');
data->arg = xstrdup("5");
}
}
int
cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct winlink *wl;
const char *errstr;
struct window_pane *wp;
u_int adjust;
if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL)
if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL)
return (-1);
if (args->argc == 0)
if (data->arg == NULL)
adjust = 1;
else {
adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
adjust = strtonum(data->arg, 1, INT_MAX, &errstr);
if (errstr != NULL) {
ctx->error(ctx, "adjustment %s", errstr);
ctx->error(ctx, "adjustment %s: %s", errstr, data->arg);
return (-1);
}
}
if (args_has(self->args, 'L'))
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust);
else if (args_has(self->args, 'R'))
if (data->chflags & (CMD_CHFLAG('L')|CMD_CHFLAG('R'))) {
if (data->chflags & CMD_CHFLAG('L'))
adjust = -adjust;
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust);
else if (args_has(self->args, 'U'))
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, -adjust);
else if (args_has(self->args, 'D'))
} else {
if (data->chflags & CMD_CHFLAG('U'))
adjust = -adjust;
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust);
}
server_redraw_window(wl->window);
return (0);

View File

@@ -1,88 +0,0 @@
/* $Id$ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
* Copyright (c) 2011 Marcel P. Partap <mpartap@gmx.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <unistd.h>
#include "tmux.h"
/*
* Respawn a pane (restart the command). Kill existing if -k given.
*/
int cmd_respawn_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_respawn_pane_entry = {
"respawn-pane", "respawnp",
"kt:", 0, 1,
"[-k] " CMD_TARGET_PANE_USAGE " [command]",
0,
NULL,
NULL,
cmd_respawn_pane_exec
};
int
cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct winlink *wl;
struct window *w;
struct window_pane *wp;
struct session *s;
struct environ env;
const char *cmd;
char *cause;
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) {
ctx->error(ctx, "pane still active: %s:%u.%u",
s->name, wl->idx, window_pane_index(w, wp));
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);
screen_reinit(&wp->base);
input_init(wp);
if (args->argc != 0)
cmd = args->argv[0];
else
cmd = NULL;
if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) {
ctx->error(ctx, "respawn pane failed: %s", cause);
xfree(cause);
environ_free(&env);
return (-1);
}
wp->flags |= PANE_REDRAW;
server_status_window(w);
environ_free(&env);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-respawn-window.c,v 1.22 2009-09-16 12:36:27 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,31 +30,31 @@ int cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_respawn_window_entry = {
"respawn-window", "respawnw",
"kt:", 0, 1,
"[-k] " CMD_TARGET_WINDOW_USAGE " [command]",
0,
NULL,
NULL,
cmd_respawn_window_exec
CMD_ARG01, CMD_CHFLAG('k'),
cmd_target_init,
cmd_target_parse,
cmd_respawn_window_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct window *w;
struct window_pane *wp;
struct session *s;
struct environ env;
const char *cmd;
char *cause;
if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL)
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
w = wl->window;
if (!args_has(self->args, 'k')) {
if (!(data->chflags & CMD_CHFLAG('k'))) {
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd == -1)
continue;
@@ -72,24 +72,18 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
wp = TAILQ_FIRST(&w->panes);
TAILQ_REMOVE(&w->panes, wp, entry);
layout_free(w);
window_destroy_panes(w);
window_destroy_panes(w);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
window_pane_resize(wp, w->sx, w->sy);
if (args->argc != 0)
cmd = args->argv[0];
else
cmd = NULL;
if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) {
if (window_pane_spawn(
wp, data->arg, NULL, NULL, &env, s->tio, &cause) != 0) {
ctx->error(ctx, "respawn window failed: %s", cause);
xfree(cause);
environ_free(&env);
server_destroy_pane(wp);
return (-1);
}
layout_init(w);
window_pane_reset_mode(wp);
screen_reinit(&wp->base);
input_init(wp);
window_set_active_pane(w, wp);
recalculate_sizes();

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-rotate-window.c,v 1.9 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,42 +24,47 @@
* Rotate the panes in a window.
*/
void cmd_rotate_window_key_binding(struct cmd *, int);
void cmd_rotate_window_init(struct cmd *, int);
int cmd_rotate_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_rotate_window_entry = {
"rotate-window", "rotatew",
"Dt:U", 0, 0,
"[-DU] " CMD_TARGET_WINDOW_USAGE,
0,
cmd_rotate_window_key_binding,
NULL,
cmd_rotate_window_exec
0, CMD_CHFLAG('D')|CMD_CHFLAG('U'),
cmd_rotate_window_init,
cmd_target_parse,
cmd_rotate_window_exec,
cmd_target_free,
cmd_target_print
};
void
cmd_rotate_window_key_binding(struct cmd *self, int key)
cmd_rotate_window_init(struct cmd *self, int key)
{
self->args = args_create(0);
struct cmd_target_data *data;
cmd_target_init(self, key);
data = self->data;
if (key == ('o' | KEYC_ESCAPE))
args_set(self->args, 'D', NULL);
data->chflags |= CMD_CHFLAG('D');
}
int
cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct window *w;
struct window_pane *wp, *wp2;
struct layout_cell *lc;
u_int sx, sy, xoff, yoff;
if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
w = wl->window;
if (args_has(self->args, 'D')) {
if (data->chflags & CMD_CHFLAG('D')) {
wp = TAILQ_LAST(&w->panes, window_panes);
TAILQ_REMOVE(&w->panes, wp, entry);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);

View File

@@ -1,141 +0,0 @@
/* $Id$ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
* Copyright (c) 2009 Nicholas Marriott <nicm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include "tmux.h"
/*
* Runs a command without a window.
*/
int cmd_run_shell_exec(struct cmd *, struct cmd_ctx *);
void cmd_run_shell_callback(struct job *);
void cmd_run_shell_free(void *);
const struct cmd_entry cmd_run_shell_entry = {
"run-shell", "run",
"", 1, 1,
"command",
0,
NULL,
NULL,
cmd_run_shell_exec
};
struct cmd_run_shell_data {
char *cmd;
struct cmd_ctx ctx;
};
int
cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_run_shell_data *cdata;
const char *shellcmd = args->argv[0];
cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(args->argv[0]);
memcpy(&cdata->ctx, ctx, sizeof cdata->ctx);
if (ctx->cmdclient != NULL)
ctx->cmdclient->references++;
if (ctx->curclient != NULL)
ctx->curclient->references++;
job_run(shellcmd, cmd_run_shell_callback, cmd_run_shell_free, cdata);
return (1); /* don't let client exit */
}
void
cmd_run_shell_callback(struct job *job)
{
struct cmd_run_shell_data *cdata = job->data;
struct cmd_ctx *ctx = &cdata->ctx;
char *cmd, *msg, *line;
size_t size;
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 {
if ((line = evbuffer_readline(job->event->input)) != NULL) {
ctx->print(ctx, "%s", line);
lines++;
}
} while (line != NULL);
size = EVBUFFER_LENGTH(job->event->input);
if (size != 0) {
line = xmalloc(size + 1);
memcpy(line, EVBUFFER_DATA(job->event->input), size);
line[size] = '\0';
ctx->print(ctx, "%s", line);
lines++;
xfree(line);
}
cmd = cdata->cmd;
msg = NULL;
if (WIFEXITED(job->status)) {
if ((retcode = WEXITSTATUS(job->status)) != 0)
xasprintf(&msg, "'%s' returned %d", cmd, retcode);
} else if (WIFSIGNALED(job->status)) {
retcode = WTERMSIG(job->status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
}
if (msg != NULL) {
if (lines != 0)
ctx->print(ctx, "%s", msg);
else
ctx->info(ctx, "%s", msg);
xfree(msg);
}
}
void
cmd_run_shell_free(void *data)
{
struct cmd_run_shell_data *cdata = data;
struct cmd_ctx *ctx = &cdata->ctx;
if (ctx->cmdclient != NULL) {
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 @@
/* $Id$ */
/* $Id: cmd-save-buffer.c,v 1.8 2009-09-07 23:48:54 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -32,71 +32,57 @@ int cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_save_buffer_entry = {
"save-buffer", "saveb",
"ab:", 1, 1,
"[-a] " CMD_BUFFER_USAGE,
0,
NULL,
NULL,
cmd_save_buffer_exec
"[-a] " CMD_BUFFER_SESSION_USAGE " path",
CMD_ARG1, CMD_CHFLAG('a'),
cmd_buffer_init,
cmd_buffer_parse,
cmd_save_buffer_exec,
cmd_buffer_free,
cmd_buffer_print
};
int
cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c = ctx->cmdclient;
struct cmd_buffer_data *data = self->data;
struct session *s;
struct paste_buffer *pb;
const char *path;
char *cause;
int buffer;
mode_t mask;
mode_t mask;
FILE *f;
if (!args_has(args, 'b')) {
if ((pb = paste_get_top(&global_buffers)) == NULL) {
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (data->buffer == -1) {
if ((pb = paste_get_top(&s->buffers)) == NULL) {
ctx->error(ctx, "no buffers");
return (-1);
}
} else {
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);
if ((pb = paste_get_index(&s->buffers, data->buffer)) == NULL) {
ctx->error(ctx, "no buffer %d", data->buffer);
return (-1);
}
}
path = args->argv[0];
if (strcmp(path, "-") == 0) {
if (c == NULL) {
ctx->error(ctx, "%s: can't write to stdout", path);
return (-1);
}
bufferevent_write(c->stdout_event, pb->data, pb->size);
} else {
mask = umask(S_IRWXG | S_IRWXO);
if (args_has(self->args, 'a'))
f = fopen(path, "ab");
else
f = fopen(path, "wb");
umask(mask);
if (f == NULL) {
ctx->error(ctx, "%s: %s", path, strerror(errno));
return (-1);
}
if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
ctx->error(ctx, "%s: fwrite error", path);
fclose(f);
return (-1);
}
fclose(f);
mask = umask(S_IRWXG | S_IRWXO);
if (data->chflags & CMD_CHFLAG('a'))
f = fopen(data->arg, "ab");
else
f = fopen(data->arg, "wb");
if (f == NULL) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1);
}
if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
ctx->error(ctx, "%s: fwrite error", data->arg);
fclose(f);
return (-1);
}
fclose(f);
umask(mask);
return (0);
}

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

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

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-select-layout.c,v 1.8 2009-07-28 23:04:29 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,60 +24,40 @@
* Switch window to selected layout.
*/
void cmd_select_layout_key_binding(struct cmd *, int);
void cmd_select_layout_init(struct cmd *, int);
int cmd_select_layout_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_select_layout_entry = {
"select-layout", "selectl",
"npt:", 0, 1,
"[-np] " CMD_TARGET_WINDOW_USAGE " [layout-name]",
0,
cmd_select_layout_key_binding,
NULL,
cmd_select_layout_exec
};
const struct cmd_entry cmd_next_layout_entry = {
"next-layout", "nextl",
"t:", 0, 0,
CMD_TARGET_WINDOW_USAGE,
0,
NULL,
NULL,
cmd_select_layout_exec
};
const struct cmd_entry cmd_previous_layout_entry = {
"previous-layout", "prevl",
"t:", 0, 0,
CMD_TARGET_WINDOW_USAGE,
0,
NULL,
NULL,
cmd_select_layout_exec
CMD_TARGET_WINDOW_USAGE " [layout-name]",
CMD_ARG01, 0,
cmd_select_layout_init,
cmd_target_parse,
cmd_select_layout_exec,
cmd_target_free,
cmd_target_print
};
void
cmd_select_layout_key_binding(struct cmd *self, int key)
cmd_select_layout_init(struct cmd *self, int key)
{
struct cmd_target_data *data;
cmd_target_init(self, key);
data = self->data;
switch (key) {
case '1' | KEYC_ESCAPE:
self->args = args_create(1, "even-horizontal");
case ('1' | KEYC_ESCAPE):
data->arg = xstrdup("even-horizontal");
break;
case '2' | KEYC_ESCAPE:
self->args = args_create(1, "even-vertical");
case ('2' | KEYC_ESCAPE):
data->arg = xstrdup("even-vertical");
break;
case ('3' | KEYC_ESCAPE):
data->arg = xstrdup("main-horizontal");
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);
case ('4' | KEYC_ESCAPE):
data->arg = xstrdup("main-vertical");
break;
}
}
@@ -85,49 +65,24 @@ cmd_select_layout_key_binding(struct cmd *self, int key)
int
cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct winlink *wl;
const char *layoutname;
int next, previous, layout;
struct cmd_target_data *data = self->data;
struct winlink *wl;
int layout;
if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
next = self->entry == &cmd_next_layout_entry;
if (args_has(self->args, 'n'))
next = 1;
previous = self->entry == &cmd_previous_layout_entry;
if (args_has(self->args, 'p'))
previous = 1;
if (next || previous) {
if (next)
layout = layout_set_next(wl->window);
else
layout = layout_set_previous(wl->window);
ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
return (0);
}
if (args->argc == 0)
if (data->arg == NULL) {
layout = wl->window->lastlayout;
else
layout = layout_set_lookup(args->argv[0]);
if (layout != -1) {
layout = layout_set_select(wl->window, layout);
ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
return (0);
}
if (args->argc != 0) {
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);
if (layout == -1)
return (0);
} else if ((layout = layout_set_lookup(data->arg)) == -1) {
ctx->error(ctx, "unknown layout or ambiguous: %s", data->arg);
return (-1);
}
layout = layout_set_select(wl->window, layout);
ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-select-pane.c,v 1.10 2009-07-30 20:45:20 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,93 +24,35 @@
* Select pane.
*/
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 = {
"select-pane", "selectp",
"lDLRt:U", 0, 0,
"[-lDLRU] " CMD_TARGET_PANE_USAGE,
0,
cmd_select_pane_key_binding,
NULL,
cmd_select_pane_exec
CMD_TARGET_PANE_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_select_pane_exec,
cmd_target_free,
cmd_target_print
};
const struct cmd_entry cmd_last_pane_entry = {
"last-pane", "lastp",
"t:", 0, 0,
CMD_TARGET_WINDOW_USAGE,
0,
NULL,
NULL,
cmd_select_pane_exec
};
void
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 cmd_target_data *data = self->data;
struct winlink *wl;
struct window_pane *wp;
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) {
ctx->error(ctx, "no last pane");
return (-1);
}
window_set_active_pane(wl->window, wl->window->last);
server_status_window(wl->window);
server_redraw_window_borders(wl->window);
return (0);
}
if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL)
if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL)
return (-1);
if (!window_pane_visible(wp)) {
ctx->error(ctx, "pane not visible");
ctx->error(ctx, "pane not visible: %s", data->target);
return (-1);
}
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);
}

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

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

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-select-window.c,v 1.23 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,113 +26,43 @@
* Select window by index.
*/
void cmd_select_window_key_binding(struct cmd *, int);
void cmd_select_window_init(struct cmd *, int);
int cmd_select_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_select_window_entry = {
"select-window", "selectw",
"lnpt:", 0, 0,
"[-lnp] " CMD_TARGET_WINDOW_USAGE,
0,
cmd_select_window_key_binding,
NULL,
cmd_select_window_exec
};
const struct cmd_entry cmd_next_window_entry = {
"next-window", "next",
"at:", 0, 0,
"[-a] " CMD_TARGET_SESSION_USAGE,
0,
cmd_select_window_key_binding,
NULL,
cmd_select_window_exec
};
const struct cmd_entry cmd_previous_window_entry = {
"previous-window", "prev",
"at:", 0, 0,
"[-a] " CMD_TARGET_SESSION_USAGE,
0,
cmd_select_window_key_binding,
NULL,
cmd_select_window_exec
};
const struct cmd_entry cmd_last_window_entry = {
"last-window", "last",
"t:", 0, 0,
CMD_TARGET_SESSION_USAGE,
0,
NULL,
NULL,
cmd_select_window_exec
CMD_TARGET_WINDOW_USAGE,
0, 0,
cmd_select_window_init,
cmd_target_parse,
cmd_select_window_exec,
cmd_target_free,
cmd_target_print
};
void
cmd_select_window_key_binding(struct cmd *self, int key)
cmd_select_window_init(struct cmd *self, int key)
{
char tmp[16];
struct cmd_target_data *data;
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);
cmd_target_init(self, key);
data = self->data;
xasprintf(&data->target, ":%d", key - '0');
}
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;
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct session *s;
next = self->entry == &cmd_next_window_entry;
if (args_has(self->args, 'n'))
next = 1;
previous = self->entry == &cmd_previous_window_entry;
if (args_has(self->args, 'p'))
previous = 1;
last = self->entry == &cmd_last_window_entry;
if (args_has(self->args, 'l'))
last = 1;
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');
if (next) {
if (session_next(s, activity) != 0) {
ctx->error(ctx, "no next window");
return (-1);
}
} else if (previous) {
if (session_previous(s, activity) != 0) {
ctx->error(ctx, "no previous window");
return (-1);
}
} else {
if (session_last(s) != 0) {
ctx->error(ctx, "no last window");
return (-1);
}
}
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
if (session_select(s, wl->idx) == 0)
server_redraw_session(s);
} else {
wl = cmd_find_window(ctx, args_get(args, 't'), &s);
if (wl == NULL)
return (-1);
if (session_select(s, wl->idx) == 0)
server_redraw_session(s);
}
recalculate_sizes();
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-send-keys.c,v 1.21 2009-08-20 11:37:46 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,40 +26,131 @@
* Send keys to client.
*/
int cmd_send_keys_parse(struct cmd *, int, char **, char **);
int cmd_send_keys_exec(struct cmd *, struct cmd_ctx *);
void cmd_send_keys_free(struct cmd *);
size_t cmd_send_keys_print(struct cmd *, char *, size_t);
struct cmd_send_keys_data {
char *target;
int idx;
u_int nkeys;
int *keys;
};
const struct cmd_entry cmd_send_keys_entry = {
"send-keys", "send",
"t:", 0, -1,
"[-t target-pane] key ...",
0,
0, 0,
NULL,
NULL,
cmd_send_keys_exec
cmd_send_keys_parse,
cmd_send_keys_exec,
cmd_send_keys_free,
cmd_send_keys_print
};
int
cmd_send_keys_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_send_keys_data *data;
int opt, key;
char *s;
self->data = data = xmalloc(sizeof *data);
data->target = NULL;
data->idx = -1;
data->nkeys = 0;
data->keys = NULL;
while ((opt = getopt(argc, argv, "t:")) != -1) {
switch (opt) {
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (argc == 0)
goto usage;
while (argc-- != 0) {
if ((key = key_string_lookup_string(*argv)) != KEYC_NONE) {
data->keys = xrealloc(
data->keys, data->nkeys + 1, sizeof *data->keys);
data->keys[data->nkeys++] = key;
} else {
for (s = *argv; *s != '\0'; s++) {
data->keys = xrealloc(data->keys,
data->nkeys + 1, sizeof *data->keys);
data->keys[data->nkeys++] = *s;
}
}
argv++;
}
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
int
cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct window_pane *wp;
struct session *s;
const char *str;
int i, key;
struct cmd_send_keys_data *data = self->data;
struct window_pane *wp;
u_int i;
if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
if (data == NULL)
return (-1);
for (i = 0; i < args->argc; i++) {
str = args->argv[i];
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
return (-1);
if ((key = key_string_lookup_string(str)) != KEYC_NONE) {
window_pane_key(wp, s, key);
} else {
for (; *str != '\0'; str++)
window_pane_key(wp, s, *str);
}
}
for (i = 0; i < data->nkeys; i++)
window_pane_key(wp, ctx->curclient, data->keys[i]);
return (0);
}
void
cmd_send_keys_free(struct cmd *self)
{
struct cmd_send_keys_data *data = self->data;
if (data->target != NULL)
xfree(data->target);
xfree(data);
}
size_t
cmd_send_keys_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_send_keys_data *data = self->data;
size_t off = 0;
u_int i;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
if (off < len && data->idx != -1)
off += xsnprintf(buf + off, len - off, " -i %d", data->idx);
for (i = 0; i < data->nkeys; i++) {
if (off >= len)
break;
off += xsnprintf(buf + off,
len - off, " %s", key_string_lookup_key(data->keys[i]));
}
return (off);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-send-prefix.c,v 1.26 2009-08-20 11:37:46 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,27 +28,28 @@ int cmd_send_prefix_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_send_prefix_entry = {
"send-prefix", NULL,
"t:", 0, 0,
CMD_TARGET_PANE_USAGE,
0,
NULL,
NULL,
cmd_send_prefix_exec
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_send_prefix_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct session *s;
struct window_pane *wp;
struct keylist *keylist;
int key;
if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL)
return (-1);
keylist = options_get_data(&s->options, "prefix");
window_pane_key(wp, s, ARRAY_FIRST(keylist));
key = options_get_number(&s->options, "prefix");
window_pane_key(wp, ctx->curclient, key);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-server-info.c,v 1.28 2009-09-07 23:59:19 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -34,45 +34,45 @@ int cmd_server_info_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_server_info_entry = {
"server-info", "info",
"", 0, 0,
"",
0,
0, 0,
NULL,
NULL,
cmd_server_info_exec
cmd_server_info_exec,
NULL,
NULL
};
/* 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;
struct tty_term *term;
struct client *c;
struct session *s;
struct winlink *wl;
struct window *w;
struct window_pane *wp;
struct tty_code *code;
struct tty_term_code_entry *ent;
struct utsname un;
struct grid *gd;
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",
"tmux " BUILD ", pid %ld, started %s", (long) getpid(), tim);
ctx->print(ctx, "socket path %s, debug level %d%s%s",
socket_path, debug_level, be_quiet ? ", quiet" : "",
login_shell ? ", login shell" : "");
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)
@@ -80,6 +80,8 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
else
ctx->print(ctx, "configuration file not specified");
ctx->print(ctx, "protocol version is %d", PROTOCOL_VERSION);
ctx->print(ctx, "%u clients, %u sessions",
ARRAY_LENGTH(&clients), ARRAY_LENGTH(&sessions));
ctx->print(ctx, "%s", "");
ctx->print(ctx, "Clients:");
@@ -88,25 +90,29 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
if (c == NULL || c->session == NULL)
continue;
ctx->print(ctx,"%2d: %s (%d, %d): %s [%ux%u %s bs=%hho] "
ctx->print(ctx, "%2d: %s (%d, %d): %s [%ux%u %s] "
"[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.sx, c->tty.sy, c->tty.termname, c->flags,
c->tty.flags, c->references);
}
ctx->print(ctx, "%s", "");
ctx->print(ctx, "Sessions: [%zu/%zu]",
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;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
t = s->tv.tv_sec;
tim = ctime(&t);
*strchr(tim, '\n') = '\0';
ctx->print(ctx, "%2u: %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);
"[flags=0x%x, references=%u]", i, s->name,
winlink_count(&s->windows), tim, s->sx, s->sy, s->flags,
s->references);
RB_FOREACH(wl, winlinks, &s->windows) {
w = wl->window;
ctx->print(ctx, "%4u: %s [%ux%u] [flags=0x%x, "
@@ -141,8 +147,8 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
}
ctx->print(ctx, "%s", "");
ctx->print(ctx, "Terminals:");
LIST_FOREACH(term, &tty_terms, entry) {
ctx->print(ctx, "Terminals:");
SLIST_FOREACH(term, &tty_terms, entry) {
ctx->print(ctx, "%s [references=%u, flags=0x%x]:",
term->name, term->references, term->flags);
for (i = 0; i < NTTYCODE; i++) {
@@ -173,11 +179,5 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
}
ctx->print(ctx, "%s", "");
ctx->print(ctx, "Jobs:");
LIST_FOREACH(job, &all_jobs, lentry) {
ctx->print(ctx, "%s [fd=%d, pid=%d, status=%d]",
job->cmd, job->fd, job->pid, job->status);
}
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-set-buffer.c,v 1.10 2009-09-07 23:48:54 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,46 +30,39 @@ int cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_set_buffer_entry = {
"set-buffer", "setb",
"b:", 1, 1,
CMD_BUFFER_USAGE " data",
0,
NULL,
NULL,
cmd_set_buffer_exec
CMD_BUFFER_SESSION_USAGE " data",
CMD_ARG1, 0,
cmd_buffer_init,
cmd_buffer_parse,
cmd_set_buffer_exec,
cmd_buffer_free,
cmd_buffer_print
};
int
cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
u_int limit;
char *pdata, *cause;
size_t psize;
int buffer;
struct cmd_buffer_data *data = self->data;
struct session *s;
u_int limit;
u_char *pdata;
size_t psize;
limit = options_get_number(&global_options, "buffer-limit");
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
limit = options_get_number(&s->options, "buffer-limit");
pdata = xstrdup(args->argv[0]);
pdata = xstrdup(data->arg);
psize = strlen(pdata);
if (!args_has(args, 'b')) {
paste_add(&global_buffers, pdata, psize, limit);
if (data->buffer == -1) {
paste_add(&s->buffers, pdata, psize, limit);
return (0);
}
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
ctx->error(ctx, "buffer %s", cause);
xfree(cause);
if (paste_replace(&s->buffers, data->buffer, pdata, psize) != 0) {
ctx->error(ctx, "no buffer %d", data->buffer);
xfree(pdata);
return (-1);
}
if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) {
ctx->error(ctx, "no buffer %d", buffer);
xfree(pdata);
return (-1);
}
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-set-environment.c,v 1.2 2009-08-11 14:42:59 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,63 +31,57 @@ int cmd_set_environment_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_set_environment_entry = {
"set-environment", "setenv",
"grt:u", 1, 2,
"[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
0,
CMD_ARG12, CMD_CHFLAG('g')|CMD_CHFLAG('r')|CMD_CHFLAG('u'),
NULL,
NULL,
cmd_set_environment_exec
cmd_target_parse,
cmd_set_environment_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s;
struct environ *env;
const char *name, *value;
struct cmd_target_data *data = self->data;
struct session *s;
struct environ *env;
name = args->argv[0];
if (*name == '\0') {
if (*data->arg == '\0') {
ctx->error(ctx, "empty variable name");
return (-1);
}
if (strchr(name, '=') != NULL) {
if (strchr(data->arg, '=') != NULL) {
ctx->error(ctx, "variable name contains =");
return (-1);
}
if (args->argc < 1)
value = NULL;
else
value = args->argv[1];
if (args_has(self->args, 'g'))
if (data->chflags & CMD_CHFLAG('g'))
env = &global_environ;
else {
if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
env = &s->environ;
}
if (args_has(self->args, 'u')) {
if (value != NULL) {
if (data->chflags & CMD_CHFLAG('u')) {
if (data->arg2 != NULL) {
ctx->error(ctx, "can't specify a value with -u");
return (-1);
}
environ_unset(env, name);
} else if (args_has(self->args, 'r')) {
if (value != NULL) {
environ_unset(env, data->arg);
} else if (data->chflags & CMD_CHFLAG('r')) {
if (data->arg2 != NULL) {
ctx->error(ctx, "can't specify a value with -r");
return (-1);
}
environ_set(env, name, NULL);
environ_set(env, data->arg, NULL);
} else {
if (value == NULL) {
if (data->arg2 == NULL) {
ctx->error(ctx, "no value specified");
return (-1);
}
environ_set(env, name, value);
environ_set(env, data->arg, data->arg2);
}
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-set-option.c,v 1.79 2009-09-19 18:53:01 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -29,161 +29,157 @@
int cmd_set_option_exec(struct cmd *, struct cmd_ctx *);
int cmd_set_option_find(const char *, const struct options_table_entry **,
const struct options_table_entry **);
int cmd_set_option_unset(struct cmd *, struct cmd_ctx *,
const struct options_table_entry *, struct options *,
const char *);
int cmd_set_option_set(struct cmd *, struct cmd_ctx *,
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_keys(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 = {
"set-option", "set",
"agst:uw", 1, 2,
"[-agsuw] [-t target-session|target-window] option [value]",
0,
"[-agu] " CMD_TARGET_SESSION_USAGE " option [value]",
CMD_ARG12, CMD_CHFLAG('a')|CMD_CHFLAG('g')|CMD_CHFLAG('u'),
NULL,
NULL,
cmd_set_option_exec
cmd_target_parse,
cmd_set_option_exec,
cmd_target_free,
cmd_target_print
};
const struct cmd_entry cmd_set_window_option_entry = {
"set-window-option", "setw",
"agt:u", 1, 2,
"[-agu] " CMD_TARGET_WINDOW_USAGE " option [value]",
0,
NULL,
NULL,
cmd_set_option_exec
const char *set_option_status_keys_list[] = {
"emacs", "vi", NULL
};
const char *set_option_status_justify_list[] = {
"left", "centre", "right", NULL
};
const char *set_option_bell_action_list[] = {
"none", "any", "current", NULL
};
const struct set_option_entry set_option_table[] = {
{ "base-index", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "bell-action", SET_OPTION_CHOICE, 0, 0, set_option_bell_action_list },
{ "buffer-limit", SET_OPTION_NUMBER, 1, INT_MAX, NULL },
{ "default-command", SET_OPTION_STRING, 0, 0, NULL },
{ "default-path", SET_OPTION_STRING, 0, 0, NULL },
{ "default-shell", SET_OPTION_STRING, 0, 0, NULL },
{ "default-terminal", SET_OPTION_STRING, 0, 0, NULL },
{ "display-panes-colour", SET_OPTION_COLOUR, 0, 0, NULL },
{ "display-panes-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL },
{ "display-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL },
{ "history-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "lock-after-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "message-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "message-bg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "message-fg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "prefix", SET_OPTION_KEY, 0, 0, NULL },
{ "repeat-time", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL },
{ "set-remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL },
{ "set-titles", SET_OPTION_FLAG, 0, 0, NULL },
{ "set-titles-string", SET_OPTION_STRING, 0, 0, NULL },
{ "status", SET_OPTION_FLAG, 0, 0, NULL },
{ "status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "status-bg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "status-fg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "status-interval", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "status-justify",
SET_OPTION_CHOICE, 0, 0, set_option_status_justify_list },
{ "status-keys", SET_OPTION_CHOICE, 0, 0, set_option_status_keys_list },
{ "status-left", SET_OPTION_STRING, 0, 0, NULL },
{ "status-left-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "status-left-bg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "status-left-fg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "status-left-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL },
{ "status-right", SET_OPTION_STRING, 0, 0, NULL },
{ "status-right-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "status-right-bg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "status-right-fg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "status-right-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL },
{ "status-utf8", SET_OPTION_FLAG, 0, 0, NULL },
{ "terminal-overrides", SET_OPTION_STRING, 0, 0, NULL },
{ "update-environment", SET_OPTION_STRING, 0, 0, NULL },
{ "visual-activity", SET_OPTION_FLAG, 0, 0, NULL },
{ "visual-bell", SET_OPTION_FLAG, 0, 0, NULL },
{ "visual-content", SET_OPTION_FLAG, 0, 0, NULL },
{ NULL, 0, 0, 0, NULL }
};
/* Look for an option in all three tables. */
int
cmd_set_option_find(
const char *optstr, const struct options_table_entry **table,
const struct options_table_entry **oe)
{
static const struct options_table_entry *tables[] = {
server_options_table,
window_options_table,
session_options_table
};
const struct options_table_entry *oe_loop;
u_int i;
for (i = 0; i < nitems(tables); i++) {
for (oe_loop = tables[i]; oe_loop->name != NULL; oe_loop++) {
if (strncmp(oe_loop->name, optstr, strlen(optstr)) != 0)
continue;
/* If already found, ambiguous. */
if (*oe != NULL)
return (-1);
*oe = oe_loop;
*table = tables[i];
/* Bail now if an exact match. */
if (strcmp((*oe)->name, optstr) == 0)
break;
}
}
return (0);
}
int
cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
const struct options_table_entry *table, *oe;
struct session *s;
struct winlink *wl;
struct client *c;
struct options *oo;
const char *optstr, *valstr;
u_int i;
struct cmd_target_data *data = self->data;
struct session *s;
struct client *c;
struct options *oo;
const struct set_option_entry *entry, *opt;
u_int i;
/* Get the option name and value. */
optstr = args->argv[0];
if (*optstr == '\0') {
if (data->chflags & CMD_CHFLAG('g'))
oo = &global_s_options;
else {
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
oo = &s->options;
}
if (*data->arg == '\0') {
ctx->error(ctx, "invalid option");
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);
}
/* Work out the tree from the table. */
if (table == server_options_table)
oo = &global_options;
else if (table == window_options_table) {
if (args_has(self->args, 'g'))
oo = &global_w_options;
else {
wl = cmd_find_window(ctx, args_get(args, 't'), NULL);
if (wl == NULL)
return (-1);
oo = &wl->window->options;
}
} else if (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;
}
} else {
ctx->error(ctx, "unknown table");
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)
entry = NULL;
for (opt = set_option_table; opt->name != NULL; opt++) {
if (strncmp(opt->name, data->arg, strlen(data->arg)) != 0)
continue;
if (entry != NULL) {
ctx->error(ctx, "ambiguous option: %s", data->arg);
return (-1);
}
entry = opt;
/* Bail now if an exact match. */
if (strcmp(entry->name, data->arg) == 0)
break;
}
if (entry == NULL) {
ctx->error(ctx, "unknown option: %s", data->arg);
return (-1);
}
if (data->chflags & CMD_CHFLAG('u')) {
if (data->chflags & CMD_CHFLAG('g')) {
ctx->error(ctx,
"can't unset global option: %s", entry->name);
return (-1);
}
if (data->arg2 != NULL) {
ctx->error(ctx,
"value passed to unset option: %s", entry->name);
return (-1);
}
options_remove(oo, entry->name);
ctx->info(ctx, "unset option: %s", entry->name);
} else {
switch (entry->type) {
case SET_OPTION_STRING:
set_option_string(ctx, oo, entry,
data->arg2, data->chflags & CMD_CHFLAG('a'));
break;
case SET_OPTION_NUMBER:
set_option_number(ctx, oo, entry, data->arg2);
break;
case SET_OPTION_KEY:
set_option_key(ctx, oo, entry, data->arg2);
break;
case SET_OPTION_COLOUR:
set_option_colour(ctx, oo, entry, data->arg2);
break;
case SET_OPTION_ATTRIBUTES:
set_option_attributes(ctx, oo, entry, data->arg2);
break;
case SET_OPTION_FLAG:
set_option_flag(ctx, oo, entry, data->arg2);
break;
case SET_OPTION_CHOICE:
set_option_choice(ctx, oo, entry, data->arg2);
break;
}
}
/* 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);
@@ -193,219 +189,3 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
return (0);
}
/* Unset an option. */
int
cmd_set_option_unset(struct cmd *self, struct cmd_ctx *ctx,
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_KEYS:
o = cmd_set_option_keys(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 keys option. */
struct options_entry *
cmd_set_option_keys(unused struct cmd *self, struct cmd_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const char *value)
{
struct keylist *keylist;
char *copy, *ptr, *s;
int key;
keylist = xmalloc(sizeof *keylist);
ARRAY_INIT(keylist);
ptr = copy = xstrdup(value);
while ((s = strsep(&ptr, ",")) != NULL) {
if ((key = key_string_lookup_string(s)) == KEYC_NONE) {
ctx->error(ctx, "unknown key: %s", s);
xfree(copy);
xfree(keylist);
return (NULL);
}
ARRAY_ADD(keylist, key);
}
xfree(copy);
return (options_set_data(oo, oe->name, keylist, xfree));
}
/* 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;
if (value == NULL || *value == '\0')
flag = !options_get_number(oo, oe->name);
else {
if ((value[0] == '1' && value[1] == '\0') ||
strcasecmp(value, "on") == 0 ||
strcasecmp(value, "yes") == 0)
flag = 1;
else if ((value[0] == '0' && value[1] == '\0') ||
strcasecmp(value, "off") == 0 ||
strcasecmp(value, "no") == 0)
flag = 0;
else {
ctx->error(ctx, "bad value: %s", value);
return (NULL);
}
}
return (options_set_number(oo, oe->name, flag));
}
/* Set a choice option. */
struct options_entry *
cmd_set_option_choice(unused struct cmd *self, struct cmd_ctx *ctx,
const struct options_table_entry *oe, struct options *oo, const char *value)
{
const char **choicep;
int n, choice = -1;
n = 0;
for (choicep = oe->choices; *choicep != NULL; choicep++) {
n++;
if (strncmp(*choicep, value, strlen(value)) != 0)
continue;
if (choice != -1) {
ctx->error(ctx, "ambiguous value: %s", value);
return (NULL);
}
choice = n - 1;
}
if (choice == -1) {
ctx->error(ctx, "unknown value: %s", value);
return (NULL);
}
return (options_set_number(oo, oe->name, choice));
}

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

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

169
cmd-set-window-option.c Normal file
View File

@@ -0,0 +1,169 @@
/* $Id: cmd-set-window-option.c,v 1.38 2009-08-11 14:42:59 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Set a window option.
*/
int cmd_set_window_option_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_set_window_option_entry = {
"set-window-option", "setw",
"[-agu] " CMD_TARGET_WINDOW_USAGE " option [value]",
CMD_ARG12, CMD_CHFLAG('a')|CMD_CHFLAG('g')|CMD_CHFLAG('u'),
NULL,
cmd_target_parse,
cmd_set_window_option_exec,
cmd_target_free,
cmd_target_print
};
const char *set_option_mode_keys_list[] = {
"emacs", "vi", NULL
};
const char *set_option_clock_mode_style_list[] = {
"12", "24", NULL
};
const struct set_option_entry set_window_option_table[] = {
{ "aggressive-resize", SET_OPTION_FLAG, 0, 0, NULL },
{ "automatic-rename", SET_OPTION_FLAG, 0, 0, NULL },
{ "clock-mode-colour", SET_OPTION_COLOUR, 0, 0, NULL },
{ "clock-mode-style",
SET_OPTION_CHOICE, 0, 0, set_option_clock_mode_style_list },
{ "force-height", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "force-width", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "main-pane-height", SET_OPTION_NUMBER, 1, INT_MAX, NULL },
{ "main-pane-width", SET_OPTION_NUMBER, 1, INT_MAX, NULL },
{ "mode-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "mode-bg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "mode-fg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "mode-keys", SET_OPTION_CHOICE, 0, 0, set_option_mode_keys_list },
{ "mode-mouse", SET_OPTION_FLAG, 0, 0, NULL },
{ "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL },
{ "monitor-content", SET_OPTION_STRING, 0, 0, NULL },
{ "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL },
{ "utf8", SET_OPTION_FLAG, 0, 0, NULL },
{ "window-status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "window-status-bg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "window-status-current-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "window-status-current-bg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "window-status-current-fg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "window-status-fg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "xterm-keys", SET_OPTION_FLAG, 0, 0, NULL },
{ NULL, 0, 0, 0, NULL }
};
int
cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct client *c;
struct options *oo;
const struct set_option_entry *entry, *opt;
u_int i;
if (data->chflags & CMD_CHFLAG('g'))
oo = &global_w_options;
else {
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
oo = &wl->window->options;
}
if (*data->arg == '\0') {
ctx->error(ctx, "invalid option");
return (-1);
}
entry = NULL;
for (opt = set_window_option_table; opt->name != NULL; opt++) {
if (strncmp(opt->name, data->arg, strlen(data->arg)) != 0)
continue;
if (entry != NULL) {
ctx->error(ctx, "ambiguous option: %s", data->arg);
return (-1);
}
entry = opt;
/* Bail now if an exact match. */
if (strcmp(entry->name, data->arg) == 0)
break;
}
if (entry == NULL) {
ctx->error(ctx, "unknown option: %s", data->arg);
return (-1);
}
if (data->chflags & CMD_CHFLAG('u')) {
if (data->chflags & CMD_CHFLAG('g')) {
ctx->error(ctx,
"can't unset global option: %s", entry->name);
return (-1);
}
if (data->arg2 != NULL) {
ctx->error(ctx,
"value passed to unset option: %s", entry->name);
return (-1);
}
options_remove(oo, entry->name);
ctx->info(ctx, "unset option: %s", entry->name);
} else {
switch (entry->type) {
case SET_OPTION_STRING:
set_option_string(ctx, oo, entry,
data->arg2, data->chflags & CMD_CHFLAG('a'));
break;
case SET_OPTION_NUMBER:
set_option_number(ctx, oo, entry, data->arg2);
break;
case SET_OPTION_KEY:
set_option_key(ctx, oo, entry, data->arg2);
break;
case SET_OPTION_COLOUR:
set_option_colour(ctx, oo, entry, data->arg2);
break;
case SET_OPTION_ATTRIBUTES:
set_option_attributes(ctx, oo, entry, data->arg2);
break;
case SET_OPTION_FLAG:
set_option_flag(ctx, oo, entry, data->arg2);
break;
case SET_OPTION_CHOICE:
set_option_choice(ctx, oo, entry, data->arg2);
break;
}
}
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);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-show-buffer.c,v 1.10 2009-09-07 23:48:54 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,47 +28,39 @@ 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
CMD_BUFFER_SESSION_USAGE,
0, 0,
cmd_buffer_init,
cmd_buffer_parse,
cmd_show_buffer_exec,
cmd_buffer_free,
cmd_buffer_print
};
int
cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_buffer_data *data = self->data;
struct session *s;
struct paste_buffer *pb;
int buffer;
char *in, *buf, *ptr, *cause;
char *in, *buf, *ptr;
size_t size, len;
u_int width;
if ((s = cmd_find_session(ctx, NULL, 0)) == NULL)
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (!args_has(args, 'b')) {
if ((pb = paste_get_top(&global_buffers)) == NULL) {
if (data->buffer == -1) {
if ((pb = paste_get_top(&s->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);
}
} else if ((pb = paste_get_index(&s->buffers, data->buffer)) == NULL) {
ctx->error(ctx, "no buffer %d", data->buffer);
return (-1);
}
if (pb == NULL)
return (0);
size = pb->size;
if (size > SIZE_MAX / 4 - 1)
@@ -79,24 +71,24 @@ cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
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);
ctx->print(ctx, "%s", buf);
len = 0;
}
} while (*ptr != '\0');
if (len != 0) {
buf[len] = '\0';
ctx->print(ctx, "%s", buf);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-show-environment.c,v 1.1 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,26 +31,27 @@ int cmd_show_environment_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_show_environment_entry = {
"show-environment", "showenv",
"gt:", 0, 0,
"[-g] " CMD_TARGET_SESSION_USAGE,
0,
NULL,
NULL,
cmd_show_environment_exec
0, CMD_CHFLAG('g'),
cmd_target_init,
cmd_target_parse,
cmd_show_environment_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s;
struct environ *env;
struct environ_entry *envent;
struct cmd_target_data *data = self->data;
struct session *s;
struct environ *env;
struct environ_entry *envent;
if (args_has(self->args, 'g'))
if (data->chflags & CMD_CHFLAG('g'))
env = &global_environ;
else {
if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
env = &s->environ;
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-show-options.c,v 1.16 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,66 +31,74 @@ int cmd_show_options_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_show_options_entry = {
"show-options", "show",
"gst:w", 0, 0,
"[-gsw] [-t target-session|target-window]",
0,
NULL,
NULL,
cmd_show_options_exec
};
const struct cmd_entry cmd_show_window_options_entry = {
"show-window-options", "showw",
"gt:", 0, 0,
"[-g] " CMD_TARGET_WINDOW_USAGE,
0,
NULL,
NULL,
cmd_show_options_exec
"[-g] " CMD_TARGET_SESSION_USAGE,
0, CMD_CHFLAG('g'),
cmd_target_init,
cmd_target_parse,
cmd_show_options_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
const struct options_table_entry *table, *oe;
struct session *s;
struct winlink *wl;
struct options *oo;
struct options_entry *o;
const char *optval;
struct cmd_target_data *data = self->data;
struct session *s;
struct options *oo;
const struct set_option_entry *entry;
char *vs;
long long vn;
if (args_has(self->args, 's')) {
oo = &global_options;
table = server_options_table;
} else if (args_has(self->args, 'w') ||
self->entry == &cmd_show_window_options_entry) {
table = window_options_table;
if (args_has(self->args, 'g'))
oo = &global_w_options;
else {
wl = cmd_find_window(ctx, args_get(args, 't'), NULL);
if (wl == NULL)
return (-1);
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;
}
if (data->chflags & CMD_CHFLAG('g'))
oo = &global_s_options;
else {
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
oo = &s->options;
}
for (oe = table; oe->name != NULL; oe++) {
if ((o = options_find1(oo, oe->name)) == NULL)
for (entry = set_option_table; entry->name != NULL; entry++) {
if (options_find1(oo, entry->name) == NULL)
continue;
optval = options_table_print_entry(oe, o);
ctx->print(ctx, "%s %s", oe->name, optval);
switch (entry->type) {
case SET_OPTION_STRING:
vs = options_get_string(oo, entry->name);
ctx->print(ctx, "%s \"%s\"", entry->name, vs);
break;
case SET_OPTION_NUMBER:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %lld", entry->name, vn);
break;
case SET_OPTION_KEY:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, key_string_lookup_key(vn));
break;
case SET_OPTION_COLOUR:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, colour_tostring(vn));
break;
case SET_OPTION_ATTRIBUTES:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, attributes_tostring(vn));
break;
case SET_OPTION_FLAG:
vn = options_get_number(oo, entry->name);
if (vn)
ctx->print(ctx, "%s on", entry->name);
else
ctx->print(ctx, "%s off", entry->name);
break;
case SET_OPTION_CHOICE:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, entry->choices[vn]);
break;
}
}
return (0);

105
cmd-show-window-options.c Normal file
View File

@@ -0,0 +1,105 @@
/* $Id: cmd-show-window-options.c,v 1.12 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Show window options.
*/
int cmd_show_window_options_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_show_window_options_entry = {
"show-window-options", "showw",
"[-g] " CMD_TARGET_WINDOW_USAGE,
0, CMD_CHFLAG('g'),
cmd_target_init,
cmd_target_parse,
cmd_show_window_options_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct options *oo;
const struct set_option_entry *entry;
char *vs;
long long vn;
if (data->chflags & CMD_CHFLAG('g'))
oo = &global_w_options;
else {
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
oo = &wl->window->options;
}
for (entry = set_window_option_table; entry->name != NULL; entry++) {
if (options_find1(oo, entry->name) == NULL)
continue;
switch (entry->type) {
case SET_OPTION_STRING:
vs = options_get_string(oo, entry->name);
ctx->print(ctx, "%s \"%s\"", entry->name, vs);
break;
case SET_OPTION_NUMBER:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %lld", entry->name, vn);
break;
case SET_OPTION_KEY:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, key_string_lookup_key(vn));
break;
case SET_OPTION_COLOUR:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, colour_tostring(vn));
break;
case SET_OPTION_ATTRIBUTES:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, attributes_tostring(vn));
break;
case SET_OPTION_FLAG:
vn = options_get_number(oo, entry->name);
if (vn)
ctx->print(ctx, "%s on", entry->name);
else
ctx->print(ctx, "%s off", entry->name);
break;
case SET_OPTION_CHOICE:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, entry->choices[vn]);
break;
}
}
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-source-file.c,v 1.8 2009-08-24 16:27:03 tcunha Exp $ */
/*
* Copyright (c) 2008 Tiago Cunha <me@tiagocunha.org>
@@ -24,51 +24,101 @@
* Sources a configuration file.
*/
int cmd_source_file_parse(struct cmd *, int, char **, char **);
int cmd_source_file_exec(struct cmd *, struct cmd_ctx *);
void cmd_source_file_free(struct cmd *);
void cmd_source_file_init(struct cmd *, int);
size_t cmd_source_file_print(struct cmd *, char *, size_t);
struct cmd_source_file_data {
char *path;
};
const struct cmd_entry cmd_source_file_entry = {
"source-file", "source",
"", 1, 1,
"path",
0,
NULL,
NULL,
cmd_source_file_exec
0, 0,
cmd_source_file_init,
cmd_source_file_parse,
cmd_source_file_exec,
cmd_source_file_free,
cmd_source_file_print
};
void
cmd_source_file_init(struct cmd *self, unused int arg)
{
struct cmd_source_file_data *data;
self->data = data = xmalloc(sizeof *data);
data->path = NULL;
}
int
cmd_source_file_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_source_file_data *data;
int opt;
self->entry->init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "")) != -1) {
switch (opt) {
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (argc != 1)
goto usage;
data->path = xstrdup(argv[0]);
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
int
cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct causelist causes;
char *cause;
struct window_pane *wp;
int retval;
u_int i;
struct cmd_source_file_data *data = self->data;
char *cause;
ARRAY_INIT(&causes);
retval = load_cfg(args->argv[0], ctx, &causes);
if (ARRAY_EMPTY(&causes))
return (retval);
if (retval == 1 && !RB_EMPTY(&sessions) && ctx->cmdclient != NULL) {
wp = RB_MIN(sessions, &sessions)->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp);
for (i = 0; i < ARRAY_LENGTH(&causes); i++) {
cause = ARRAY_ITEM(&causes, i);
window_copy_add(wp, "%s", cause);
xfree(cause);
}
} else {
for (i = 0; i < ARRAY_LENGTH(&causes); i++) {
cause = ARRAY_ITEM(&causes, i);
ctx->print(ctx, "%s", cause);
xfree(cause);
}
if (load_cfg(data->path, ctx, &cause) != 0) {
ctx->error(ctx, "%s", cause);
xfree(cause);
return (-1);
}
ARRAY_FREE(&causes);
return (retval);
return (0);
}
void
cmd_source_file_free(struct cmd *self)
{
struct cmd_source_file_data *data = self->data;
if (data->path != NULL)
xfree(data->path);
xfree(data);
}
size_t
cmd_source_file_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_source_file_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->path != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->path);
return (off);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-split-window.c,v 1.27 2009-09-16 12:36:27 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,44 +27,136 @@
* Split a window (add a new pane).
*/
void cmd_split_window_key_binding(struct cmd *, int);
int cmd_split_window_parse(struct cmd *, int, char **, char **);
int cmd_split_window_exec(struct cmd *, struct cmd_ctx *);
void cmd_split_window_free(struct cmd *);
void cmd_split_window_init(struct cmd *, int);
size_t cmd_split_window_print(struct cmd *, char *, size_t);
struct cmd_split_window_data {
char *target;
char *cmd;
int flag_detached;
int flag_horizontal;
int percentage;
int size;
};
const struct cmd_entry cmd_split_window_entry = {
"split-window", "splitw",
"dl:hp:Pt:v", 0, 1,
"[-dhvP] [-p percentage|-l size] [-t target-pane] [command]",
0,
cmd_split_window_key_binding,
NULL,
cmd_split_window_exec
"[-dhv] [-p percentage|-l size] [-t target-window] [command]",
0, 0,
cmd_split_window_init,
cmd_split_window_parse,
cmd_split_window_exec,
cmd_split_window_free,
cmd_split_window_print
};
void
cmd_split_window_key_binding(struct cmd *self, int key)
cmd_split_window_init(struct cmd *self, int key)
{
self->args = args_create(0);
if (key == '%')
args_set(self->args, 'h', NULL);
struct cmd_split_window_data *data;
self->data = data = xmalloc(sizeof *data);
data->target = NULL;
data->cmd = NULL;
data->flag_detached = 0;
data->flag_horizontal = 0;
data->percentage = -1;
data->size = -1;
switch (key) {
case '%':
data->flag_horizontal = 1;
break;
case '"':
data->flag_horizontal = 0;
break;
}
}
int
cmd_split_window_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_split_window_data *data;
int opt;
const char *errstr;
self->entry->init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "dhl:p:t:v")) != -1) {
switch (opt) {
case 'd':
data->flag_detached = 1;
break;
case 'h':
data->flag_horizontal = 1;
break;
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
case 'l':
if (data->percentage != -1 || data->size != -1)
break;
data->size = strtonum(optarg, 1, INT_MAX, &errstr);
if (errstr != NULL) {
xasprintf(cause, "size %s", errstr);
goto error;
}
break;
case 'p':
if (data->size != -1 || data->percentage != -1)
break;
data->percentage = strtonum(optarg, 1, 100, &errstr);
if (errstr != NULL) {
xasprintf(cause, "percentage %s", errstr);
goto error;
}
break;
case 'v':
data->flag_horizontal = 0;
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (argc != 0 && argc != 1)
goto usage;
if (argc == 1)
data->cmd = xstrdup(argv[0]);
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
error:
self->entry->free(self);
return (-1);
}
int
cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s;
struct winlink *wl;
struct window *w;
struct window_pane *wp, *new_wp = NULL;
struct environ env;
char *cmd, *cwd, *cause;
const char *shell;
u_int hlimit, paneidx;
int size, percentage;
enum layout_type type;
struct layout_cell *lc;
struct cmd_split_window_data *data = self->data;
struct session *s;
struct winlink *wl;
struct window *w;
struct window_pane *wp;
struct environ env;
char *cmd, *cwd, *cause;
const char *shell;
u_int hlimit;
int size;
enum layout_type type;
if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL)
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
w = wl->window;
@@ -73,80 +165,92 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
environ_copy(&s->environ, &env);
server_fill_environ(s, &env);
if (args->argc == 0)
cmd = data->cmd;
if (cmd == NULL)
cmd = options_get_string(&s->options, "default-command");
if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL)
cwd = options_get_string(&s->options, "default-path");
else
cmd = args->argv[0];
cwd = options_get_string(&s->options, "default-path");
if (*cwd == '\0') {
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
cwd = ctx->cmdclient->cwd;
else
cwd = s->cwd;
}
type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT;
cwd = ctx->cmdclient->cwd;
size = -1;
if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
ctx->error(ctx, "size %s", cause);
xfree(cause);
return (-1);
}
} else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause);
if (cause != NULL) {
ctx->error(ctx, "percentage %s", cause);
xfree(cause);
return (-1);
}
if (type == LAYOUT_TOPBOTTOM)
size = (wp->sy * percentage) / 100;
else
size = (wp->sx * percentage) / 100;
}
if (data->size != -1)
size = data->size;
else if (data->percentage != -1)
size = (w->active->sy * data->percentage) / 100;
hlimit = options_get_number(&s->options, "history-limit");
type = LAYOUT_TOPBOTTOM;
if (data->flag_horizontal)
type = LAYOUT_LEFTRIGHT;
shell = options_get_string(&s->options, "default-shell");
if (*shell == '\0' || areshell(shell))
shell = _PATH_BSHELL;
if ((lc = layout_split_pane(wp, type, size)) == NULL) {
wp = window_add_pane(w, hlimit);
if (window_pane_spawn(wp, cmd, shell, cwd, &env, s->tio, &cause) != 0)
goto error;
if (layout_split_pane(w->active, type, size, wp) != 0) {
cause = xstrdup("pane too small");
goto error;
}
new_wp = window_add_pane(w, hlimit);
if (window_pane_spawn(
new_wp, cmd, shell, cwd, &env, s->tio, &cause) != 0)
goto error;
layout_assign_pane(lc, new_wp);
server_redraw_window(w);
if (!args_has(args, 'd')) {
window_set_active_pane(w, new_wp);
if (!data->flag_detached) {
window_set_active_pane(w, wp);
session_select(s, wl->idx);
server_redraw_session(s);
} else
server_status_session(s);
environ_free(&env);
if (args_has(args, 'P')) {
paneidx = window_pane_index(wl->window, new_wp);
ctx->print(ctx, "%s:%u.%u", s->name, wl->idx, paneidx);
}
return (0);
error:
environ_free(&env);
if (new_wp != NULL)
window_remove_pane(w, new_wp);
if (wp != NULL)
window_remove_pane(w, wp);
ctx->error(ctx, "create pane failed: %s", cause);
xfree(cause);
return (-1);
}
void
cmd_split_window_free(struct cmd *self)
{
struct cmd_split_window_data *data = self->data;
if (data->target != NULL)
xfree(data->target);
if (data->cmd != NULL)
xfree(data->cmd);
xfree(data);
}
size_t
cmd_split_window_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_split_window_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->flag_detached)
off += xsnprintf(buf + off, len - off, " -d");
if (off < len && data->flag_horizontal)
off += xsnprintf(buf + off, len - off, " -h");
if (off < len && data->size > 0)
off += xsnprintf(buf + off, len - off, " -l %d", data->size);
if (off < len && data->percentage > 0) {
off += xsnprintf(
buf + off, len - off, " -p %d", data->percentage);
}
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
if (off < len && data->cmd != NULL)
off += cmd_prarg(buf + off, len - off, " ", data->cmd);
return (off);
}

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-start-server.c,v 1.8 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,15 +28,15 @@ int cmd_start_server_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_start_server_entry = {
"start-server", "start",
"", 0, 0,
"",
CMD_STARTSERVER,
CMD_STARTSERVER, 0,
NULL,
NULL,
cmd_start_server_exec
cmd_start_server_exec,
NULL,
NULL
};
/* ARGSUSED */
int
cmd_start_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
{

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-string.c,v 1.23 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -32,7 +32,7 @@
*/
int cmd_string_getc(const char *, size_t *);
void cmd_string_ungetc(size_t *);
void cmd_string_ungetc(const char *, size_t *);
char *cmd_string_string(const char *, size_t *, char, int);
char *cmd_string_variable(const char *, size_t *);
char *cmd_string_expand_tilde(const char *, size_t *);
@@ -40,15 +40,13 @@ char *cmd_string_expand_tilde(const char *, size_t *);
int
cmd_string_getc(const char *s, size_t *p)
{
const u_char *ucs = s;
if (ucs[*p] == '\0')
if (s[*p] == '\0')
return (EOF);
return (ucs[(*p)++]);
return (s[(*p)++]);
}
void
cmd_string_ungetc(size_t *p)
cmd_string_ungetc(unused const char *s, size_t *p)
{
(*p)--;
}
@@ -61,7 +59,7 @@ int
cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
{
size_t p;
int ch, i, argc, rval;
int ch, i, argc, rval, have_arg;
char **argv, *buf, *t;
const char *whitespace, *equals;
size_t len;
@@ -72,6 +70,8 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
buf = NULL;
len = 0;
have_arg = 0;
*cause = NULL;
*cmdlist = NULL;
@@ -88,6 +88,8 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
strlcpy(buf + len, t, strlen(t) + 1);
len += strlen(t);
xfree(t);
have_arg = 1;
break;
case '"':
if ((t = cmd_string_string(s, &p, '"', 1)) == NULL)
@@ -96,6 +98,8 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
strlcpy(buf + len, t, strlen(t) + 1);
len += strlen(t);
xfree(t);
have_arg = 1;
break;
case '$':
if ((t = cmd_string_variable(s, &p)) == NULL)
@@ -104,6 +108,8 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
strlcpy(buf + len, t, strlen(t) + 1);
len += strlen(t);
xfree(t);
have_arg = 1;
break;
case '#':
/* Comment: discard rest of line. */
@@ -113,7 +119,7 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
case EOF:
case ' ':
case '\t':
if (buf != NULL) {
if (have_arg) {
buf = xrealloc(buf, 1, len + 1);
buf[len] = '\0';
@@ -122,19 +128,23 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
buf = NULL;
len = 0;
have_arg = 0;
}
if (ch != EOF)
break;
if (argc == 0)
goto out;
while (argc != 0) {
equals = strchr(argv[0], '=');
whitespace = argv[0] + strcspn(argv[0], " \t");
for (i = 0; i < argc; i++) {
equals = strchr(argv[i], '=');
whitespace = argv[i] + strcspn(argv[i], " \t");
if (equals == NULL || equals > whitespace)
break;
environ_put(&global_environ, argv[0]);
environ_put(&global_environ, argv[i]);
memmove(&argv[i], &argv[i + 1], argc - i - 1);
argc--;
memmove(argv, argv + 1, argc * (sizeof *argv));
}
if (argc == 0)
goto out;
@@ -143,10 +153,14 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
if (*cmdlist == NULL)
goto out;
do
xfree(argv[argc - 1]);
while (--argc > 0);
rval = 0;
goto out;
case '~':
if (buf == NULL) {
if (have_arg == 0) {
if ((t = cmd_string_expand_tilde(s, &p)) == NULL)
goto error;
buf = xrealloc(buf, 1, len + strlen(t) + 1);
@@ -162,6 +176,8 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
buf = xrealloc(buf, 1, len + 1);
buf[len++] = ch;
have_arg = 1;
break;
}
}
@@ -173,11 +189,10 @@ out:
if (buf != NULL)
xfree(buf);
if (argv != NULL) {
for (i = 0; i < argc; i++)
xfree(argv[i]);
while (--argc >= 0)
xfree(argv[argc]);
if (argv != NULL)
xfree(argv);
}
return (rval);
}
@@ -189,33 +204,33 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc)
char *buf, *t;
size_t len;
buf = NULL;
buf = NULL;
len = 0;
while ((ch = cmd_string_getc(s, p)) != endch) {
switch (ch) {
while ((ch = cmd_string_getc(s, p)) != endch) {
switch (ch) {
case EOF:
goto error;
case '\\':
case '\\':
if (!esc)
break;
switch (ch = cmd_string_getc(s, p)) {
switch (ch = cmd_string_getc(s, p)) {
case EOF:
goto error;
case 'e':
ch = '\033';
break;
case 'r':
ch = '\r';
break;
case 'n':
ch = '\n';
break;
case 't':
ch = '\t';
break;
}
break;
case 'r':
ch = '\r';
break;
case 'n':
ch = '\n';
break;
case 't':
ch = '\t';
break;
}
break;
case '$':
if (!esc)
break;
@@ -226,13 +241,13 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc)
len += strlen(t);
xfree(t);
continue;
}
}
if (len >= SIZE_MAX - 2)
goto error;
buf = xrealloc(buf, 1, len + 1);
buf[len++] = ch;
}
buf[len++] = ch;
}
buf = xrealloc(buf, 1, len + 1);
buf[len] = '\0';
@@ -247,10 +262,9 @@ error:
char *
cmd_string_variable(const char *s, size_t *p)
{
int ch, fch;
char *buf, *t;
size_t len;
struct environ_entry *envent;
int ch, fch;
char *buf, *t;
size_t len;
#define cmd_string_first(ch) ((ch) == '_' || \
((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
@@ -258,7 +272,7 @@ cmd_string_variable(const char *s, size_t *p)
((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \
((ch) >= '0' && (ch) <= '9'))
buf = NULL;
buf = NULL;
len = 0;
fch = EOF;
@@ -297,16 +311,17 @@ cmd_string_variable(const char *s, size_t *p)
if (fch == '{' && ch != '}')
goto error;
if (ch != EOF && fch != '{')
cmd_string_ungetc(p); /* ch */
cmd_string_ungetc(s, p); /* ch */
buf = xrealloc(buf, 1, len + 1);
buf[len] = '\0';
envent = environ_find(&global_environ, buf);
xfree(buf);
if (envent == NULL)
if ((t = getenv(buf)) == NULL) {
xfree(buf);
return (xstrdup(""));
return (xstrdup(envent->value));
}
xfree(buf);
return (xstrdup(t));
error:
if (buf != NULL)
@@ -317,24 +332,23 @@ error:
char *
cmd_string_expand_tilde(const char *s, size_t *p)
{
struct passwd *pw;
struct environ_entry *envent;
char *home, *path, *username;
struct passwd *pw;
char *home, *path, *username;
home = NULL;
if (cmd_string_getc(s, p) == '/') {
envent = environ_find(&global_environ, "HOME");
if (envent != NULL && *envent->value != '\0')
home = envent->value;
else if ((pw = getpwuid(getuid())) != NULL)
home = pw->pw_dir;
if ((home = getenv("HOME")) == NULL) {
if ((pw = getpwuid(getuid())) != NULL)
home = pw->pw_dir;
}
} else {
cmd_string_ungetc(p);
cmd_string_ungetc(s, p);
if ((username = cmd_string_string(s, p, '/', 0)) == NULL)
return (NULL);
if ((pw = getpwnam(username)) != NULL)
home = pw->pw_dir;
xfree(username);
if (username != NULL)
xfree(username);
}
if (home == NULL)
return (NULL);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-suspend-client.c,v 1.4 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -29,23 +29,29 @@
int cmd_suspend_client_exec(struct cmd *, struct cmd_ctx *);
struct cmd_suspend_client_data {
char *name;
char *target;
};
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
"[-c target-client]",
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_suspend_client_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_suspend_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c;
struct cmd_target_data *data = self->data;
struct client *c;
if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
tty_stop_tty(&c->tty);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-swap-pane.c,v 1.13 2009-07-30 21:04:40 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,58 +26,65 @@
* Swap two panes.
*/
void cmd_swap_pane_key_binding(struct cmd *, int);
void cmd_swap_pane_init(struct cmd *, int);
int cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_swap_pane_entry = {
"swap-pane", "swapp",
"dDs:t:U", 0, 0,
"[-dDU] " CMD_SRCDST_PANE_USAGE,
0,
cmd_swap_pane_key_binding,
NULL,
cmd_swap_pane_exec
0, CMD_CHFLAG('d')|CMD_CHFLAG('D')|CMD_CHFLAG('U'),
cmd_swap_pane_init,
cmd_srcdst_parse,
cmd_swap_pane_exec,
cmd_srcdst_free,
cmd_srcdst_print
};
void
cmd_swap_pane_key_binding(struct cmd *self, int key)
cmd_swap_pane_init(struct cmd *self, int key)
{
self->args = args_create(0);
struct cmd_target_data *data;
cmd_srcdst_init(self, key);
data = self->data;
if (key == '{')
args_set(self->args, 'U', NULL);
data->chflags |= CMD_CHFLAG('U');
else if (key == '}')
args_set(self->args, 'D', NULL);
data->chflags |= CMD_CHFLAG('D');
}
int
cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_srcdst_data *data = self->data;
struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w;
struct window_pane *tmp_wp, *src_wp, *dst_wp;
struct layout_cell *src_lc, *dst_lc;
u_int sx, sy, xoff, yoff;
dst_wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &dst_wp);
if (dst_wl == NULL)
if (data == NULL)
return (0);
if ((dst_wl = cmd_find_pane(ctx, data->dst, NULL, &dst_wp)) == NULL)
return (-1);
dst_w = dst_wl->window;
if (!args_has(args, 's')) {
if (data->src == NULL) {
src_w = dst_w;
if (args_has(self->args, 'D')) {
if (data->chflags & CMD_CHFLAG('D')) {
src_wp = TAILQ_NEXT(dst_wp, entry);
if (src_wp == NULL)
src_wp = TAILQ_FIRST(&dst_w->panes);
} else if (args_has(self->args, 'U')) {
} else if (data->chflags & CMD_CHFLAG('U')) {
src_wp = TAILQ_PREV(dst_wp, window_panes, entry);
if (src_wp == NULL)
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);
src_wl = cmd_find_pane(ctx, data->src, NULL, &src_wp);
if (src_wl == NULL)
return (-1);
src_w = src_wl->window;
@@ -102,7 +109,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
dst_wp->layout_cell = src_lc;
dst_lc->wp = src_wp;
src_wp->layout_cell = dst_lc;
src_wp->window = dst_w;
dst_wp->window = src_w;
@@ -113,7 +120,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
dst_wp->xoff = xoff; dst_wp->yoff = yoff;
window_pane_resize(dst_wp, sx, sy);
if (!args_has(self->args, 'd')) {
if (!(data->chflags & CMD_CHFLAG('d'))) {
if (src_w != dst_w) {
window_set_active_pane(src_w, dst_wp);
window_set_active_pane(dst_w, src_wp);
@@ -129,12 +136,6 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
if (dst_w->active == dst_wp)
window_set_active_pane(dst_w, src_wp);
}
if (src_w != dst_w) {
if (src_w->last == src_wp)
src_w->last = NULL;
if (dst_w->last == dst_wp)
dst_w->last = NULL;
}
server_redraw_window(src_w);
server_redraw_window(dst_w);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-swap-window.c,v 1.17 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,39 +30,28 @@ int cmd_swap_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_swap_window_entry = {
"swap-window", "swapw",
"ds:t:", 0, 0,
"[-d] " CMD_SRCDST_WINDOW_USAGE,
0,
NULL,
NULL,
cmd_swap_window_exec
0, CMD_CHFLAG('d'),
cmd_srcdst_init,
cmd_srcdst_parse,
cmd_swap_window_exec,
cmd_srcdst_free,
cmd_srcdst_print
};
int
cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
const char *target_src, *target_dst;
struct cmd_srcdst_data *data = self->data;
struct session *src, *dst;
struct session_group *sg_src, *sg_dst;
struct winlink *wl_src, *wl_dst;
struct window *w;
target_src = args_get(args, 's');
if ((wl_src = cmd_find_window(ctx, target_src, &src)) == NULL)
if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL)
return (-1);
target_dst = args_get(args, 't');
if ((wl_dst = cmd_find_window(ctx, target_dst, &dst)) == NULL)
if ((wl_dst = cmd_find_window(ctx, data->dst, &dst)) == NULL)
return (-1);
sg_src = session_group_find(src);
sg_dst = session_group_find(dst);
if (src != dst &&
sg_src != NULL && sg_dst != NULL && sg_src == sg_dst) {
ctx->error(ctx, "can't move window, sessions are grouped");
return (-1);
}
if (wl_dst->window == wl_src->window)
return (0);
@@ -70,17 +59,14 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx)
wl_dst->window = wl_src->window;
wl_src->window = w;
if (!args_has(self->args, 'd')) {
if (!(data->chflags & CMD_CHFLAG('d'))) {
session_select(dst, wl_dst->idx);
if (src != dst)
session_select(src, wl_src->idx);
}
session_group_synchronize_from(src);
server_redraw_session_group(src);
if (src != dst) {
session_group_synchronize_from(dst);
server_redraw_session_group(dst);
}
server_redraw_session(src);
if (src != dst)
server_redraw_session(dst);
recalculate_sizes();
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id$ */
/* $Id: cmd-switch-client.c,v 1.17 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,77 +27,110 @@
* Switch client to a different session.
*/
void cmd_switch_client_key_binding(struct cmd *, int);
int cmd_switch_client_parse(struct cmd *, int, char **, char **);
int cmd_switch_client_exec(struct cmd *, struct cmd_ctx *);
void cmd_switch_client_free(struct cmd *);
size_t cmd_switch_client_print(struct cmd *, char *, size_t);
struct cmd_switch_client_data {
char *name;
char *target;
};
const struct cmd_entry cmd_switch_client_entry = {
"switch-client", "switchc",
"lc:npt:", 0, 0,
"[-lnp] [-c target-client] [-t target-session]",
0,
cmd_switch_client_key_binding,
"[-c target-client] [-t target-session]",
0, 0,
NULL,
cmd_switch_client_exec
cmd_switch_client_parse,
cmd_switch_client_exec,
cmd_switch_client_free,
cmd_switch_client_print
};
void
cmd_switch_client_key_binding(struct cmd *self, int key)
int
cmd_switch_client_parse(struct cmd *self, int argc, char **argv, char **cause)
{
self->args = args_create(0);
switch (key) {
case '(':
args_set(self->args, 'p', NULL);
break;
case ')':
args_set(self->args, 'n', NULL);
break;
case 'L':
args_set(self->args, 'l', NULL);
break;
struct cmd_switch_client_data *data;
int opt;
self->data = data = xmalloc(sizeof *data);
data->name = NULL;
data->target = NULL;
while ((opt = getopt(argc, argv, "c:t:")) != -1) {
switch (opt) {
case 'c':
data->name = xstrdup(optarg);
break;
case 't':
data->target = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (argc != 0)
goto usage;
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
int
cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c;
struct session *s;
struct cmd_switch_client_data *data = self->data;
struct client *c;
struct session *s;
if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL)
if (data == NULL)
return (0);
if ((c = cmd_find_client(ctx, data->name)) == NULL)
return (-1);
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
s = NULL;
if (args_has(args, 'n')) {
if ((s = session_next_session(c->session)) == NULL) {
ctx->error(ctx, "can't find next session");
return (-1);
}
} else if (args_has(args, 'p')) {
if ((s = session_previous_session(c->session)) == NULL) {
ctx->error(ctx, "can't find previous session");
return (-1);
}
} else if (args_has(args, 'l')) {
if (c->last_session != NULL && session_alive(c->last_session))
s = c->last_session;
if (s == NULL) {
ctx->error(ctx, "can't find last session");
return (-1);
}
} else
s = cmd_find_session(ctx, args_get(args, 't'), 0);
if (s == NULL)
return (-1);
if (c->session != NULL)
c->last_session = c->session;
c->session = s;
session_update_activity(s);
recalculate_sizes();
server_check_unattached();
server_redraw_client(c);
return (0);
}
void
cmd_switch_client_free(struct cmd *self)
{
struct cmd_switch_client_data *data = self->data;
if (data->name != NULL)
xfree(data->name);
if (data->target != NULL)
xfree(data->target);
xfree(data);
}
size_t
cmd_switch_client_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_switch_client_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->name != NULL)
off += cmd_prarg(buf + off, len - off, " -c ", data->name);
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
return (off);
}

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