1 Commits
2.6 ... 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
274 changed files with 22052 additions and 49460 deletions

20
.gitignore vendored
View File

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

View File

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

View File

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

991
CHANGES

File diff suppressed because it is too large Load Diff

View File

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

21
COPYING
View File

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

204
FAQ Normal file
View File

@@ -0,0 +1,204 @@
tmux frequently asked questions
* How is tmux different from GNU screen? What else does it offer?
tmux offers several advantages over screen:
- 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.
There are still a few features screen includes that tmux omits:
- 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. 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;
- the terminal emulator you are using and the TERM setting when tmux was
started;
- a description of the problem;
- if the problem is repeatable, the steps to repeat the problem;
- for screen corruption issues, a screenshot and the output of "infocmp $TERM"
from outside tmux are often very useful.
* Why doesn't tmux do $x?
Please send feature requests by email to nicm@users.sourceforge.net.
* Why do you use the screen terminal description inside tmux? It sucks.
It is already widely available. It is planned to change to something else such
as xterm-xfree86 at some point, if possible.
* I don't see any colour in my terminal! Help!
On some platforms, common terminal descriptions such as xterm do not include
colour. screen ignores this, tmux does not. If the terminal emulator in use
supports colour, use a value for TERM which correctly lists this, such as
xterm-color.
* tmux freezes my terminal when I attach to a session. I even have to kill -9
the shell it was started from to recover!
Some consoles really really don't like attempts to set the window title. Tell
tmux not to do this by turning off the "set-titles" option (you can do this
in .tmux.conf):
set -g set-titles off
If this doesn't fix it, send a bug report.
* Why is C-b the prefix key? How do I change it?
The default key is C-b because the prototype of tmux was originally developed
inside screen and C-b was chosen not to clash with the screen meta key. It
also has the advantage of not interfering with the use of C-a for start-of-line
in emacs and the shell (although it does interfere with previous-character).
Changing is simple: change the "prefix-key" option, and - if required - move
the binding of the "send-prefix" command from C-b (C-b C-b sends C-b by
default) to the new key. For example:
set -g prefix C-a
unbind C-b
bind C-a send-prefix
* How do I use UTF-8?
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
* How do I use a 256 colour terminal?
Provided the underlying terminal supports 256 colours, it is usually sufficient
to add the following to ~/.tmux.conf:
set -g default-terminal "screen-256color"
Note that some platforms do not support "screen-256color" ("infocmp
screen-256color" will return an error) - in this case see the next entry in
this FAQ.
tmux attempts to detect a 256 colour terminal both by looking at the colors
terminfo entry and by looking for the string "256col" in the TERM environment
variable.
If both these methods fail, the -2 flag may be passed to tmux when attaching
to a session to indicate the terminal supports 256 colours.
* vim or $otherprogram doesn't display 256 colours. What's up?
Some programs attempt to detect the number of colours a terminal is capable of
by checking the colors terminfo or Co termcap entry. However, this is not
reliable, and in any case is missing from the "screen" terminal description
used inside tmux.
There are two options (aside from using "screen-256color") to allow programs to
recognise they are running on a 256-colour terminal inside tmux:
- Manually force the application to use 256 colours always or if TERM is set to
screen. For vim, you can do this by overriding the t_Co option, see
http://vim.wikia.com/wiki/256_colors_in_vim.
- Creating a custom terminfo file that includes colors#256 in ~/.terminfo and
using it instead. These may be compiled with tic(1).
* How do I make Ctrl-PgUp and Ctrl-PgDn work in vim?
tmux supports passing through ctrl (and where supported by the client terminal,
alt and shift) modifiers to function keys using xterm(1)-style key sequences.
This may be enabled per window, or globally with the tmux command:
setw -g xterm-keys on
Because the TERM variable inside tmux must be set to "screen", vim will not
automatically detect these keys are available; however, the appropriate key
sequences can be overridden in .vimrc using the following:
if &term == "screen"
set t_kN=^[[6;*~
set t_kP=^[[5;*~
endif
And similarly for any other keys for which modifiers are desired.
Please note that the "xterm-keys" setting may affect other programs, in the
same way as running them in a standard xterm; for example most shells do not
expect to receive xterm(1)-style key sequences so this setting may prevent keys
such as ctrl-left and ctrl-right working correctly. tmux also passes through
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.
* 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
elinks attempts to guess by looking at the environment. Rather than looking for
TERM=screen, it uses the STY variable to detect if it is running in screen;
tmux does not use this so the check fails. A workaround is to set STY before
running elinks.
The following shell function does this, and also clears the window title on
exit (elinks, for some strange reason, sets it to the value of TERM):
elinks() {
STY= `which elinks` $*
echo -ne \\033]0\;\\007;
}
* What is the proper way to escape characters with #(command)?
When using the #(command) construction to include the output from a command in
the status line, the command will be parsed twice. First, when it's read by the
configuration file or the command-prompt parser, and second when the status
line is being drawn and the command is passed to the shell. For example, to
echo the string "(test)" to the status line, either single or double quotes
could be used:
set -g status-right "#(echo \\\\(test\\\\))"
set -g status-right '#(echo \\\(test\\\))'
In both cases, the status-right option will be set to the string "#(echo
\\(test\\))" and the command executed will be "echo \(test\)".
* tmux uses too much CPU. What do I do?
Automatic window renaming may use a lot of CPU, particularly on slow computers:
if this is a problem, turn it off with "setw -g automatic-rename off". If this
doesn't fix it, please report the problem.
* I use PuTTY and my tmux window pane separators are all qqqqqqqqq's!
PuTTY is using a character set translation that doesn't support ACS line
drawing. With a Unicode font, try setting PuTTY to use a different translation
on the Window -> Translation configuration page. For example, change UTF-8 to
ISO-8859-1 or CP437. It may also be necessary to adjust the way PuTTY treats
line drawing characters in the lower part of the same configuration page.
$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

View File

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

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,202 +0,0 @@
# Makefile.am
# Obvious program stuff.
bin_PROGRAMS = tmux
CLEANFILES = tmux.1.mdoc tmux.1.man
# Distribution tarball options.
EXTRA_DIST = \
CHANGES README COPYING example_tmux.conf compat/*.[ch] \
osdep-*.c mdoc2man.awk tmux.1
# Preprocessor flags.
AM_CPPFLAGS += @XOPEN_DEFINES@ -DTMUX_CONF="\"$(sysconfdir)/tmux.conf\""
# Additional object files.
LDADD = $(LIBOBJS)
# Set flags for gcc.
if IS_GCC
AM_CFLAGS += -std=gnu99 -O2
if IS_DEBUG
AM_CFLAGS += -g
AM_CFLAGS += -Wno-long-long -Wall -W -Wformat=2
AM_CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
AM_CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
AM_CFLAGS += -Wno-unused-result
AM_CPPFLAGS += -DDEBUG
endif
AM_CPPFLAGS += -iquote.
endif
# Set flags for Solaris.
if IS_SUNOS
if IS_GCC
AM_CPPFLAGS += -D_XPG6
else
AM_CPPFLAGS += -D_XPG4_2
endif
endif
# Set flags for Sun CC.
if IS_SUNCC
AM_CFLAGS += -erroff=E_EMPTY_DECLARATION
endif
# Set _LINUX_SOURCE_COMPAT for AIX for malloc(0).
if IS_AIX
AM_CPPFLAGS += -D_LINUX_SOURCE_COMPAT=1
endif
# Set flags for NetBSD.
if IS_NETBSD
AM_CPPFLAGS += -D_OPENBSD_SOURCE
endif
# List of sources.
dist_tmux_SOURCES = \
alerts.c \
arguments.c \
attributes.c \
cfg.c \
client.c \
cmd-attach-session.c \
cmd-bind-key.c \
cmd-break-pane.c \
cmd-capture-pane.c \
cmd-choose-tree.c \
cmd-command-prompt.c \
cmd-confirm-before.c \
cmd-copy-mode.c \
cmd-detach-client.c \
cmd-display-message.c \
cmd-display-panes.c \
cmd-find-window.c \
cmd-find.c \
cmd-if-shell.c \
cmd-join-pane.c \
cmd-kill-pane.c \
cmd-kill-server.c \
cmd-kill-session.c \
cmd-kill-window.c \
cmd-list-buffers.c \
cmd-list-clients.c \
cmd-list-keys.c \
cmd-list-panes.c \
cmd-list-sessions.c \
cmd-list-windows.c \
cmd-list.c \
cmd-load-buffer.c \
cmd-lock-server.c \
cmd-move-window.c \
cmd-new-session.c \
cmd-new-window.c \
cmd-paste-buffer.c \
cmd-pipe-pane.c \
cmd-queue.c \
cmd-refresh-client.c \
cmd-rename-session.c \
cmd-rename-window.c \
cmd-resize-pane.c \
cmd-respawn-pane.c \
cmd-respawn-window.c \
cmd-rotate-window.c \
cmd-run-shell.c \
cmd-save-buffer.c \
cmd-select-layout.c \
cmd-select-pane.c \
cmd-select-window.c \
cmd-send-keys.c \
cmd-set-buffer.c \
cmd-set-environment.c \
cmd-set-hook.c \
cmd-set-option.c \
cmd-show-environment.c \
cmd-show-messages.c \
cmd-show-options.c \
cmd-source-file.c \
cmd-split-window.c \
cmd-string.c \
cmd-swap-pane.c \
cmd-swap-window.c \
cmd-switch-client.c \
cmd-unbind-key.c \
cmd-wait-for.c \
cmd.c \
colour.c \
compat.h \
control-notify.c \
control.c \
environ.c \
format.c \
grid-view.c \
grid.c \
hooks.c \
input-keys.c \
input.c \
job.c \
key-bindings.c \
key-string.c \
layout-custom.c \
layout-set.c \
layout.c \
log.c \
mode-tree.c \
names.c \
notify.c \
options-table.c \
options.c \
paste.c \
proc.c \
resize.c \
screen-redraw.c \
screen-write.c \
screen.c \
server-client.c \
server-fn.c \
server.c \
session.c \
status.c \
style.c \
tmux.c \
tmux.h \
tty-acs.c \
tty-keys.c \
tty-term.c \
tty.c \
utf8.c \
window-buffer.c \
window-client.c \
window-clock.c \
window-copy.c \
window-tree.c \
window.c \
xmalloc.c \
xmalloc.h \
xterm-keys.c
nodist_tmux_SOURCES = osdep-@PLATFORM@.c
# Add compat file for forkpty.
if NEED_FORKPTY
nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c
endif
# Add compat file for utf8proc.
if HAVE_UTF8PROC
nodist_tmux_SOURCES += compat/utf8proc.c
endif
# Install tmux.1 in the right format.
install-exec-hook:
if test x@MANFORMAT@ = xmdoc; then \
sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1 \
>$(srcdir)/tmux.1.mdoc; \
else \
sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1| \
$(AWK) -f$(srcdir)/mdoc2man.awk >$(srcdir)/tmux.1.man; \
fi
$(mkdir_p) $(DESTDIR)$(mandir)/man1
$(INSTALL_DATA) $(srcdir)/tmux.1.@MANFORMAT@ \
$(DESTDIR)$(mandir)/man1/tmux.1

86
NOTES Normal file
View File

@@ -0,0 +1,86 @@
Welcome to tmux!
tmux is a "terminal multiplexer", it enables a number of terminals (or windows)
to be accessed and controlled from a single terminal. tmux is intended to be a
simple, modern, BSD-licensed alternative to programs such as GNU screen.
This 0.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.
If upgrading from 0.5, PLEASE NOTE the following configuration file changes: it
is now required to pass the -g flag to set-option or set-window-option to set
global options; remain-by-default and utf8-default are now gone, use global
window options (set-window-option -g) instead.
tmux consists of a server part and multiple clients. The server is created when
required and runs continuously unless killed by the user. Clients access the
server through a socket in /tmp. Multiple sessions may be created on a single
server and attached to a number of clients. Each session may then have a number
of windows and windows may be linked to a number of sessions. Commands are
available to create, rename and destroy windows and sessions; to attach and
detach sessions from client terminals; to set configuration options; to split
windows into several simultaneously displayed panes; and to bind and unbind
command keys (invoked preceded by a prefix key, by default ctrl-b). Please see
the tmux(1) man page for further information.
The following is a summary of major features implemented in this version:
- Basic multiplexing, window switching, attaching and detaching.
- Window listing and renaming.
- Key binding.
- Handling of client terminal resize.
- Terminal emulation sufficient to handle most curses applications.
- A optional status line (enabled by default).
- Window history and copy and paste.
- Support for VT100 line drawing characters.
- A large command set.
- Vertical window splitting and layout.
- Automatic server locking on inactivity.
- A configuration file.
- UTF-8 support.
A more extensive, but rough, todo list is included in the TODO file.
tmux also depends on several features of the client terminal (TERM), if these
are missing it may refuse to run, or not behave correctly. Known working are
TERM=screen (tmux in screen), xterm, xterm-color and rxvt. Note that TERM=xterm
does not support colour on OpenBSD. screen ignores this, tmux does not: use
xterm-color or rxvt for colour.
tmux supports UTF-8. To use it, the utf8 option must be set on each window;
this may be turned on for all windows by setting it as a global option, see
tmux(1) and the FAQ file. 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:
- Drop the file in the syntax directory in your runtimepath (such as
~/.vim/syntax/tmux.vim).
- Make the filetype recognisable by adding the following to filetype.vim
in your runtimepath (~/.vim/filetype.vim):
augroup filetypedetect
au BufNewFile,BufRead .tmux.conf*,tmux.conf* setf tmux
augroup END
- Switch on syntax highlighting by adding "syntax enable" to your vimrc file.
For debugging, running tmux with -v or -vv will generate server and client log
files in the current directory.
tmux mailing lists are available; visit:
https://sourceforge.net/mail/?group_id=200378
Bug reports, feature suggestions and especially code contributions are most
welcome. Please send by email to:
nicm@users.sf.net
-- Nicholas Marriott <nicm@users.sf.net>
$Id: NOTES,v 1.49 2009-07-06 18:53:24 nicm Exp $

76
README
View File

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

173
SYNCING
View File

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

234
TODO
View File

@@ -1,130 +1,106 @@
- command bits and pieces:
* allow multiple targets: fnmatch for -t/-c, for example detach all
clients with -t*
* ' and " should be parsed the same (eg "\e" vs '\e') in config
and command prompt
* last-pane across sessions
* resize-pane -p to match split-window -p
* flag to wait-for to have a timeout and/or to stop waiting when the
client gets a signal
- make command sequences more usable
* don't require space after ;
* options for error handling: && and ||?
- options bits and pieces:
* way to set socket path from config file
- format improvements:
* option to quote format (#{q:session_name})
* some way to pad # stuff with spaces
* formats to show if a window is linked into multiple sessions, into
multiple attached sessions, and is the active window in multiple
attached sessions?
* comparison operators like < and > (for #{version}?)
* %else statement in config file
- improve monitor-*:
* straighten out rules for multiple clients
* think about what happens across sessions
* monitor changes within a region
* perhaps monitor /all/ panes in the window not just one
- improve mouse support:
* bind commands to mouse in different areas?
* commands executed when clicking on a pattern (URL)
- 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)?
- 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 (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; 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-*
- copy/paste improvements:
* paste w/o trailing whitespace
* command to toggle selection not to move it in copy-mode
* regex searching
* searching in copy mode should unwrap lines, so if you search for "foobar"
then it should be found even if it is now "foo\nbar" (if the WRAP flag
is set on the line)
* capture-pane option to preserve spaces but not join lines
* improve word and line selection in copy mode (for example when
dragging it should select by word. compare how xterm works. GitHub
issue 682)
- layout stuff
* way to tag a layout as a number/name
* maybe keep last layout + size around and if size reverts just put it
back
* revamp layouts: they are too complicated, should be more closely
integrated, should support hints, layout sets should just be a
special case of custom layouts, and we should support panes that are
not attached to a cell at all. this could be the time to introduce
panelink to replace layout_cell
* way to set hints/limits about pane size for resizing
* panning over window (window larger than visible)
* a mode where one application can cross two panes (ie x|y, width =
COLUMNS/2 but height = ROWS * 2)
* separate active panes for different clients
* way to choose where the freed space goes when a pane is killed:
option to kill-pane? GitHub issue 918
- code cleanup
* instead of separate window and session options, just one master
options list with each option having a type (window or session), then
options on window, on session, and global. for window options we look
window->session->global, and for session we look session->global.
problem: what about windows in multiple sessions? there are contexts
where we do not know which session, or where multiple choices makes
no sense... could at least have one global list for all types of
global options and keep separate window,session lists
* the way pane, window, session destroy is handled is too complicated
and the distinction between session.c, window.c and server-fn.c
functions is not clear. could we just have kill_pane(),
kill_window(), unlink_window(), kill_session() that fix up all data
structures (flagging sessions as dead) and return a value to say
whether clients need to be checked for dead sessions? sort of like
session_detach now but more so. or some other scheme to make it
simpler and clearer? also would be nice to remove/rename server-fn.c
* more readable way to work out the various things commands need to
know about the client, notably:
- is this the config file? (cmdq->c == NULL)
- is this a command client? (cmdq->c != NULL &&
cmdq->c->session == NULL)
- is this a control client?
- can i do stdin or stdout to this client?
or even guarantee that cmdq->c != NULL and provide a better way to
tell when in the config file - then we use cmdq->c if we need a
client w/o a session else cmd_current_client
- miscellaneous
* link panes into multiple windows
* live update: server started with -U connects to server, requests
sessions and windows, receives file descriptors
* there are inconsistencies in what we get from old shell and what
comes from config for new sessions and windows. likewise, panes and
jobs and run-shell and lock command all start with slightly different
environments
* multiline status line? separate command prompt and status line?
* automatic pane logging
* marks in history, automatically add (move?) one when pane is changed
* this doesn't work, need pane reference count probably:
bind -n DoubleClick3Status confirm-before -p "kill-window #I? (y/n)" kill-window
* respawn -c flag same as neww etc
* marker lines in history (GitHub issue 1042)
* tree mode stuff: predefined filters, tag-all key, ...
- hooks
* more hooks for various things
* finish after hooks for special commands. these do not have a hook at
the moment:
attach-session detach-client kill-server respawn-window
swap-window break-pane find-window kill-session rotate-window
switch-client choose-tree if-shell kill-window run-shell
wait-for command-prompt join-pane move-window source-file
confirm-before kill-pane respawn-pane swap-pane
at the moment AFTERHOOK uses current only if target is not valid,
but target is ALWAYS valid - it should use current if no -t flag?
then select-* could use AFTERHOOK
* multiple hooks with the same name?
* finish hooks for notifys
* for session_closed, if no sessions at all, perhaps fake up a
temporary one
- 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-*
- 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
- 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
- support the mouse wheel to scroll through history

317
alerts.c
View File

@@ -1,317 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <event.h>
#include <stdlib.h>
#include "tmux.h"
static int alerts_fired;
static void alerts_timer(int, short, void *);
static int alerts_enabled(struct window *, int);
static void alerts_callback(int, short, void *);
static void alerts_reset(struct window *);
static int alerts_action_applies(struct winlink *, const char *);
static int alerts_check_all(struct window *);
static int alerts_check_bell(struct window *);
static int alerts_check_activity(struct window *);
static int alerts_check_silence(struct window *);
static void alerts_set_message(struct winlink *, const char *,
const char *);
static TAILQ_HEAD(, window) alerts_list = TAILQ_HEAD_INITIALIZER(alerts_list);
static void
alerts_timer(__unused int fd, __unused short events, void *arg)
{
struct window *w = arg;
log_debug("@%u alerts timer expired", w->id);
alerts_queue(w, WINDOW_SILENCE);
}
static void
alerts_callback(__unused int fd, __unused short events, __unused void *arg)
{
struct window *w, *w1;
int alerts;
TAILQ_FOREACH_SAFE(w, &alerts_list, alerts_entry, w1) {
alerts = alerts_check_all(w);
log_debug("@%u alerts check, alerts %#x", w->id, alerts);
w->alerts_queued = 0;
TAILQ_REMOVE(&alerts_list, w, alerts_entry);
w->flags &= ~WINDOW_ALERTFLAGS;
window_remove_ref(w, __func__);
}
alerts_fired = 0;
}
static int
alerts_action_applies(struct winlink *wl, const char *name)
{
int action;
/*
* {bell,activity,silence}-action determines when to alert: none means
* nothing happens, current means only do something for the current
* window and other means only for windows other than the current.
*/
action = options_get_number(wl->session->options, name);
if (action == ALERT_ANY)
return (1);
if (action == ALERT_CURRENT)
return (wl == wl->session->curw);
if (action == ALERT_OTHER)
return (wl != wl->session->curw);
return (0);
}
static int
alerts_check_all(struct window *w)
{
int alerts;
alerts = alerts_check_bell(w);
alerts |= alerts_check_activity(w);
alerts |= alerts_check_silence(w);
return (alerts);
}
void
alerts_check_session(struct session *s)
{
struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows)
alerts_check_all(wl->window);
}
static int
alerts_enabled(struct window *w, int flags)
{
if (flags & WINDOW_BELL) {
if (options_get_number(w->options, "monitor-bell"))
return (1);
}
if (flags & WINDOW_ACTIVITY) {
if (options_get_number(w->options, "monitor-activity"))
return (1);
}
if (flags & WINDOW_SILENCE) {
if (options_get_number(w->options, "monitor-silence") != 0)
return (1);
}
return (0);
}
void
alerts_reset_all(void)
{
struct window *w;
RB_FOREACH(w, windows, &windows)
alerts_reset(w);
}
static void
alerts_reset(struct window *w)
{
struct timeval tv;
if (!event_initialized(&w->alerts_timer))
evtimer_set(&w->alerts_timer, alerts_timer, w);
w->flags &= ~WINDOW_SILENCE;
event_del(&w->alerts_timer);
timerclear(&tv);
tv.tv_sec = options_get_number(w->options, "monitor-silence");
log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec);
if (tv.tv_sec != 0)
event_add(&w->alerts_timer, &tv);
}
void
alerts_queue(struct window *w, int flags)
{
alerts_reset(w);
if ((w->flags & flags) != flags) {
w->flags |= flags;
log_debug("@%u alerts flags added %#x", w->id, flags);
}
if (alerts_enabled(w, flags)) {
if (!w->alerts_queued) {
w->alerts_queued = 1;
TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
window_add_ref(w, __func__);
}
if (!alerts_fired) {
log_debug("alerts check queued (by @%u)", w->id);
event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
alerts_fired = 1;
}
}
}
static int
alerts_check_bell(struct window *w)
{
struct winlink *wl;
struct session *s;
if (~w->flags & WINDOW_BELL)
return (0);
if (!options_get_number(w->options, "monitor-bell"))
return (0);
TAILQ_FOREACH(wl, &w->winlinks, wentry)
wl->session->flags &= ~SESSION_ALERTED;
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
/*
* Bells are allowed even if there is an existing bell (so do
* not check WINLINK_BELL).
*/
s = wl->session;
if (s->curw != wl)
wl->flags |= WINLINK_BELL;
if (!alerts_action_applies(wl, "bell-action"))
continue;
notify_winlink("alert-bell", wl);
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
alerts_set_message(wl, "Bell", "visual-bell");
}
return (WINDOW_BELL);
}
static int
alerts_check_activity(struct window *w)
{
struct winlink *wl;
struct session *s;
if (~w->flags & WINDOW_ACTIVITY)
return (0);
if (!options_get_number(w->options, "monitor-activity"))
return (0);
TAILQ_FOREACH(wl, &w->winlinks, wentry)
wl->session->flags &= ~SESSION_ALERTED;
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
if (wl->flags & WINLINK_ACTIVITY)
continue;
s = wl->session;
if (s->curw != wl)
wl->flags |= WINLINK_ACTIVITY;
if (!alerts_action_applies(wl, "activity-action"))
continue;
notify_winlink("alert-activity", wl);
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
alerts_set_message(wl, "Activity", "visual-activity");
}
return (WINDOW_ACTIVITY);
}
static int
alerts_check_silence(struct window *w)
{
struct winlink *wl;
struct session *s;
if (~w->flags & WINDOW_SILENCE)
return (0);
if (options_get_number(w->options, "monitor-silence") == 0)
return (0);
TAILQ_FOREACH(wl, &w->winlinks, wentry)
wl->session->flags &= ~SESSION_ALERTED;
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
if (wl->flags & WINLINK_SILENCE)
continue;
s = wl->session;
if (s->curw != wl)
wl->flags |= WINLINK_SILENCE;
if (!alerts_action_applies(wl, "silence-action"))
continue;
notify_winlink("alert-silence", wl);
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
alerts_set_message(wl, "Silence", "visual-silence");
}
return (WINDOW_SILENCE);
}
static void
alerts_set_message(struct winlink *wl, const char *type, const char *option)
{
struct client *c;
int visual;
/*
* We have found an alert (bell, activity or silence), so we need to
* pass it on to the user. For each client attached to this session,
* decide whether a bell, message or both is needed.
*
* If visual-{bell,activity,silence} is on, then a message is
* substituted for a bell; if it is off, a bell is sent as normal; both
* mean both a bell and message is sent.
*/
visual = options_get_number(wl->session->options, option);
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != wl->session || c->flags & CLIENT_CONTROL)
continue;
if (visual == VISUAL_OFF || visual == VISUAL_BOTH)
tty_putcode(&c->tty, TTYC_BEL);
if (visual == VISUAL_OFF)
continue;
if (c->session->curw == wl)
status_message_set(c, "%s in current window", type);
else
status_message_set(c, "%s in window %d", type, wl->idx);
}
}

View File

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

119
array.h Normal file
View File

@@ -0,0 +1,119 @@
/* $Id: array.h,v 1.7 2008-09-29 16:58:02 nicm Exp $ */
/*
* Copyright (c) 2006 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef ARRAY_H
#define ARRAY_H
#define ARRAY_DECL(n, c) \
struct n { \
c *list; \
u_int num; \
size_t space; \
}
#define ARRAY_ITEM(a, i) ((a)->list[i])
#define ARRAY_ITEMSIZE(a) (sizeof *(a)->list)
#define ARRAY_INITIALSPACE(a) (10 * ARRAY_ITEMSIZE(a))
#define ARRAY_ENSURE(a, n) do { \
if (UINT_MAX - (n) < (a)->num) \
fatalx("number too big"); \
if (SIZE_MAX / ((a)->num + (n)) < ARRAY_ITEMSIZE(a)) \
fatalx("size too big"); \
if ((a)->space == 0) { \
(a)->space = ARRAY_INITIALSPACE(a); \
(a)->list = xrealloc((a)->list, 1, (a)->space); \
} \
while ((a)->space <= ((a)->num + (n)) * ARRAY_ITEMSIZE(a)) { \
(a)->list = xrealloc((a)->list, 2, (a)->space); \
(a)->space *= 2; \
} \
} while (0)
#define ARRAY_EMPTY(a) ((a) == NULL || (a)->num == 0)
#define ARRAY_LENGTH(a) ((a)->num)
#define ARRAY_DATA(a) ((a)->list)
#define ARRAY_FIRST(a) ARRAY_ITEM(a, 0)
#define ARRAY_LAST(a) ARRAY_ITEM(a, (a)->num - 1)
#define ARRAY_INIT(a) do { \
(a)->num = 0; \
(a)->list = NULL; \
(a)->space = 0; \
} while (0)
#define ARRAY_CLEAR(a) do { \
(a)->num = 0; \
} while (0)
#define ARRAY_SET(a, i, s) do { \
(a)->list[i] = s; \
} while (0)
#define ARRAY_ADD(a, s) do { \
ARRAY_ENSURE(a, 1); \
(a)->list[(a)->num] = s; \
(a)->num++; \
} while (0)
#define ARRAY_INSERT(a, i, s) do { \
ARRAY_ENSURE(a, 1); \
if ((i) < (a)->num) { \
memmove((a)->list + (i) + 1, (a)->list + (i), \
ARRAY_ITEMSIZE(a) * ((a)->num - (i))); \
} \
(a)->list[i] = s; \
(a)->num++; \
} while (0)
#define ARRAY_REMOVE(a, i) do { \
if ((i) < (a)->num - 1) { \
memmove((a)->list + (i), (a)->list + (i) + 1, \
ARRAY_ITEMSIZE(a) * ((a)->num - (i) - 1)); \
} \
(a)->num--; \
if ((a)->num == 0) \
ARRAY_FREE(a); \
} while (0)
#define ARRAY_EXPAND(a, n) do { \
ARRAY_ENSURE(a, n); \
(a)->num += n; \
} while (0)
#define ARRAY_TRUNC(a, n) do { \
if ((a)->num > n) \
(a)->num -= n; \
else \
ARRAY_FREE(a); \
} while (0)
#define ARRAY_CONCAT(a, b) do { \
ARRAY_ENSURE(a, (b)->num); \
memcpy((a)->list + (a)->num, (b)->list, (b)->num * ARRAY_ITEMSIZE(a)) \
(a)->num += (b)->num; \
} while (0)
#define ARRAY_FREE(a) do { \
if ((a)->list != NULL) \
xfree((a)->list); \
ARRAY_INIT(a); \
} while (0)
#define ARRAY_FREEALL(a) do { \
ARRAY_FREE(a); \
xfree(a); \
} while (0)
#endif

View File

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

View File

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

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);
}

274
cfg.c
View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cfg.c,v 1.22 2009-08-24 16:27:03 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,229 +17,111 @@
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
static char *cfg_file;
int cfg_finished;
static char **cfg_causes;
static u_int cfg_ncauses;
static struct cmdq_item *cfg_item;
/*
* Config file parser. Pretty quick and simple, each line is parsed into a
* argv array and executed as a command.
*/
static enum cmd_retval
cfg_client_done(__unused struct cmdq_item *item, __unused void *data)
void printflike2 cfg_print(struct cmd_ctx *, const char *, ...);
void printflike2 cfg_error(struct cmd_ctx *, const char *, ...);
char *cfg_cause;
void printflike2
cfg_print(unused struct cmd_ctx *ctx, unused const char *fmt, ...)
{
if (!cfg_finished)
return (CMD_RETURN_WAIT);
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cfg_done(__unused struct cmdq_item *item, __unused void *data)
void printflike2
cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...)
{
if (cfg_finished)
return (CMD_RETURN_NORMAL);
cfg_finished = 1;
va_list ap;
if (!RB_EMPTY(&sessions))
cfg_show_causes(RB_MIN(sessions, &sessions));
if (cfg_item != NULL)
cfg_item->flags &= ~CMDQ_WAITING;
status_prompt_load_history();
return (CMD_RETURN_NORMAL);
}
void
set_cfg_file(const char *path)
{
free(cfg_file);
cfg_file = xstrdup(path);
}
void
start_cfg(void)
{
const char *home;
int quiet = 0;
struct client *c;
/*
* Configuration files are loaded without a client, so NULL is passed
* into load_cfg() and commands run in the global queue with
* item->client NULL.
*
* However, we must block the initial client (but just the initial
* client) so that its command runs after the configuration is loaded.
* Because start_cfg() is called so early, we can be sure the client's
* command queue is currently empty and our callback will be at the
* front - we need to get in before MSG_COMMAND.
*/
c = TAILQ_FIRST(&clients);
if (c != NULL) {
cfg_item = cmdq_get_callback(cfg_client_done, NULL);
cmdq_append(c, cfg_item);
}
load_cfg(TMUX_CONF, NULL, NULL, 1);
if (cfg_file == NULL && (home = find_home()) != NULL) {
xasprintf(&cfg_file, "%s/.tmux.conf", home);
quiet = 1;
}
if (cfg_file != NULL)
load_cfg(cfg_file, NULL, NULL, quiet);
cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
va_start(ap, fmt);
xvasprintf(&cfg_cause, fmt, ap);
va_end(ap);
}
int
load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
load_cfg(const char *path, struct cmd_ctx *ctxin, char **cause)
{
FILE *f;
const char delim[3] = { '\\', '\\', '\0' };
u_int found = 0;
size_t line = 0;
char *buf, *cause1, *p, *q, *s;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
int condition = 0;
struct format_tree *ft;
FILE *f;
u_int n;
char *buf, *line, *ptr;
size_t len;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
log_debug("loading %s", path);
if ((f = fopen(path, "rb")) == NULL) {
if (errno == ENOENT && quiet)
return (0);
cfg_add_cause("%s: %s", path, strerror(errno));
return (-1);
xasprintf(cause, "%s: %s", path, strerror(errno));
return (1);
}
n = 0;
while ((buf = fparseln(f, NULL, &line, delim, 0)) != NULL) {
log_debug("%s: %s", path, buf);
p = buf;
while (isspace((u_char)*p))
p++;
if (*p == '\0') {
free(buf);
continue;
line = NULL;
while ((buf = fgetln(f, &len))) {
if (buf[len - 1] == '\n')
buf[len - 1] = '\0';
else {
line = xrealloc(line, 1, len + 1);
memcpy(line, buf, len);
line[len] = '\0';
buf = line;
}
q = p + strlen(p) - 1;
while (q != p && isspace((u_char)*q))
*q-- = '\0';
n++;
if (condition != 0 && strcmp(p, "%endif") == 0) {
condition = 0;
continue;
}
if (strncmp(p, "%if ", 4) == 0) {
if (condition != 0) {
cfg_add_cause("%s:%zu: nested %%if", path,
line);
if (cmd_string_parse(buf, &cmdlist, cause) != 0) {
if (*cause == NULL)
continue;
}
ft = format_create(NULL, NULL, FORMAT_NONE,
FORMAT_NOJOBS);
s = p + 3;
while (isspace((u_char)*s))
s++;
s = format_expand(ft, s);
if (*s != '\0' && (s[0] != '0' || s[1] != '\0'))
condition = 1;
else
condition = -1;
free(s);
format_free(ft);
continue;
goto error;
}
if (condition == -1)
continue;
cmdlist = cmd_string_parse(p, path, line, &cause1);
if (cmdlist == NULL) {
free(buf);
if (cause1 == NULL)
continue;
cfg_add_cause("%s:%zu: %s", path, line, cause1);
free(cause1);
continue;
}
free(buf);
if (cmdlist == NULL)
continue;
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
if (item != NULL)
cmdq_insert_after(item, new_item);
else
cmdq_append(c, new_item);
cmd_list_free(cmdlist);
cfg_cause = NULL;
found++;
if (ctxin == NULL) {
ctx.msgdata = NULL;
ctx.curclient = NULL;
ctx.cmdclient = NULL;
} else {
ctx.msgdata = ctxin->msgdata;
ctx.curclient = ctxin->curclient;
ctx.cmdclient = ctxin->cmdclient;
}
ctx.error = cfg_error;
ctx.print = cfg_print;
ctx.info = cfg_print;
cfg_cause = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist);
if (cfg_cause != NULL) {
*cause = cfg_cause;
goto error;
}
}
if (line != NULL)
xfree(line);
fclose(f);
return (found);
}
void
cfg_add_cause(const char *fmt, ...)
{
va_list ap;
char *msg;
va_start(ap, fmt);
xvasprintf(&msg, fmt, ap);
va_end(ap);
cfg_ncauses++;
cfg_causes = xreallocarray(cfg_causes, cfg_ncauses, sizeof *cfg_causes);
cfg_causes[cfg_ncauses - 1] = msg;
}
void
cfg_print_causes(struct cmdq_item *item)
{
u_int i;
for (i = 0; i < cfg_ncauses; i++) {
cmdq_print(item, "%s", cfg_causes[i]);
free(cfg_causes[i]);
}
free(cfg_causes);
cfg_causes = NULL;
cfg_ncauses = 0;
}
void
cfg_show_causes(struct session *s)
{
struct window_pane *wp;
u_int i;
if (s == NULL || cfg_ncauses == 0)
return;
wp = s->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode, NULL, NULL);
window_copy_init_for_output(wp);
for (i = 0; i < cfg_ncauses; i++) {
window_copy_add(wp, "%s", cfg_causes[i]);
free(cfg_causes[i]);
}
free(cfg_causes);
cfg_causes = NULL;
cfg_ncauses = 0;
return (0);
error:
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);
}

919
client.c
View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: client.c,v 1.70 2009-09-03 21:06:30 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,705 +17,314 @@
*/
#include <sys/types.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <errno.h>
#include <event.h>
#include <fcntl.h>
#include <signal.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "tmux.h"
static struct tmuxproc *client_proc;
static struct tmuxpeer *client_peer;
static int client_flags;
static struct event client_stdin;
static enum {
CLIENT_EXIT_NONE,
CLIENT_EXIT_DETACHED,
CLIENT_EXIT_DETACHED_HUP,
CLIENT_EXIT_LOST_TTY,
CLIENT_EXIT_TERMINATED,
CLIENT_EXIT_LOST_SERVER,
CLIENT_EXIT_EXITED,
CLIENT_EXIT_SERVER_EXITED,
} client_exitreason = CLIENT_EXIT_NONE;
static int client_exitval;
static enum msgtype client_exittype;
static const char *client_exitsession;
static const char *client_execshell;
static const char *client_execcmd;
static int client_attached;
void client_send_environ(struct client_ctx *);
void client_handle_winch(struct client_ctx *);
static __dead void client_exec(const char *,const char *);
static int client_get_lock(char *);
static int client_connect(struct event_base *, const char *, int);
static void client_send_identify(const char *, const char *);
static void client_stdin_callback(int, short, void *);
static void client_write(int, const char *, size_t);
static void client_signal(int);
static void client_dispatch(struct imsg *, void *);
static void client_dispatch_attached(struct imsg *);
static void client_dispatch_wait(struct imsg *);
static const char *client_exit_message(void);
/*
* Get server create lock. If already held then server start is happening in
* another client, so block until the lock is released and return -2 to
* retry. Return -1 on failure to continue and start the server anyway.
*/
static int
client_get_lock(char *lockfile)
int
client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags)
{
int lockfd;
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
log_debug("lock file is %s", lockfile);
#ifdef HAVE_SETPROCTITLE
if (realpath(path, rpathbuf) == NULL)
strlcpy(rpathbuf, path, sizeof rpathbuf);
setproctitle("client (%s)", rpathbuf);
#endif
if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) {
log_debug("open failed: %s", strerror(errno));
return (-1);
if (lstat(path, &sb) != 0) {
if (cmdflags & CMD_STARTSERVER && errno == ENOENT) {
if ((fd = server_start(path)) == -1)
goto start_failed;
goto server_started;
}
goto not_found;
}
if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
log_debug("flock failed: %s", strerror(errno));
if (errno != EAGAIN)
return (lockfd);
while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
/* nothing */;
close(lockfd);
return (-2);
if (!S_ISSOCK(sb.st_mode)) {
errno = ENOTSOCK;
goto not_found;
}
log_debug("flock succeeded");
return (lockfd);
}
/* Connect client to server. */
static int
client_connect(struct event_base *base, const char *path, int start_server)
{
struct sockaddr_un sa;
size_t size;
int fd, lockfd = -1, locked = 0;
char *lockfile = NULL;
memset(&sa, 0, sizeof sa);
sa.sun_family = AF_UNIX;
size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
if (size >= sizeof sa.sun_path) {
errno = ENAMETOOLONG;
return (-1);
goto not_found;
}
log_debug("socket is %s", path);
retry:
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
return (-1);
fatal("socket");
log_debug("trying connect");
if (connect(fd, (struct sockaddr *)&sa, sizeof sa) == -1) {
log_debug("connect failed: %s", strerror(errno));
if (errno != ECONNREFUSED && errno != ENOENT)
goto failed;
if (!start_server)
goto failed;
close(fd);
if (!locked) {
xasprintf(&lockfile, "%s.lock", path);
if ((lockfd = client_get_lock(lockfile)) < 0) {
log_debug("didn't get lock (%d)", lockfd);
free(lockfile);
lockfile = NULL;
if (lockfd == -2)
goto retry;
}
log_debug("got lock (%d)", lockfd);
/*
* Always retry at least once, even if we got the lock,
* because another client could have taken the lock,
* started the server and released the lock between our
* connect() and flock().
*/
locked = 1;
goto retry;
}
if (lockfd >= 0 && unlink(path) != 0 && errno != ENOENT) {
free(lockfile);
close(lockfd);
return (-1);
}
fd = server_start(client_proc, base, lockfd, lockfile);
}
if (locked && lockfd >= 0) {
free(lockfile);
close(lockfd);
}
setblocking(fd, 0);
return (fd);
failed:
if (locked) {
free(lockfile);
close(lockfd);
}
close(fd);
return (-1);
}
/* Get exit string from reason number. */
const char *
client_exit_message(void)
{
static char msg[256];
switch (client_exitreason) {
case CLIENT_EXIT_NONE:
break;
case CLIENT_EXIT_DETACHED:
if (client_exitsession != NULL) {
xsnprintf(msg, sizeof msg, "detached "
"(from session %s)", client_exitsession);
return (msg);
}
return ("detached");
case CLIENT_EXIT_DETACHED_HUP:
if (client_exitsession != NULL) {
xsnprintf(msg, sizeof msg, "detached and SIGHUP "
"(from session %s)", client_exitsession);
return (msg);
}
return ("detached and SIGHUP");
case CLIENT_EXIT_LOST_TTY:
return ("lost tty");
case CLIENT_EXIT_TERMINATED:
return ("terminated");
case CLIENT_EXIT_LOST_SERVER:
return ("lost server");
case CLIENT_EXIT_EXITED:
return ("exited");
case CLIENT_EXIT_SERVER_EXITED:
return ("server exited");
}
return ("unknown reason");
}
/* Client main loop. */
int
client_main(struct event_base *base, int argc, char **argv, int flags)
{
struct cmd *cmd;
struct cmd_list *cmdlist;
struct msg_command_data *data;
int cmdflags, fd, i;
const char *ttynam, *cwd;
pid_t ppid;
enum msgtype msg;
char *cause, path[PATH_MAX];
struct termios tio, saved_tio;
size_t size;
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
signal(SIGCHLD, SIG_IGN);
/* Save the flags. */
client_flags = flags;
/* Set up the initial command. */
cmdflags = 0;
if (shell_command != NULL) {
msg = MSG_SHELL;
cmdflags = CMD_STARTSERVER;
} else if (argc == 0) {
msg = MSG_COMMAND;
cmdflags = CMD_STARTSERVER;
} else {
msg = MSG_COMMAND;
/*
* It sucks parsing the command string twice (in client and
* later in server) but it is necessary to get the start server
* flag.
*/
cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause);
if (cmdlist != NULL) {
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
if (cmd->entry->flags & CMD_STARTSERVER)
cmdflags |= CMD_STARTSERVER;
}
cmd_list_free(cmdlist);
}
}
/* Create client process structure (starts logging). */
client_proc = proc_start("client");
proc_set_signals(client_proc, client_signal);
/* Initialize the client socket and start the server. */
fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
if (fd == -1) {
if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
if (errno == ECONNREFUSED) {
fprintf(stderr, "no server running on %s\n",
socket_path);
} else {
fprintf(stderr, "error connecting to %s (%s)\n",
socket_path, strerror(errno));
if (unlink(path) != 0 || !(cmdflags & CMD_STARTSERVER))
goto not_found;
if ((fd = server_start(path)) == -1)
goto start_failed;
goto server_started;
}
goto not_found;
}
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);
if (cmdflags & CMD_SENDENVIRON)
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;
if (getcwd(data.cwd, sizeof data.cwd) == NULL)
*data.cwd = '\0';
*data.term = '\0';
if ((term = getenv("TERM")) != NULL) {
if (strlcpy(data.term,
term, sizeof data.term) >= sizeof data.term)
*data.term = '\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");
fd2 = dup(STDIN_FILENO);
imsg_compose(&cctx->ibuf, MSG_IDENTIFY,
PROTOCOL_VERSION, -1, fd2, &data, sizeof data);
}
return (0);
start_failed:
log_warnx("server failed to start");
return (1);
not_found:
log_warn("server not found");
return (1);
}
void
client_send_environ(struct client_ctx *cctx)
{
char **var;
struct msg_environ_data data;
for (var = environ; *var != NULL; var++) {
if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var)
continue;
client_write_server(cctx, MSG_ENVIRON, &data, sizeof data);
}
}
int
client_main(struct client_ctx *cctx)
{
struct pollfd pfd;
int n, nfds;
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 (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;
}
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;
}
if (client_msg_dispatch(cctx) != 0)
break;
}
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);
}
client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL);
/* Save these before pledge(). */
if ((cwd = getcwd(path, sizeof path)) == NULL) {
if ((cwd = find_home()) == NULL)
cwd = "/";
}
if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
ttynam = "";
/*
* Drop privileges for client. "proc exec" is needed for -c and for
* locking (which uses system(3)).
*
* "tty" is needed to restore termios(4) and also for some reason -CC
* does not work properly without it (input is not recognised).
*
* "sendfd" is dropped later in client_dispatch_wait().
*/
if (pledge("stdio unix sendfd proc exec tty", NULL) != 0)
fatal("pledge failed");
/* Free stuff that is not used in the client. */
if (ptm_fd != -1)
close(ptm_fd);
options_free(global_options);
options_free(global_s_options);
options_free(global_w_options);
environ_free(global_environ);
/* Create stdin handler. */
setblocking(STDIN_FILENO, 0);
event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
client_stdin_callback, NULL);
if (client_flags & CLIENT_CONTROLCONTROL) {
if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) {
fprintf(stderr, "tcgetattr failed: %s\n",
strerror(errno));
return (1);
}
cfmakeraw(&tio);
tio.c_iflag = ICRNL|IXANY;
tio.c_oflag = OPOST|ONLCR;
#ifdef NOKERNINFO
tio.c_lflag = NOKERNINFO;
#endif
tio.c_cflag = CREAD|CS8|HUPCL;
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;
cfsetispeed(&tio, cfgetispeed(&saved_tio));
cfsetospeed(&tio, cfgetospeed(&saved_tio));
tcsetattr(STDIN_FILENO, TCSANOW, &tio);
}
/* Send identify messages. */
client_send_identify(ttynam, cwd);
/* Send first command. */
if (msg == MSG_COMMAND) {
/* How big is the command? */
size = 0;
for (i = 0; i < argc; i++)
size += strlen(argv[i]) + 1;
data = xmalloc((sizeof *data) + size);
/* Prepare command for server. */
data->argc = argc;
if (cmd_pack_argv(argc, argv, (char *)(data + 1), size) != 0) {
fprintf(stderr, "command too long\n");
free(data);
return (1);
}
size += sizeof *data;
/* Send the command. */
if (proc_send(client_peer, msg, -1, data, size) != 0) {
fprintf(stderr, "failed to send command\n");
free(data);
return (1);
}
free(data);
} else if (msg == MSG_SHELL)
proc_send(client_peer, msg, -1, NULL, 0);
/* Start main loop. */
proc_loop(client_proc, NULL);
/* Run command if user requested exec, instead of exiting. */
if (client_exittype == MSG_EXEC) {
if (client_flags & CLIENT_CONTROLCONTROL)
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
client_exec(client_execshell, client_execcmd);
}
/* Print the exit message, if any, and exit. */
if (client_attached) {
if (client_exitreason != CLIENT_EXIT_NONE)
printf("[%s]\n", client_exit_message());
ppid = getppid();
if (client_exittype == MSG_DETACHKILL && ppid > 1)
kill(ppid, SIGHUP);
} else if (client_flags & CLIENT_CONTROLCONTROL) {
if (client_exitreason != CLIENT_EXIT_NONE)
printf("%%exit %s\n", client_exit_message());
else
printf("%%exit\n");
printf("\033\\");
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
} else if (client_exitreason != CLIENT_EXIT_NONE)
fprintf(stderr, "%s\n", client_exit_message());
setblocking(STDIN_FILENO, 1);
return (client_exitval);
}
/* Send identify messages to server. */
static void
client_send_identify(const char *ttynam, const char *cwd)
void
client_handle_winch(struct client_ctx *cctx)
{
const char *s;
char **ss;
size_t sslen;
int fd, flags = client_flags;
pid_t pid;
struct msg_resize_data data;
struct winsize ws;
proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
fatal("ioctl failed");
if ((s = getenv("TERM")) == NULL)
s = "";
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
data.sx = ws.ws_col;
data.sy = ws.ws_row;
client_write_server(cctx, MSG_RESIZE, &data, sizeof data);
proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
strlen(ttynam) + 1);
proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
if ((fd = dup(STDIN_FILENO)) == -1)
fatal("dup failed");
proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
pid = getpid();
proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
for (ss = environ; *ss != NULL; ss++) {
sslen = strlen(*ss) + 1;
if (sslen > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
continue;
proc_send(client_peer, MSG_IDENTIFY_ENVIRON, -1, *ss, sslen);
}
proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0);
sigwinch = 0;
}
/* Callback for client stdin read events. */
static void
client_stdin_callback(__unused int fd, __unused short events,
__unused void *arg)
int
client_msg_dispatch(struct client_ctx *cctx)
{
struct msg_stdin_data data;
struct imsg imsg;
struct msg_print_data printdata;
ssize_t n, datalen;
data.size = read(STDIN_FILENO, data.data, sizeof data.data);
if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
return;
for (;;) {
if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1)
fatalx("imsg_get failed");
if (n == 0)
return (0);
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
proc_send(client_peer, MSG_STDIN, -1, &data, sizeof data);
if (data.size <= 0)
event_del(&client_stdin);
}
switch (imsg.hdr.type) {
case MSG_DETACH:
if (datalen != 0)
fatalx("bad MSG_DETACH size");
/* Force write to file descriptor. */
static void
client_write(int fd, const char *data, size_t size)
{
ssize_t used;
while (size != 0) {
used = write(fd, data, size);
if (used == -1) {
if (errno == EINTR || errno == EAGAIN)
continue;
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)
fatalx("bad MSG_EXIT size");
client_write_server(cctx, MSG_EXITING, NULL, 0);
cctx->exittype = CCTX_EXIT;
break;
case MSG_EXITED:
if (datalen != 0)
fatalx("bad MSG_EXITED size");
imsg_free(&imsg);
return (-1);
case MSG_SHUTDOWN:
if (datalen != 0)
fatalx("bad MSG_SHUTDOWN size");
client_write_server(cctx, MSG_EXITING, NULL, 0);
cctx->exittype = CCTX_SHUTDOWN;
break;
case MSG_SUSPEND:
if (datalen != 0)
fatalx("bad MSG_SUSPEND size");
client_suspend();
break;
default:
fatalx("unexpected message");
}
data += used;
size -= used;
}
}
/* Run command in shell; used for -c. */
static __dead void
client_exec(const char *shell, const char *shellcmd)
{
const char *name, *ptr;
char *argv0;
log_debug("shell %s, command %s", shell, shellcmd);
ptr = strrchr(shell, '/');
if (ptr != NULL && *(ptr + 1) != '\0')
name = ptr + 1;
else
name = shell;
if (client_flags & CLIENT_LOGIN)
xasprintf(&argv0, "-%s", name);
else
xasprintf(&argv0, "%s", name);
setenv("SHELL", shell, 1);
proc_clear_signals(client_proc, 1);
setblocking(STDIN_FILENO, 1);
setblocking(STDOUT_FILENO, 1);
setblocking(STDERR_FILENO, 1);
closefrom(STDERR_FILENO + 1);
execl(shell, argv0, "-c", shellcmd, (char *) NULL);
fatal("execl failed");
}
/* Callback to handle signals in the client. */
static void
client_signal(int sig)
{
struct sigaction sigact;
int status;
if (sig == SIGCHLD)
waitpid(WAIT_ANY, &status, WNOHANG);
else if (!client_attached) {
if (sig == SIGTERM)
proc_exit(client_proc);
} else {
switch (sig) {
case SIGHUP:
client_exitreason = CLIENT_EXIT_LOST_TTY;
client_exitval = 1;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
case SIGTERM:
client_exitreason = CLIENT_EXIT_TERMINATED;
client_exitval = 1;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
case SIGWINCH:
proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
break;
case SIGCONT:
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0);
break;
}
}
}
/* Callback for client read events. */
static void
client_dispatch(struct imsg *imsg, __unused void *arg)
{
if (imsg == NULL) {
client_exitreason = CLIENT_EXIT_LOST_SERVER;
client_exitval = 1;
proc_exit(client_proc);
return;
}
if (client_attached)
client_dispatch_attached(imsg);
else
client_dispatch_wait(imsg);
}
/* Dispatch imsgs when in wait state (before MSG_READY). */
static void
client_dispatch_wait(struct imsg *imsg)
{
char *data;
ssize_t datalen;
struct msg_stdout_data stdoutdata;
struct msg_stderr_data stderrdata;
int retval;
static int pledge_applied;
/*
* "sendfd" is no longer required once all of the identify messages
* have been sent. We know the server won't send us anything until that
* point (because we don't ask it to), so we can drop "sendfd" once we
* get the first message from the server.
*/
if (!pledge_applied) {
if (pledge("stdio unix proc exec tty", NULL) != 0)
fatal("pledge failed");
pledge_applied = 1;
};
data = imsg->data;
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
switch (imsg->hdr.type) {
case MSG_EXIT:
case MSG_SHUTDOWN:
if (datalen != sizeof retval && datalen != 0)
fatalx("bad MSG_EXIT size");
if (datalen == sizeof retval) {
memcpy(&retval, data, sizeof retval);
client_exitval = retval;
}
proc_exit(client_proc);
break;
case MSG_READY:
if (datalen != 0)
fatalx("bad MSG_READY size");
event_del(&client_stdin);
client_attached = 1;
proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
break;
case MSG_STDIN:
if (datalen != 0)
fatalx("bad MSG_STDIN size");
event_add(&client_stdin, NULL);
break;
case MSG_STDOUT:
if (datalen != sizeof stdoutdata)
fatalx("bad MSG_STDOUT size");
memcpy(&stdoutdata, data, sizeof stdoutdata);
client_write(STDOUT_FILENO, stdoutdata.data,
stdoutdata.size);
break;
case MSG_STDERR:
if (datalen != sizeof stderrdata)
fatalx("bad MSG_STDERR size");
memcpy(&stderrdata, data, sizeof stderrdata);
client_write(STDERR_FILENO, stderrdata.data,
stderrdata.size);
break;
case MSG_VERSION:
if (datalen != 0)
fatalx("bad MSG_VERSION size");
fprintf(stderr, "protocol version mismatch "
"(client %d, server %u)\n", PROTOCOL_VERSION,
imsg->hdr.peerid & 0xff);
client_exitval = 1;
proc_exit(client_proc);
break;
case MSG_SHELL:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_SHELL string");
client_exec(data, shell_command);
/* NOTREACHED */
case MSG_DETACH:
case MSG_DETACHKILL:
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
case MSG_EXITED:
proc_exit(client_proc);
break;
}
}
/* Dispatch imsgs in attached state (after MSG_READY). */
static void
client_dispatch_attached(struct imsg *imsg)
{
struct sigaction sigact;
char *data;
ssize_t datalen;
data = imsg->data;
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
switch (imsg->hdr.type) {
case MSG_DETACH:
case MSG_DETACHKILL:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_DETACH string");
client_exitsession = xstrdup(data);
client_exittype = imsg->hdr.type;
if (imsg->hdr.type == MSG_DETACHKILL)
client_exitreason = CLIENT_EXIT_DETACHED_HUP;
else
client_exitreason = CLIENT_EXIT_DETACHED;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
case MSG_EXEC:
if (datalen == 0 || data[datalen - 1] != '\0' ||
strlen(data) + 1 == (size_t)datalen)
fatalx("bad MSG_EXEC string");
client_execcmd = xstrdup(data);
client_execshell = xstrdup(data + strlen(data) + 1);
client_exittype = imsg->hdr.type;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
case MSG_EXIT:
if (datalen != 0 && datalen != sizeof (int))
fatalx("bad MSG_EXIT size");
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
client_exitreason = CLIENT_EXIT_EXITED;
break;
case MSG_EXITED:
if (datalen != 0)
fatalx("bad MSG_EXITED size");
proc_exit(client_proc);
break;
case MSG_SHUTDOWN:
if (datalen != 0)
fatalx("bad MSG_SHUTDOWN size");
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
client_exitreason = CLIENT_EXIT_SERVER_EXITED;
client_exitval = 1;
break;
case MSG_SUSPEND:
if (datalen != 0)
fatalx("bad MSG_SUSPEND size");
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_DFL;
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
kill(getpid(), SIGTSTP);
break;
case MSG_LOCK:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_LOCK string");
system(data);
proc_send(client_peer, MSG_UNLOCK, -1, NULL, 0);
break;
imsg_free(&imsg);
}
}

159
clock.c Normal file
View File

@@ -0,0 +1,159 @@
/* $Id: clock.c,v 1.7 2009-09-11 14:13:52 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 <string.h>
#include <time.h>
#include "tmux.h"
const char clock_table[14][5][5] = {
{ { 1,1,1,1,1 }, /* 0 */
{ 1,0,0,0,1 },
{ 1,0,0,0,1 },
{ 1,0,0,0,1 },
{ 1,1,1,1,1 } },
{ { 0,0,0,0,1 }, /* 1 */
{ 0,0,0,0,1 },
{ 0,0,0,0,1 },
{ 0,0,0,0,1 },
{ 0,0,0,0,1 } },
{ { 1,1,1,1,1 }, /* 2 */
{ 0,0,0,0,1 },
{ 1,1,1,1,1 },
{ 1,0,0,0,0 },
{ 1,1,1,1,1 } },
{ { 1,1,1,1,1 }, /* 3 */
{ 0,0,0,0,1 },
{ 1,1,1,1,1 },
{ 0,0,0,0,1 },
{ 1,1,1,1,1 } },
{ { 1,0,0,0,1 }, /* 4 */
{ 1,0,0,0,1 },
{ 1,1,1,1,1 },
{ 0,0,0,0,1 },
{ 0,0,0,0,1 } },
{ { 1,1,1,1,1 }, /* 5 */
{ 1,0,0,0,0 },
{ 1,1,1,1,1 },
{ 0,0,0,0,1 },
{ 1,1,1,1,1 } },
{ { 1,1,1,1,1 }, /* 6 */
{ 1,0,0,0,0 },
{ 1,1,1,1,1 },
{ 1,0,0,0,1 },
{ 1,1,1,1,1 } },
{ { 1,1,1,1,1 }, /* 7 */
{ 0,0,0,0,1 },
{ 0,0,0,0,1 },
{ 0,0,0,0,1 },
{ 0,0,0,0,1 } },
{ { 1,1,1,1,1 }, /* 8 */
{ 1,0,0,0,1 },
{ 1,1,1,1,1 },
{ 1,0,0,0,1 },
{ 1,1,1,1,1 } },
{ { 1,1,1,1,1 }, /* 9 */
{ 1,0,0,0,1 },
{ 1,1,1,1,1 },
{ 0,0,0,0,1 },
{ 1,1,1,1,1 } },
{ { 0,0,0,0,0 }, /* : */
{ 0,0,1,0,0 },
{ 0,0,0,0,0 },
{ 0,0,1,0,0 },
{ 0,0,0,0,0 } },
{ { 1,1,1,1,1 }, /* A */
{ 1,0,0,0,1 },
{ 1,1,1,1,1 },
{ 1,0,0,0,1 },
{ 1,0,0,0,1 } },
{ { 1,1,1,1,1 }, /* P */
{ 1,0,0,0,1 },
{ 1,1,1,1,1 },
{ 1,0,0,0,0 },
{ 1,0,0,0,0 } },
{ { 1,0,0,0,1 }, /* M */
{ 1,1,0,1,1 },
{ 1,0,1,0,1 },
{ 1,0,0,0,1 },
{ 1,0,0,0,1 } },
};
void
clock_draw(struct screen_write_ctx *ctx, u_int colour, int style)
{
struct screen *s = ctx->s;
struct grid_cell gc;
char tim[64], *ptr;
time_t t;
u_int i, j, x, y, idx;
t = time(NULL);
if (style == 0)
strftime(tim, sizeof tim, "%l:%M %p", localtime(&t));
else
strftime(tim, sizeof tim, "%H:%M", localtime(&t));
screen_write_clearscreen(ctx);
if (screen_size_x(s) < 6 * strlen(tim) || screen_size_y(s) < 6) {
if (screen_size_x(s) >= strlen(tim) && screen_size_y(s) != 0) {
x = (screen_size_x(s) / 2) - (strlen(tim) / 2);
y = screen_size_y(s) / 2;
screen_write_cursormove(ctx, x, y);
memcpy(&gc, &grid_default_cell, sizeof gc);
colour_set_fg(&gc, colour);
screen_write_puts(ctx, &gc, "%s", tim);
}
return;
}
x = (screen_size_x(s) / 2) - 3 * strlen(tim);
y = (screen_size_y(s) / 2) - 3;
memcpy(&gc, &grid_default_cell, sizeof gc);
colour_set_bg(&gc, colour);
for (ptr = tim; *ptr != '\0'; ptr++) {
if (*ptr >= '0' && *ptr <= '9')
idx = *ptr - '0';
else if (*ptr == ':')
idx = 10;
else if (*ptr == 'A')
idx = 11;
else if (*ptr == 'P')
idx = 12;
else if (*ptr == 'M')
idx = 13;
else {
x += 6;
continue;
}
for (j = 0; j < 5; j++) {
for (i = 0; i < 5; i++) {
screen_write_cursormove(ctx, x + i, y + j);
if (clock_table[idx][j][i])
screen_write_putc(ctx, &gc, ' ');
}
}
x += 6;
}
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-attach-session.c,v 1.32 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,154 +18,89 @@
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
/*
* Attach existing session to the current terminal.
*/
static enum cmd_retval cmd_attach_session_exec(struct cmd *,
struct cmdq_item *);
int cmd_attach_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_attach_session_entry = {
.name = "attach-session",
.alias = "attach",
.args = { "c:dErt:", 0, 0 },
.usage = "[-dEr] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
/* -t is special */
.flags = CMD_STARTSERVER,
.exec = cmd_attach_session_exec
"attach-session", "attach",
"[-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
};
enum cmd_retval
cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
int rflag, const char *cflag, int Eflag)
int
cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_find_state *current = &item->shared->current;
enum cmd_find_type type;
int flags;
struct client *c = item->client, *c_loop;
struct cmd_target_data *data = self->data;
struct session *s;
struct winlink *wl;
struct window_pane *wp;
char *cause;
struct client *c;
const char *update;
char *overrides, *cause;
u_int i;
if (RB_EMPTY(&sessions)) {
cmdq_error(item, "no sessions");
return (CMD_RETURN_ERROR);
if (ARRAY_LENGTH(&sessions) == 0) {
ctx->error(ctx, "no sessions");
return (-1);
}
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (c == NULL)
return (CMD_RETURN_NORMAL);
if (server_client_check_nested(c)) {
cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force");
return (CMD_RETURN_ERROR);
}
if (ctx->cmdclient == NULL && ctx->curclient == NULL)
return (0);
if (tflag != NULL && tflag[strcspn(tflag, ":.")] != '\0') {
type = CMD_FIND_PANE;
flags = 0;
} else {
type = CMD_FIND_SESSION;
flags = CMD_FIND_PREFER_UNATTACHED;
}
if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
return (CMD_RETURN_ERROR);
s = item->target.s;
wl = item->target.wl;
wp = item->target.wp;
if (wl != NULL) {
if (wp != NULL)
window_set_active_pane(wp->window, wp);
session_set_current(s, wl);
if (wp != NULL)
cmd_find_from_winlink_pane(current, wl, wp, 0);
else
cmd_find_from_winlink(current, wl, 0);
}
if (cflag != NULL) {
free((void *)s->cwd);
s->cwd = format_single(item, cflag, c, s, wl, wp);
}
if (c->session != NULL) {
if (dflag) {
TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session != s || c == c_loop)
if (ctx->cmdclient == NULL) {
if (data->chflags & CMD_CHFLAG('d')) {
/*
* Can't use server_write_session in case attaching to
* the same session as currently attached to.
*/
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != s)
continue;
server_client_detach(c_loop, MSG_DETACH);
if (c == ctx->curclient)
continue;
server_write_client(c, MSG_DETACH, NULL, 0);
}
}
if (!Eflag)
environ_update(s->options, c->environ, s->environ);
c->session = s;
if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
ctx->curclient->session = s;
server_redraw_client(ctx->curclient);
} else {
if (server_client_open(c, &cause) != 0) {
cmdq_error(item, "open terminal failed: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) {
ctx->error(ctx, "not a terminal");
return (-1);
}
if (rflag)
c->flags |= CLIENT_READONLY;
if (dflag) {
TAILQ_FOREACH(c_loop, &clients, entry) {
if (c_loop->session != s || c == c_loop)
continue;
server_client_detach(c_loop, MSG_DETACH);
}
overrides =
options_get_string(&s->options, "terminal-overrides");
if (tty_open(&ctx->cmdclient->tty, overrides, &cause) != 0) {
ctx->error(ctx, "terminal open failed: %s", cause);
xfree(cause);
return (-1);
}
if (!Eflag)
environ_update(s->options, c->environ, s->environ);
c->session = s;
server_client_set_key_table(c, NULL);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
if (data->chflags & CMD_CHFLAG('d'))
server_write_session(s, MSG_DETACH, NULL, 0);
if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0);
notify_client("client-attached", c);
c->flags |= CLIENT_ATTACHED;
ctx->cmdclient->session = s;
server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
update = options_get_string(&s->options, "update-environment");
environ_update(update, &ctx->cmdclient->environ, &s->environ);
server_redraw_client(ctx->cmdclient);
}
recalculate_sizes();
alerts_check_session(s);
server_update_socket();
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_attach_session_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
return (cmd_attach_session(item, args_get(args, 't'),
args_has(args, 'd'), args_has(args, 'r'), args_get(args, 'c'),
args_has(args, 'E')));
return (1); /* 1 means don't tell command client to exit */
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-bind-key.c,v 1.25 2009-07-28 23:19:06 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,59 +18,184 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Bind a key to a command.
* Bind a key to a command, this recurses through cmd_*.
*/
static enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmdq_item *);
int cmd_bind_key_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);
const struct cmd_entry cmd_bind_key_entry = {
.name = "bind-key",
.alias = "bind",
int cmd_bind_key_table(struct cmd *, struct cmd_ctx *);
.args = { "cnrT:", 2, -1 },
.usage = "[-cnr] [-T key-table] key "
"command [arguments]",
struct cmd_bind_key_data {
int key;
int can_repeat;
struct cmd_list *cmdlist;
.flags = CMD_AFTERHOOK,
.exec = cmd_bind_key_exec
int command_key;
char *tablename;
char *modecmd;
};
static enum cmd_retval
cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
const struct cmd_entry cmd_bind_key_entry = {
"bind-key", "bind",
"[-cnr] [-t key-table] key command [arguments]",
0, 0,
NULL,
cmd_bind_key_parse,
cmd_bind_key_exec,
cmd_bind_key_free,
cmd_bind_key_print
};
int
cmd_bind_key_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct args *args = self->args;
char *cause;
struct cmd_list *cmdlist;
key_code key;
const char *tablename;
struct cmd_bind_key_data *data;
int opt, no_prefix = 0;
key = key_string_lookup_string(args->argv[0]);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
cmdq_error(item, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
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 ((data->cmdlist = cmd_list_parse(argc, argv, cause)) == NULL)
goto error;
}
if (args_has(args, 'T'))
tablename = args_get(args, 'T');
else if (args_has(args, 'n'))
tablename = "root";
else
tablename = "prefix";
return (0);
cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0,
&cause);
if (cmdlist == NULL) {
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
key_bindings_add(tablename, key, args_has(args, 'r'), cmdlist);
return (CMD_RETURN_NORMAL);
error:
self->entry->free(self);
return (-1);
}
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_table(struct cmd *self, struct cmd_ctx *ctx)
{
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;
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, data->modecmd);
if (cmd == MODEKEY_NONE) {
ctx->error(ctx, "unknown command: %s", data->modecmd);
return (-1);
}
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);
}
mbind = xmalloc(sizeof *mbind);
mbind->key = mtmp.key;
mbind->mode = mtmp.mode;
mbind->cmd = cmd;
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,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-break-pane.c,v 1.8 2009-08-16 19:16:27 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -26,93 +26,58 @@
* Break pane off into a window.
*/
#define BREAK_PANE_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
static enum cmd_retval cmd_break_pane_exec(struct cmd *, struct cmdq_item *);
int cmd_break_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_break_pane_entry = {
.name = "break-pane",
.alias = "breakp",
.args = { "dPF:n:s:t:", 0, 0 },
.usage = "[-dP] [-F format] [-n window-name] [-s src-pane] "
"[-t dst-window]",
.source = { 's', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
.flags = 0,
.exec = cmd_break_pane_exec
"break-pane", "breakp",
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
};
static enum cmd_retval
cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
struct client *c = cmd_find_client(item, NULL, 1);
struct winlink *wl = item->source.wl;
struct session *src_s = item->source.s;
struct session *dst_s = item->target.s;
struct window_pane *wp = item->source.wp;
struct window *w = wl->window;
char *name, *cause;
int idx = item->target.idx;
const char *template;
char *cp;
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct session *s;
struct window_pane *wp;
struct window *w;
char *cause;
int base_idx;
if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) {
cmdq_error(item, "index %d already in use", idx);
return (CMD_RETURN_ERROR);
if ((wl = cmd_find_pane(ctx, data->target, &s, &wp)) == NULL)
return (-1);
if (window_count_panes(wl->window) == 1) {
ctx->error(ctx, "can't break with only one pane");
return (-1);
}
if (window_count_panes(w) == 1) {
cmdq_error(item, "can't break with only one pane");
return (CMD_RETURN_ERROR);
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);
}
server_unzoom_window(w);
layout_close_pane(wp);
TAILQ_REMOVE(&w->panes, wp, entry);
window_lost_pane(w, wp);
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);
layout_init(w);
w = wp->window = window_create(dst_s->sx, dst_s->sy);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp;
base_idx = options_get_number(&s->options, "base-index");
wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */
if (!(data->chflags & CMD_CHFLAG('d')))
session_select(s, wl->idx);
if (!args_has(args, 'n')) {
name = default_window_name(w);
window_set_name(w, name);
free(name);
} else {
window_set_name(w, args_get(args, 'n'));
options_set_number(w->options, "automatic-rename", 0);
}
server_redraw_session(s);
layout_init(w, wp);
wp->flags |= PANE_CHANGED;
if (idx == -1)
idx = -1 - options_get_number(dst_s->options, "base-index");
wl = session_attach(dst_s, w, idx, &cause); /* can't fail */
if (!args_has(self->args, 'd')) {
session_select(dst_s, wl->idx);
cmd_find_from_session(current, dst_s, 0);
}
server_redraw_session(src_s);
if (src_s != dst_s)
server_redraw_session(dst_s);
server_status_session_group(src_s);
if (src_s != dst_s)
server_status_session_group(dst_s);
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = BREAK_PANE_TEMPLATE;
cp = format_single(item, template, c, dst_s, wl, wp);
cmdq_print(item, "%s", cp);
free(cp);
}
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,243 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Jonathan Alvarado <radobobo@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Write the entire contents of a pane to a buffer or stdout.
*/
static enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmdq_item *);
static char *cmd_capture_pane_append(char *, size_t *, char *, size_t);
static char *cmd_capture_pane_pending(struct args *, struct window_pane *,
size_t *);
static char *cmd_capture_pane_history(struct args *, struct cmdq_item *,
struct window_pane *, size_t *);
const struct cmd_entry cmd_capture_pane_entry = {
.name = "capture-pane",
.alias = "capturep",
.args = { "ab:CeE:JpPqS:t:", 0, 0 },
.usage = "[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] "
"[-S start-line]" CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_capture_pane_exec
};
const struct cmd_entry cmd_clear_history_entry = {
.name = "clear-history",
.alias = "clearhist",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_capture_pane_exec
};
static char *
cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen)
{
buf = xrealloc(buf, *len + linelen + 1);
memcpy(buf + *len, line, linelen);
*len += linelen;
return (buf);
}
static char *
cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
size_t *len)
{
struct evbuffer *pending;
char *buf, *line, tmp[5];
size_t linelen;
u_int i;
pending = input_pending(wp);
if (pending == NULL)
return (xstrdup(""));
line = EVBUFFER_DATA(pending);
linelen = EVBUFFER_LENGTH(pending);
buf = xstrdup("");
if (args_has(args, 'C')) {
for (i = 0; i < linelen; i++) {
if (line[i] >= ' ' && line[i] != '\\') {
tmp[0] = line[i];
tmp[1] = '\0';
} else
xsnprintf(tmp, sizeof tmp, "\\%03hho", line[i]);
buf = cmd_capture_pane_append(buf, len, tmp,
strlen(tmp));
}
} else
buf = cmd_capture_pane_append(buf, len, line, linelen);
return (buf);
}
static char *
cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
struct window_pane *wp, size_t *len)
{
struct grid *gd;
const struct grid_line *gl;
struct grid_cell *gc = NULL;
int n, with_codes, escape_c0, join_lines;
u_int i, sx, top, bottom, tmp;
char *cause, *buf, *line;
const char *Sflag, *Eflag;
size_t linelen;
sx = screen_size_x(&wp->base);
if (args_has(args, 'a')) {
gd = wp->saved_grid;
if (gd == NULL) {
if (!args_has(args, 'q')) {
cmdq_error(item, "no alternate screen");
return (NULL);
}
return (xstrdup(""));
}
} else
gd = wp->base.grid;
Sflag = args_get(args, 'S');
if (Sflag != NULL && strcmp(Sflag, "-") == 0)
top = 0;
else {
n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause);
if (cause != NULL) {
top = gd->hsize;
free(cause);
} else if (n < 0 && (u_int) -n > gd->hsize)
top = 0;
else
top = gd->hsize + n;
if (top > gd->hsize + gd->sy - 1)
top = gd->hsize + gd->sy - 1;
}
Eflag = args_get(args, 'E');
if (Eflag != NULL && strcmp(Eflag, "-") == 0)
bottom = gd->hsize + gd->sy - 1;
else {
n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause);
if (cause != NULL) {
bottom = gd->hsize + gd->sy - 1;
free(cause);
} else if (n < 0 && (u_int) -n > gd->hsize)
bottom = 0;
else
bottom = gd->hsize + n;
if (bottom > gd->hsize + gd->sy - 1)
bottom = gd->hsize + gd->sy - 1;
}
if (bottom < top) {
tmp = bottom;
bottom = top;
top = tmp;
}
with_codes = args_has(args, 'e');
escape_c0 = args_has(args, 'C');
join_lines = args_has(args, 'J');
buf = NULL;
for (i = top; i <= bottom; i++) {
line = grid_string_cells(gd, 0, i, sx, &gc, with_codes,
escape_c0, !join_lines);
linelen = strlen(line);
buf = cmd_capture_pane_append(buf, len, line, linelen);
gl = grid_peek_line(gd, i);
if (!join_lines || !(gl->flags & GRID_LINE_WRAPPED))
buf[(*len)++] = '\n';
free(line);
}
return (buf);
}
static enum cmd_retval
cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c;
struct window_pane *wp = item->target.wp;
char *buf, *cause;
const char *bufname;
size_t len;
if (self->entry == &cmd_clear_history_entry) {
if (wp->mode == &window_copy_mode)
window_pane_reset_mode(wp);
grid_clear_history(wp->base.grid);
return (CMD_RETURN_NORMAL);
}
len = 0;
if (args_has(args, 'P'))
buf = cmd_capture_pane_pending(args, wp, &len);
else
buf = cmd_capture_pane_history(args, item, wp, &len);
if (buf == NULL)
return (CMD_RETURN_ERROR);
if (args_has(args, 'p')) {
c = item->client;
if (c == NULL ||
(c->session != NULL && !(c->flags & CLIENT_CONTROL))) {
cmdq_error(item, "can't write to stdout");
free(buf);
return (CMD_RETURN_ERROR);
}
evbuffer_add(c->stdout_data, buf, len);
free(buf);
if (args_has(args, 'P') && len > 0)
evbuffer_add(c->stdout_data, "\n", 1);
server_client_push_stdout(c);
} else {
bufname = NULL;
if (args_has(args, 'b'))
bufname = args_get(args, 'b');
if (paste_set(buf, len, bufname, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
free(buf);
return (CMD_RETURN_ERROR);
}
}
return (CMD_RETURN_NORMAL);
}

152
cmd-choose-client.c Normal file
View File

@@ -0,0 +1,152 @@
/* $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>
*
* 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 client.
*/
int cmd_choose_client_exec(struct cmd *, struct cmd_ctx *);
void cmd_choose_client_callback(void *, int);
void cmd_choose_client_free(void *);
const struct cmd_entry cmd_choose_client_entry = {
"choose-client", NULL,
CMD_TARGET_WINDOW_USAGE " [template]",
CMD_ARG01, 0,
cmd_target_init,
cmd_target_parse,
cmd_choose_client_exec,
cmd_target_free,
cmd_target_print
};
struct cmd_choose_client_data {
struct client *client;
char *template;
};
int
cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct cmd_choose_client_data *cdata;
struct winlink *wl;
struct client *c;
u_int i, idx, cur;
if (ctx->curclient == NULL) {
ctx->error(ctx, "must be run interactively");
return (-1);
}
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (0);
cur = idx = 0;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
continue;
if (c == ctx->curclient)
cur = idx;
idx++;
window_choose_add(wl->window->active, i,
"%s: %s [%ux%u %s]%s", c->tty.path,
c->session->name, c->tty.sx, c->tty.sy,
c->tty.termname, c->tty.flags & TTY_UTF8 ? " (utf8)" : "");
}
cdata = xmalloc(sizeof *cdata);
if (data->arg != NULL)
cdata->template = xstrdup(data->arg);
else
cdata->template = xstrdup("detach-client -t '%%'");
cdata->client = ctx->curclient;
cdata->client->references++;
window_choose_ready(wl->window->active,
cur, cmd_choose_client_callback, cmd_choose_client_free, cdata);
return (0);
}
void
cmd_choose_client_callback(void *data, int idx)
{
struct cmd_choose_client_data *cdata = data;
struct client *c;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *template, *cause;
if (idx == -1)
return;
if (cdata->client->flags & CLIENT_DEAD)
return;
if ((u_int) idx > ARRAY_LENGTH(&clients) - 1)
return;
c = ARRAY_ITEM(&clients, idx);
if (c == NULL || c->session == NULL)
return;
template = cmd_template_replace(cdata->template, c->tty.path, 1);
if (cmd_string_parse(template, &cmdlist, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(c, "%s", cause);
xfree(cause);
}
xfree(template);
return;
}
xfree(template);
ctx.msgdata = NULL;
ctx.curclient = cdata->client;
ctx.error = key_bindings_error;
ctx.print = key_bindings_print;
ctx.info = key_bindings_info;
ctx.cmdclient = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist);
}
void
cmd_choose_client_free(void *data)
{
struct cmd_choose_client_data *cdata = data;
cdata->client->references--;
xfree(cdata->template);
xfree(cdata);
}

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

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

View File

@@ -1,91 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Enter a mode.
*/
static enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_choose_tree_entry = {
.name = "choose-tree",
.alias = NULL,
.args = { "F:f:NO:st:w", 0, 1 },
.usage = "[-Nsw] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_choose_tree_exec
};
const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client",
.alias = NULL,
.args = { "F:f:NO:t:", 0, 1 },
.usage = "[-N] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_choose_tree_exec
};
const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer",
.alias = NULL,
.args = { "F:f:NO:t:", 0, 1 },
.usage = "[-N] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_choose_tree_exec
};
static enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct window_pane *wp = item->target.wp;
const struct window_mode *mode;
if (self->entry == &cmd_choose_buffer_entry) {
if (paste_get_top(NULL) == NULL)
return (CMD_RETURN_NORMAL);
mode = &window_buffer_mode;
} else if (self->entry == &cmd_choose_client_entry) {
if (server_client_how_many() == 0)
return (CMD_RETURN_NORMAL);
mode = &window_client_mode;
} else
mode = &window_tree_mode;
window_pane_set_mode(wp, mode, &item->target, args);
return (CMD_RETURN_NORMAL);
}

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

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

55
cmd-clear-history.c Normal file
View File

@@ -0,0 +1,55 @@
/* $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>
*
* 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"
/*
* Clear pane history.
*/
int cmd_clear_history_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_clear_history_entry = {
"clear-history", "clearhist",
CMD_TARGET_PANE_USAGE,
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 cmd_target_data *data = self->data;
struct window_pane *wp;
struct grid *gd;
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
return (-1);
gd = wp->base.grid;
grid_move_lines(gd, 0, gd->hsize, gd->sy);
gd->hsize = 0;
return (0);
}

View File

@@ -1,5 +1,7 @@
/* $Id: cmd-clock-mode.c,v 1.6 2009-08-20 11:37:46 tcunha Exp $ */
/*
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -16,19 +18,35 @@
#include <sys/types.h>
#include <limits.h>
#include "tmux.h"
#include "compat.h"
/*
* Enter clock mode.
*/
int cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_clock_mode_entry = {
"clock-mode", NULL,
CMD_TARGET_PANE_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_clock_mode_exec,
cmd_target_free,
cmd_target_print
};
int
getptmfd(void)
cmd_clock_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
{
return (INT_MAX);
}
struct cmd_target_data *data = self->data;
struct window_pane *wp;
pid_t
fdforkpty(__unused int ptmfd, int *master, char *name, struct termios *tio,
struct winsize *ws)
{
return (forkpty(master, name, tio, ws));
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
return (-1);
window_pane_set_mode(wp, &window_clock_mode);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-command-prompt.c,v 1.25 2009-08-25 13:53:39 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -19,9 +19,7 @@
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "tmux.h"
@@ -29,181 +27,240 @@
* Prompt for command in client.
*/
static enum cmd_retval cmd_command_prompt_exec(struct cmd *,
struct cmdq_item *);
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);
static int cmd_command_prompt_callback(struct client *, void *,
const char *, int);
static 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 = {
.name = "command-prompt",
.alias = NULL,
"command-prompt", NULL,
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
};
.args = { "1iI:Np:t:", 0, 1 },
.usage = "[-1Ni] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
"[template]",
.flags = 0,
.exec = cmd_command_prompt_exec
struct cmd_command_prompt_data {
char *prompts;
char *target;
char *template;
};
struct cmd_command_prompt_cdata {
int flags;
char *inputs;
char *next_input;
char *prompts;
char *next_prompt;
char *template;
int idx;
struct client *c;
char *next_prompt;
char *prompts;
char *template;
int idx;
};
static enum cmd_retval
cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
void
cmd_command_prompt_init(struct cmd *self, int key)
{
struct args *args = self->args;
const char *inputs, *prompts;
struct cmd_command_prompt_data *data;
self->data = data = xmalloc(sizeof *data);
data->prompts = NULL;
data->target = NULL;
data->template = NULL;
switch (key) {
case ',':
data->template = xstrdup("rename-window '%%'");
break;
case '.':
data->template = xstrdup("move-window -t '%%'");
break;
case 'f':
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 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(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
if (c->prompt_string != NULL)
return (CMD_RETURN_NORMAL);
return (0);
cdata = xcalloc(1, sizeof *cdata);
cdata->inputs = NULL;
cdata->next_input = NULL;
cdata->prompts = NULL;
cdata->next_prompt = NULL;
cdata->template = NULL;
cdata = xmalloc(sizeof *cdata);
cdata->c = c;
cdata->idx = 1;
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);
status_prompt_set(c, prompt, cmd_command_prompt_callback,
cmd_command_prompt_cfree, cdata, 0);
xfree(prompt);
/* Get initial prompt input. */
if ((inputs = args_get(args, 'I')) != NULL) {
cdata->inputs = xstrdup(inputs);
cdata->next_input = cdata->inputs;
input = strsep(&cdata->next_input, ",");
}
if (args_has(args, '1'))
cdata->flags |= PROMPT_SINGLE;
else if (args_has(args, 'N'))
cdata->flags |= PROMPT_NUMERIC;
else if (args_has(args, 'i'))
cdata->flags |= PROMPT_INCREMENTAL;
status_prompt_set(c, prompt, input, cmd_command_prompt_callback,
cmd_command_prompt_free, cdata, cdata->flags);
free(prompt);
return (CMD_RETURN_NORMAL);
return (0);
}
static enum cmd_retval
cmd_command_prompt_error(struct cmdq_item *item, void *data)
void
cmd_command_prompt_free(struct cmd *self)
{
char *error = data;
struct cmd_command_prompt_data *data = self->data;
cmdq_error(item, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
if (data->prompts != NULL)
xfree(data->prompts);
if (data->target != NULL)
xfree(data->target);
if (data->template != NULL)
xfree(data->template);
xfree(data);
}
static int
cmd_command_prompt_callback(struct client *c, void *data, const char *s,
int done)
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)
{
struct cmd_command_prompt_cdata *cdata = data;
struct client *c = cdata->c;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
char *cause, *new_template, *prompt, *ptr;
char *input = NULL;
struct cmd_ctx ctx;
char *cause, *newtempl, *prompt, *ptr;
if (s == NULL)
return (0);
if (done && (cdata->flags & PROMPT_INCREMENTAL))
return (0);
new_template = cmd_template_replace(cdata->template, s, cdata->idx);
if (done) {
free(cdata->template);
cdata->template = new_template;
}
newtempl = cmd_template_replace(cdata->template, s, cdata->idx);
xfree(cdata->template);
cdata->template = newtempl;
/*
* Check if there are more prompts; if so, get its respective input
* and update the prompt data.
*/
if (done && (ptr = strsep(&cdata->next_prompt, ",")) != NULL) {
if ((ptr = strsep(&cdata->next_prompt, ",")) != NULL) {
xasprintf(&prompt, "%s ", ptr);
input = strsep(&cdata->next_input, ",");
status_prompt_update(c, prompt, input);
free(prompt);
status_prompt_update(c, prompt);
xfree(prompt);
cdata->idx++;
return (1);
}
cmdlist = cmd_string_parse(new_template, NULL, 0, &cause);
if (cmdlist == NULL) {
if (cmd_string_parse(newtempl, &cmdlist, &cause) != 0) {
if (cause != NULL) {
new_item = cmdq_get_callback(cmd_command_prompt_error,
cause);
} else
new_item = NULL;
} else {
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist);
*cause = toupper((u_char) *cause);
status_message_set(c, "%s", cause);
xfree(cause);
}
return (0);
}
if (new_item != NULL)
cmdq_append(c, new_item);
ctx.msgdata = NULL;
ctx.curclient = c;
if (!done)
free(new_template);
if (c->prompt_inputcb != cmd_command_prompt_callback)
ctx.error = key_bindings_error;
ctx.print = key_bindings_print;
ctx.info = key_bindings_info;
ctx.cmdclient = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist);
if (c->prompt_callbackfn != (void *) &cmd_command_prompt_callback)
return (1);
return (0);
}
static void
cmd_command_prompt_free(void *data)
void
cmd_command_prompt_cfree(void *data)
{
struct cmd_command_prompt_cdata *cdata = data;
free(cdata->inputs);
free(cdata->prompts);
free(cdata->template);
free(cdata);
if (cdata->prompts != NULL)
xfree(cdata->prompts);
if (cdata->template != NULL)
xfree(cdata->template);
xfree(cdata);
}

View File

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

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,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-copy-mode.c,v 1.23 2009-08-20 11:37:46 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -21,72 +21,34 @@
#include "tmux.h"
/*
* Enter copy or clock mode.
* Enter copy mode.
*/
static enum cmd_retval cmd_copy_mode_exec(struct cmd *, struct cmdq_item *);
int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_copy_mode_entry = {
.name = "copy-mode",
.alias = NULL,
.args = { "Met:u", 0, 0 },
.usage = "[-Mu] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_copy_mode_exec
"copy-mode", NULL,
"[-u] " CMD_TARGET_PANE_USAGE,
0, CMD_CHFLAG('u'),
cmd_target_init,
cmd_target_parse,
cmd_copy_mode_exec,
cmd_target_free,
NULL
};
const struct cmd_entry cmd_clock_mode_entry = {
.name = "clock-mode",
.alias = NULL,
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_copy_mode_exec
};
static enum cmd_retval
cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmdq_shared *shared = item->shared;
struct client *c = item->client;
struct session *s;
struct window_pane *wp = item->target.wp;
int flag;
struct cmd_target_data *data = self->data;
struct window_pane *wp;
if (args_has(args, 'M')) {
if ((wp = cmd_mouse_pane(&shared->mouse, &s, NULL)) == NULL)
return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
}
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
return (-1);
if (self->entry == &cmd_clock_mode_entry) {
window_pane_set_mode(wp, &window_clock_mode, NULL, NULL);
return (CMD_RETURN_NORMAL);
}
window_pane_set_mode(wp, &window_copy_mode);
if (wp->mode == &window_copy_mode && data->chflags & CMD_CHFLAG('u'))
window_copy_pageup(wp);
if (wp->mode != &window_copy_mode) {
flag = window_pane_set_mode(wp, &window_copy_mode, NULL, NULL);
if (flag != 0)
return (CMD_RETURN_NORMAL);
window_copy_init_from_pane(wp, args_has(self->args, 'e'));
}
if (args_has(args, 'M')) {
if (wp->mode != NULL && wp->mode != &window_copy_mode)
return (CMD_RETURN_NORMAL);
window_copy_start_drag(c, &shared->mouse);
}
if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
window_copy_pageup(wp, 0);
return (CMD_RETURN_NORMAL);
return (0);
}

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

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

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-detach-client.c,v 1.9 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,94 +18,35 @@
#include <sys/types.h>
#include <string.h>
#include "tmux.h"
/*
* Detach a client.
*/
static enum cmd_retval cmd_detach_client_exec(struct cmd *,
struct cmdq_item *);
int cmd_detach_client_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_detach_client_entry = {
.name = "detach-client",
.alias = "detach",
.args = { "aE:s:t:P", 0, 0 },
.usage = "[-aP] [-E shell-command] "
"[-s target-session] " CMD_TARGET_CLIENT_USAGE,
.source = { 's', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_READONLY,
.exec = cmd_detach_client_exec
"detach-client", "detach",
CMD_TARGET_CLIENT_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_detach_client_exec,
cmd_target_free,
cmd_target_print
};
const struct cmd_entry cmd_suspend_client_entry = {
.name = "suspend-client",
.alias = "suspendc",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE,
.flags = 0,
.exec = cmd_detach_client_exec
};
static enum cmd_retval
cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c, *cloop;
struct session *s;
enum msgtype msgtype;
const char *cmd = args_get(args, 'E');
struct cmd_target_data *data = self->data;
struct client *c;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
if (self->entry == &cmd_suspend_client_entry) {
server_client_suspend(c);
return (CMD_RETURN_NORMAL);
}
server_write_client(c, MSG_DETACH, NULL, 0);
if (args_has(args, 'P'))
msgtype = MSG_DETACHKILL;
else
msgtype = MSG_DETACH;
if (args_has(args, 's')) {
s = item->source.s;
if (s == NULL)
return (CMD_RETURN_NORMAL);
TAILQ_FOREACH(cloop, &clients, entry) {
if (cloop->session == s) {
if (cmd != NULL)
server_client_exec(cloop, cmd);
else
server_client_detach(cloop, msgtype);
}
}
return (CMD_RETURN_STOP);
}
if (args_has(args, 'a')) {
TAILQ_FOREACH(cloop, &clients, entry) {
if (cloop->session != NULL && cloop != c) {
if (cmd != NULL)
server_client_exec(cloop, cmd);
else
server_client_detach(cloop, msgtype);
}
}
return (CMD_RETURN_NORMAL);
}
if (cmd != NULL)
server_client_exec(c, cmd);
else
server_client_detach(c, msgtype);
return (CMD_RETURN_STOP);
return (0);
}

View File

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

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-display-panes.c,v 1.1 2009-08-31 22:30:15 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,112 +18,35 @@
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Display panes on a client.
*/
static enum cmd_retval cmd_display_panes_exec(struct cmd *,
struct cmdq_item *);
static void cmd_display_panes_callback(struct client *,
struct window_pane *);
int cmd_display_panes_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_display_panes_entry = {
.name = "display-panes",
.alias = "displayp",
.args = { "d:t:", 0, 1 },
.usage = "[-d duration] " CMD_TARGET_CLIENT_USAGE,
.flags = CMD_AFTERHOOK,
.exec = cmd_display_panes_exec
"display-panes", "displayp",
CMD_TARGET_CLIENT_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_display_panes_exec,
cmd_target_free,
cmd_target_print
};
static enum cmd_retval
cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_display_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c;
struct session *s;
u_int delay;
char *cause;
struct cmd_target_data *data = self->data;
struct client *c;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
if (c->identify_callback != NULL)
return (CMD_RETURN_NORMAL);
server_set_identify(c);
c->identify_callback = cmd_display_panes_callback;
if (args->argc != 0)
c->identify_callback_data = xstrdup(args->argv[0]);
else
c->identify_callback_data = xstrdup("select-pane -t '%%'");
s = c->session;
if (args_has(args, 'd')) {
delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "delay %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
} else
delay = options_get_number(s->options, "display-panes-time");
server_client_set_identify(c, delay);
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_display_panes_error(struct cmdq_item *item, void *data)
{
char *error = data;
cmdq_error(item, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static void
cmd_display_panes_callback(struct client *c, struct window_pane *wp)
{
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
char *template, *cmd, *expanded, *cause;
template = c->identify_callback_data;
if (wp == NULL)
goto out;
xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(template, expanded, 1);
cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);
if (cmdlist == NULL) {
if (cause != NULL) {
new_item = cmdq_get_callback(cmd_display_panes_error,
cause);
} else
new_item = NULL;
} else {
new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist);
}
if (new_item != NULL)
cmdq_append(c, new_item);
free(cmd);
free(expanded);
out:
free(c->identify_callback_data);
c->identify_callback_data = NULL;
c->identify_callback = NULL;
return (0);
}

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,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-find-window.c,v 1.13 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,8 @@
#include <sys/types.h>
#include <stdlib.h>
#include <fnmatch.h>
#include <string.h>
#include "tmux.h"
@@ -26,69 +27,136 @@
* Find window containing text.
*/
static enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmdq_item *);
int cmd_find_window_exec(struct cmd *, struct cmd_ctx *);
void cmd_find_window_callback(void *, int);
const struct cmd_entry cmd_find_window_entry = {
.name = "find-window",
.alias = "findw",
.args = { "CNt:T", 1, 1 },
.usage = "[-CNT] " CMD_TARGET_PANE_USAGE " match-string",
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_find_window_exec
"find-window", "findw",
CMD_TARGET_WINDOW_USAGE " match-string",
CMD_ARG1, 0,
cmd_target_init,
cmd_target_parse,
cmd_find_window_exec,
cmd_target_free,
cmd_target_print
};
static enum cmd_retval
cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
struct cmd_find_window_data {
u_int session;
};
int
cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args, *new_args;
struct window_pane *wp = item->target.wp;
const char *s = args->argv[0];
char *filter, *argv = { NULL };
int C, N, T;
struct cmd_target_data *data = self->data;
struct cmd_find_window_data *cdata;
struct session *s;
struct winlink *wl, *wm;
struct window *w;
struct window_pane *wp;
ARRAY_DECL(, u_int) list_idx;
ARRAY_DECL(, char *) list_ctx;
char *sres, *sctx, *searchstr;
u_int i, line;
C = args_has(args, 'C');
N = args_has(args, 'N');
T = args_has(args, 'T');
if (ctx->curclient == NULL) {
ctx->error(ctx, "must be run interactively");
return (-1);
}
s = ctx->curclient->session;
if (!C && !N && !T)
C = N = T = 1;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (C && N && T) {
xasprintf(&filter,
"#{||:"
"#{C:%s},#{||:#{m:*%s*,#{window_name}},"
"#{m:*%s*,#{pane_title}}}}",
s, s, s);
} else if (C && N) {
xasprintf(&filter,
"#{||:#{C:%s},#{m:*%s*,#{window_name}}}",
s, s);
} else if (C && T) {
xasprintf(&filter,
"#{||:#{C:%s},#{m:*%s*,#{pane_title}}}",
s, s);
} else if (N && T) {
xasprintf(&filter,
"#{||:#{m:*%s*,#{window_name}},#{m:*%s*,#{pane_title}}}",
s, s);
} else if (C)
xasprintf(&filter, "#{C:%s}", s);
else if (N)
xasprintf(&filter, "#{m:*%s*,#{window_name}}", s);
else
xasprintf(&filter, "#{m:*%s*,#{pane_title}}", s);
ARRAY_INIT(&list_idx);
ARRAY_INIT(&list_ctx);
new_args = args_parse("", 1, &argv);
args_set(new_args, 'f', filter);
xasprintf(&searchstr, "*%s*", data->arg);
RB_FOREACH(wm, winlinks, &s->windows) {
i = 0;
TAILQ_FOREACH(wp, &wm->window->panes, entry) {
i++;
window_pane_set_mode(wp, &window_tree_mode, &item->target, new_args);
if (fnmatch(searchstr, wm->window->name, 0) == 0)
sctx = xstrdup("");
else {
sres = window_pane_search(wp, data->arg, &line);
if (sres == NULL &&
fnmatch(searchstr, wp->base.title, 0) != 0)
continue;
args_free(new_args);
free(filter);
if (sres == NULL) {
xasprintf(&sctx,
"pane %u title: \"%s\"", i - 1,
wp->base.title);
} else {
xasprintf(&sctx,
"pane %u line %u: \"%s\"", i - 1,
line + 1, sres);
xfree(sres);
}
}
return (CMD_RETURN_NORMAL);
ARRAY_ADD(&list_idx, wm->idx);
ARRAY_ADD(&list_ctx, sctx);
}
}
xfree(searchstr);
if (ARRAY_LENGTH(&list_idx) == 0) {
ctx->error(ctx, "no windows matching: %s", data->arg);
ARRAY_FREE(&list_idx);
ARRAY_FREE(&list_ctx);
return (-1);
}
if (ARRAY_LENGTH(&list_idx) == 1) {
if (session_select(s, ARRAY_FIRST(&list_idx)) == 0)
server_redraw_session(s);
recalculate_sizes();
goto out;
}
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
goto out;
for (i = 0; i < ARRAY_LENGTH(&list_idx); i++) {
wm = winlink_find_by_index(
&s->windows, ARRAY_ITEM(&list_idx, i));
w = wm->window;
sctx = ARRAY_ITEM(&list_ctx, i);
window_choose_add(wl->window->active,
wm->idx, "%3d: %s [%ux%u] (%u panes) %s", wm->idx, w->name,
w->sx, w->sy, window_count_panes(w), sctx);
xfree(sctx);
}
cdata = xmalloc(sizeof *cdata);
if (session_index(s, &cdata->session) != 0)
fatalx("session not found");
window_choose_ready(
wl->window->active, 0, cmd_find_window_callback, xfree, cdata);
out:
ARRAY_FREE(&list_idx);
ARRAY_FREE(&list_ctx);
return (0);
}
void
cmd_find_window_callback(void *data, int idx)
{
struct cmd_find_window_data *cdata = data;
struct session *s;
if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) {
s = ARRAY_ITEM(&sessions, cdata->session);
if (s != NULL && session_select(s, idx) == 0)
server_redraw_session(s);
recalculate_sizes();
}
}

1312
cmd-find.c

File diff suppressed because it is too large Load Diff

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,6 +1,7 @@
/* $Id: cmd-has-session.c,v 1.14 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2010 Dagobert Michelsen
* Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,33 +18,32 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
#include "compat.h"
/*
* Cause client to report an error and exit with 1 if session doesn't exist.
*/
int cmd_has_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_has_session_entry = {
"has-session", "has",
CMD_TARGET_SESSION_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_has_session_exec,
cmd_target_free,
cmd_target_print
};
int
setenv(const char *name, const char *value, __unused int overwrite)
cmd_has_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
char *newval;
struct cmd_target_data *data = self->data;
xasprintf(&newval, "%s=%s", name, value);
return (putenv(newval));
}
if (cmd_find_session(ctx, data->target) == NULL)
return (-1);
int
unsetenv(const char *name)
{
char **envptr;
int namelen;
namelen = strlen(name);
for (envptr = environ; *envptr != NULL; envptr++) {
if (strncmp(name, *envptr, namelen) == 0 &&
((*envptr)[namelen] == '=' || (*envptr)[namelen] == '\0'))
break;
}
for (; *envptr != NULL; envptr++)
*envptr = *(envptr + 1);
return (0);
}

View File

@@ -1,8 +1,7 @@
/* $OpenBSD$ */
/* $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,176 +17,135 @@
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Executes a tmux command if a shell command returns true or false.
* Executes a tmux command if a shell command returns true.
*/
static enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmdq_item *);
static void cmd_if_shell_callback(struct job *);
static void cmd_if_shell_free(void *);
const struct cmd_entry cmd_if_shell_entry = {
.name = "if-shell",
.alias = "if",
.args = { "bFt:", 2, 3 },
.usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command "
"[command]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = 0,
.exec = cmd_if_shell_exec
};
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);
struct cmd_if_shell_data {
char *file;
u_int line;
char *cmd_if;
char *cmd_else;
struct client *client;
struct cmdq_item *item;
struct mouse_event mouse;
char *cmd;
char *sh_cmd;
};
static enum cmd_retval
cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
const struct cmd_entry cmd_if_shell_entry = {
"if-shell", "if",
"shell-command command",
0, 0,
cmd_if_shell_init,
cmd_if_shell_parse,
cmd_if_shell_exec,
cmd_if_shell_free,
cmd_if_shell_print
};
void
cmd_if_shell_init(struct cmd *self, unused int arg)
{
struct args *args = self->args;
struct cmdq_shared *shared = item->shared;
struct cmd_if_shell_data *cdata;
char *shellcmd, *cmd, *cause;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
const char *cwd;
struct cmd_if_shell_data *data;
if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
else if (s != NULL)
cwd = s->cwd;
else
cwd = NULL;
self->data = data = xmalloc(sizeof *data);
data->cmd = NULL;
data->sh_cmd = NULL;
}
shellcmd = format_single(item, args->argv[0], c, s, wl, wp);
if (args_has(args, 'F')) {
cmd = NULL;
if (*shellcmd != '0' && *shellcmd != '\0')
cmd = args->argv[1];
else if (args->argc == 3)
cmd = args->argv[2];
free(shellcmd);
if (cmd == NULL)
return (CMD_RETURN_NORMAL);
cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);
if (cmdlist == NULL) {
if (cause != NULL) {
cmdq_error(item, "%s", cause);
free(cause);
}
return (CMD_RETURN_ERROR);
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;
}
new_item = cmdq_get_command(cmdlist, NULL, &shared->mouse, 0);
cmdq_insert_after(item, new_item);
cmd_list_free(cmdlist);
return (CMD_RETURN_NORMAL);
}
argc -= optind;
argv += optind;
if (argc != 2)
goto usage;
cdata = xcalloc(1, sizeof *cdata);
if (self->file != NULL) {
cdata->file = xstrdup(self->file);
cdata->line = self->line;
}
data->sh_cmd = xstrdup(argv[0]);
data->cmd = xstrdup(argv[1]);
return (0);
cdata->cmd_if = xstrdup(args->argv[1]);
if (args->argc == 3)
cdata->cmd_else = xstrdup(args->argv[2]);
else
cdata->cmd_else = NULL;
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
cdata->client = item->client;
if (cdata->client != NULL)
cdata->client->references++;
if (!args_has(args, 'b'))
cdata->item = item;
else
cdata->item = NULL;
memcpy(&cdata->mouse, &shared->mouse, sizeof cdata->mouse);
job_run(shellcmd, s, cwd, NULL, cmd_if_shell_callback,
cmd_if_shell_free, cdata);
free(shellcmd);
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
self->entry->free(self);
return (-1);
}
static void
cmd_if_shell_callback(struct job *job)
int
cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_if_shell_data *cdata = job->data;
struct client *c = cdata->client;
struct cmd_if_shell_data *data = self->data;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
char *cause, *cmd, *file = cdata->file;
u_int line = cdata->line;
char *cause;
int ret;
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
cmd = cdata->cmd_else;
else
cmd = cdata->cmd_if;
if (cmd == NULL)
goto out;
if ((ret = system(data->sh_cmd)) < 0) {
ctx->error(ctx, "system error: %s", strerror(errno));
return (-1);
} else if (ret != 0)
return (0);
cmdlist = cmd_string_parse(cmd, file, line, &cause);
if (cmdlist == NULL) {
if (cause != NULL && cdata->item != NULL)
cmdq_error(cdata->item, "%s", cause);
free(cause);
new_item = NULL;
} else {
new_item = cmdq_get_command(cmdlist, NULL, &cdata->mouse, 0);
if (cmd_string_parse(data->cmd, &cmdlist, &cause) != 0) {
if (cause != NULL) {
ctx->error(ctx, "%s", cause);
xfree(cause);
}
return (-1);
}
if (cmd_list_exec(cmdlist, ctx) < 0) {
cmd_list_free(cmdlist);
return (-1);
}
if (new_item != NULL) {
if (cdata->item == NULL)
cmdq_append(c, new_item);
else
cmdq_insert_after(cdata->item, new_item);
}
out:
if (cdata->item != NULL)
cdata->item->flags &= ~CMDQ_WAITING;
cmd_list_free(cmdlist);
return (0);
}
static void
cmd_if_shell_free(void *data)
void
cmd_if_shell_free(struct cmd *self)
{
struct cmd_if_shell_data *cdata = data;
struct cmd_if_shell_data *data = self->data;
if (cdata->client != NULL)
server_client_unref(cdata->client);
free(cdata->cmd_else);
free(cdata->cmd_if);
free(cdata->file);
free(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,161 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2011 George Nachman <tmux@georgester.com>
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include "tmux.h"
/*
* Join or move a pane into another (like split/swap/kill).
*/
static enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_join_pane_entry = {
.name = "join-pane",
.alias = "joinp",
.args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_join_pane_exec
};
const struct cmd_entry cmd_move_pane_entry = {
.name = "move-pane",
.alias = "movep",
.args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_join_pane_exec
};
static enum cmd_retval
cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
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;
int not_same_window;
if (self->entry == &cmd_join_pane_entry)
not_same_window = 1;
else
not_same_window = 0;
dst_s = item->target.s;
dst_wl = item->target.wl;
dst_wp = item->target.wp;
dst_w = dst_wl->window;
dst_idx = dst_wl->idx;
server_unzoom_window(dst_w);
src_wl = item->source.wl;
src_wp = item->source.wp;
src_w = src_wl->window;
server_unzoom_window(src_w);
if (not_same_window && src_w == dst_w) {
cmdq_error(item, "can't join a pane to its own window");
return (CMD_RETURN_ERROR);
}
if (!not_same_window && src_wp == dst_wp) {
cmdq_error(item, "source and target panes must be different");
return (CMD_RETURN_ERROR);
}
type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT;
size = -1;
if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "size %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, 100, &cause);
if (cause != NULL) {
cmdq_error(item, "percentage %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (type == LAYOUT_TOPBOTTOM)
size = (dst_wp->sy * percentage) / 100;
else
size = (dst_wp->sx * percentage) / 100;
}
lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b'), 0);
if (lc == NULL) {
cmdq_error(item, "create pane failed: pane too small");
return (CMD_RETURN_ERROR);
}
layout_close_pane(src_wp);
window_lost_pane(src_w, src_wp);
TAILQ_REMOVE(&src_w->panes, src_wp, entry);
src_wp->window = dst_w;
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
layout_assign_pane(lc, src_wp);
recalculate_sizes();
server_redraw_window(src_w);
server_redraw_window(dst_w);
if (!args_has(args, 'd')) {
window_set_active_pane(dst_w, src_wp);
session_select(dst_s, dst_idx);
cmd_find_from_session(current, dst_s, 0);
server_redraw_session(dst_s);
} else
server_status_session(dst_s);
if (window_count_panes(src_w) == 0)
server_kill_window(src_w);
else
notify_window("window-layout-changed", src_w);
notify_window("window-layout-changed", dst_w);
return (CMD_RETURN_NORMAL);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-kill-pane.c,v 1.12 2009-07-30 20:45:20 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -26,47 +26,37 @@
* Kill pane.
*/
static enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmdq_item *);
int cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_pane_entry = {
.name = "kill-pane",
.alias = "killp",
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_kill_pane_exec
"kill-pane", "killp",
CMD_TARGET_PANE_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_kill_pane_exec,
cmd_target_free,
cmd_target_print
};
static enum cmd_retval
cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct winlink *wl = item->target.wl;
struct window_pane *loopwp, *tmpwp, *wp = item->target.wp;
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct window_pane *wp;
server_unzoom_window(wl->window);
if (args_has(self->args, 'a')) {
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
if (loopwp == wp)
continue;
layout_close_pane(loopwp);
window_remove_pane(wl->window, loopwp);
}
server_redraw_window(wl->window);
return (CMD_RETURN_NORMAL);
}
if ((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();
} else {
layout_close_pane(wp);
window_remove_pane(wl->window, wp);
server_redraw_window(wl->window);
return (0);
}
return (CMD_RETURN_NORMAL);
layout_close_pane(wp);
window_remove_pane(wl->window, wp);
server_redraw_window(wl->window);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-kill-server.c,v 1.8 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -27,35 +27,23 @@
* Kill the server and do nothing else.
*/
static enum cmd_retval cmd_kill_server_exec(struct cmd *, struct cmdq_item *);
int cmd_kill_server_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_server_entry = {
.name = "kill-server",
.alias = NULL,
.args = { "", 0, 0 },
.usage = "",
.flags = 0,
.exec = cmd_kill_server_exec
"kill-server", NULL,
"",
0, 0,
NULL,
NULL,
cmd_kill_server_exec,
NULL,
NULL
};
const struct cmd_entry cmd_start_server_entry = {
.name = "start-server",
.alias = "start",
.args = { "", 0, 0 },
.usage = "",
.flags = CMD_STARTSERVER,
.exec = cmd_kill_server_exec
};
static enum cmd_retval
cmd_kill_server_exec(struct cmd *self, __unused struct cmdq_item *item)
int
cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
{
if (self->entry == &cmd_kill_server_entry)
kill(getpid(), SIGTERM);
sigterm = 1;
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-kill-session.c,v 1.14 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -27,46 +27,40 @@
* Note this deliberately has no alias to make it hard to hit by accident.
*/
static enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmdq_item *);
int cmd_kill_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_session_entry = {
.name = "kill-session",
.alias = NULL,
.args = { "aCt:", 0, 0 },
.usage = "[-aC] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0,
.exec = cmd_kill_session_exec
"kill-session", NULL,
CMD_TARGET_SESSION_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_kill_session_exec,
cmd_target_free,
cmd_target_print
};
static enum cmd_retval
cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s, *sloop, *stmp;
struct winlink *wl;
struct cmd_target_data *data = self->data;
struct session *s;
struct client *c;
u_int i;
s = item->target.s;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (args_has(args, 'C')) {
RB_FOREACH(wl, winlinks, &s->windows) {
wl->window->flags &= ~WINDOW_ALERTFLAGS;
wl->flags &= ~WINLINK_ALERTFLAGS;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c->session == s) {
c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0);
}
server_redraw_session(s);
} else if (args_has(args, 'a')) {
RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) {
if (sloop != s) {
server_destroy_session(sloop);
session_destroy(sloop, __func__);
}
}
} else {
server_destroy_session(s);
session_destroy(s, __func__);
}
return (CMD_RETURN_NORMAL);
recalculate_sizes();
session_destroy(s);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-kill-window.c,v 1.19 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -24,58 +24,29 @@
* Destroy window.
*/
static enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmdq_item *);
int cmd_kill_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_window_entry = {
.name = "kill-window",
.alias = "killw",
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_kill_window_exec
"kill-window", "killw",
CMD_TARGET_WINDOW_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_kill_window_exec,
cmd_target_free,
cmd_target_print
};
const struct cmd_entry cmd_unlink_window_entry = {
.name = "unlink-window",
.alias = "unlinkw",
.args = { "kt:", 0, 0 },
.usage = "[-k] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_kill_window_exec
};
static enum cmd_retval
cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct winlink *wl = item->target.wl, *wl2, *wl3;
struct window *w = wl->window;
struct session *s = item->target.s;
struct cmd_target_data *data = self->data;
struct winlink *wl;
if (self->entry == &cmd_unlink_window_entry) {
if (!args_has(self->args, 'k') && !session_is_linked(s, w)) {
cmdq_error(item, "window only linked to one session");
return (CMD_RETURN_ERROR);
}
server_unlink_window(s, wl);
} else {
if (args_has(args, 'a')) {
RB_FOREACH_SAFE(wl2, winlinks, &s->windows, wl3) {
if (wl != wl2)
server_kill_window(wl2->window);
}
} else
server_kill_window(wl->window);
}
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
recalculate_sizes();
return (CMD_RETURN_NORMAL);
server_kill_window(wl->window);
return (0);
}

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

@@ -0,0 +1,58 @@
/* $Id: cmd-last-window.c,v 1.18 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 last window.
*/
int cmd_last_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_last_window_entry = {
"last-window", "last",
CMD_TARGET_SESSION_USAGE,
0, 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)
{
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);
}

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

@@ -0,0 +1,98 @@
/* $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>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Link a window into another session.
*/
int cmd_link_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_link_window_entry = {
"link-window", "linkw",
"[-dk] " CMD_SRCDST_WINDOW_USAGE,
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 cmd_srcdst_data *data = self->data;
struct session *dst;
struct winlink *wl_src, *wl_dst;
char *cause;
int idx;
if ((wl_src = cmd_find_window(ctx, data->src, NULL)) == NULL)
return (-1);
if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2)
return (-1);
wl_dst = NULL;
if (idx != -1)
wl_dst = winlink_find_by_index(&dst->windows, idx);
if (wl_dst != NULL) {
if (wl_dst->window == wl_src->window)
return (0);
if (data->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,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-list-buffers.c,v 1.12 2009-09-07 23:48:54 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -27,45 +26,53 @@
* List paste buffers.
*/
#define LIST_BUFFERS_TEMPLATE \
"#{buffer_name}: #{buffer_size} bytes: \"#{buffer_sample}\""
static enum cmd_retval cmd_list_buffers_exec(struct cmd *, struct cmdq_item *);
int cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_buffers_entry = {
.name = "list-buffers",
.alias = "lsb",
.args = { "F:", 0, 0 },
.usage = "[-F format]",
.flags = CMD_AFTERHOOK,
.exec = cmd_list_buffers_exec
"list-buffers", "lsb",
CMD_TARGET_SESSION_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_list_buffers_exec,
cmd_target_free,
cmd_target_print
};
static enum cmd_retval
cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_list_buffers_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct session *s;
struct paste_buffer *pb;
struct format_tree *ft;
char *line;
const char *template;
u_int idx;
char tmp[51 * 4 + 1];
size_t size, len;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_BUFFERS_TEMPLATE;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
pb = NULL;
while ((pb = paste_walk(pb)) != NULL) {
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults_paste_buffer(ft, pb);
idx = 0;
while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) {
size = pb->size;
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
/* Translate the first 50 characters. */
len = size;
if (len > 50)
len = 50;
strvisx(tmp, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL);
format_free(ft);
/*
* 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 (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-list-clients.c,v 1.18 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -28,62 +27,39 @@
* List all clients.
*/
#define LIST_CLIENTS_TEMPLATE \
"#{client_name}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}]" \
"#{?client_utf8, (utf8),} #{?client_readonly, (ro),}"
static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *);
int cmd_list_clients_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_clients_entry = {
.name = "list-clients",
.alias = "lsc",
.args = { "F:t:", 0, 0 },
.usage = "[-F format] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_READONLY|CMD_AFTERHOOK,
.exec = cmd_list_clients_exec
"list-clients", "lsc",
"",
0, 0,
NULL,
NULL,
cmd_list_clients_exec,
NULL,
NULL
};
static enum cmd_retval
cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_list_clients_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c;
struct session *s;
struct format_tree *ft;
const char *template;
u_int idx;
char *line;
struct client *c;
u_int i;
const char *s_utf8;
if (args_has(args, 't'))
s = item->target.s;
else
s = NULL;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_CLIENTS_TEMPLATE;
idx = 0;
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == NULL || (s != NULL && s != c->session))
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
continue;
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", idx);
format_defaults(ft, c, NULL, NULL, NULL);
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
format_free(ft);
idx++;
if (c->tty.flags & TTY_UTF8)
s_utf8 = " (utf8)";
else
s_utf8 = "";
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);
}
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,5 +1,7 @@
/* $Id: cmd-list-commands.c,v 1.5 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -16,40 +18,32 @@
#include <sys/types.h>
#include <glob.h>
#include <unistd.h>
#include "tmux.h"
#include "compat.h"
/*
* List all commands with usages.
*/
void fatal(const char *, ...);
void fatalx(const char *, ...);
int cmd_list_commands_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_commands_entry = {
"list-commands", "lscm",
"",
0, 0,
NULL,
NULL,
cmd_list_commands_exec,
NULL,
NULL
};
#ifdef HAVE_PROC_PID
int
getdtablecount(void)
cmd_list_commands_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{
char path[PATH_MAX];
glob_t g;
int n;
const struct cmd_entry **entryp;
for (entryp = cmd_table; *entryp != NULL; entryp++)
ctx->print(ctx, "%s %s", (*entryp)->name, (*entryp)->usage);
if (snprintf(path, sizeof path, "/proc/%ld/fd/*", (long)getpid()) < 0)
fatal("snprintf overflow");
switch (glob(path, 0, NULL, &g)) {
case GLOB_NOMATCH:
return (0);
case 0:
break;
default:
fatal("glob(\"%s\") failed", path);
}
n = g.gl_pathc;
globfree(&g);
return (n);
}
#else
int
getdtablecount(void)
{
return (0);
}
#endif

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-list-keys.c,v 1.20 2009-07-28 23:19:06 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -27,147 +26,100 @@
* List key bindings.
*/
static enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmdq_item *);
int cmd_list_keys_exec(struct cmd *, struct cmd_ctx *);
static enum cmd_retval cmd_list_keys_commands(struct cmd *,
struct cmdq_item *);
int cmd_list_keys_table(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_keys_entry = {
.name = "list-keys",
.alias = "lsk",
.args = { "T:", 0, 0 },
.usage = "[-T key-table]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_keys_exec
"list-keys", "lsk",
"[-t key-table]",
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_list_keys_exec,
cmd_target_free,
cmd_target_print
};
const struct cmd_entry cmd_list_commands_entry = {
.name = "list-commands",
.alias = "lscm",
.args = { "F:", 0, 0 },
.usage = "[-F format]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_keys_exec
};
static enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct key_table *table;
struct cmd_target_data *data = self->data;
struct key_binding *bd;
const char *key, *tablename, *r;
char *cp, tmp[BUFSIZ];
int repeat, width, tablewidth, keywidth;
const char *key;
char tmp[BUFSIZ], keytmp[64];
int width, keywidth;
if (self->entry == &cmd_list_commands_entry)
return (cmd_list_keys_commands(self, item));
if (data->target != NULL)
return (cmd_list_keys_table(self, ctx));
tablename = args_get(args, 'T');
if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(item, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR);
}
repeat = 0;
tablewidth = keywidth = 0;
RB_FOREACH(table, key_tables, &key_tables) {
if (tablename != NULL && strcmp(table->name, tablename) != 0)
width = 0;
SPLAY_FOREACH(bd, key_bindings, &key_bindings) {
key = key_string_lookup_key(bd->key & ~KEYC_PREFIX);
if (key == NULL)
continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
key = key_string_lookup_key(bd->key);
if (bd->flags & KEY_BINDING_REPEAT)
repeat = 1;
width = utf8_cstrwidth(table->name);
if (width > tablewidth)
tablewidth = width;
width = utf8_cstrwidth(key);
if (width > keywidth)
keywidth = width;
}
keywidth = strlen(key) + 1;
if (!(bd->key & KEYC_PREFIX))
keywidth += 2;
if (keywidth > width)
width = keywidth;
}
RB_FOREACH(table, key_tables, &key_tables) {
if (tablename != NULL && strcmp(table->name, tablename) != 0)
SPLAY_FOREACH(bd, key_bindings, &key_bindings) {
key = key_string_lookup_key(bd->key & ~KEYC_PREFIX);
if (key == NULL)
continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
key = key_string_lookup_key(bd->key);
if (!repeat)
r = "";
else if (bd->flags & KEY_BINDING_REPEAT)
r = "-r ";
else
r = " ";
xsnprintf(tmp, sizeof tmp, "%s-T ", r);
cp = utf8_padcstr(table->name, tablewidth);
strlcat(tmp, cp, sizeof tmp);
strlcat(tmp, " ", sizeof tmp);
free(cp);
cp = utf8_padcstr(key, keywidth);
strlcat(tmp, cp, sizeof tmp);
strlcat(tmp, " ", sizeof tmp);
free(cp);
cp = cmd_list_print(bd->cmdlist);
strlcat(tmp, cp, sizeof tmp);
free(cp);
cmdq_print(item, "bind-key %s", tmp);
*tmp = '\0';
cmd_list_print(bd->cmdlist, tmp, sizeof tmp);
if (!(bd->key & KEYC_PREFIX)) {
xsnprintf(keytmp, sizeof keytmp, "[%s]", key);
key = keytmp;
}
ctx->print(ctx, "%*s: %s", width, key, tmp);
}
return (CMD_RETURN_NORMAL);
return (0);
}
static enum cmd_retval
cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
int
cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
const struct cmd_entry **entryp;
const struct cmd_entry *entry;
struct format_tree *ft;
const char *template, *s;
char *line;
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;
if ((template = args_get(args, 'F')) == NULL) {
template = "#{command_list_name}"
"#{?command_list_alias, (#{command_list_alias}),} "
"#{command_list_usage}";
if ((mtab = mode_key_findtable(data->target)) == NULL) {
ctx->error(ctx, "unknown key table: %s", data->target);
return (-1);
}
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, NULL, NULL, NULL, NULL);
width = 0;
SPLAY_FOREACH(mbind, mode_key_tree, mtab->tree) {
key = key_string_lookup_key(mbind->key);
if (key == NULL)
continue;
for (entryp = cmd_table; *entryp != NULL; entryp++) {
entry = *entryp;
format_add(ft, "command_list_name", "%s", entry->name);
if (entry->alias != NULL)
s = entry->alias;
else
s = "";
format_add(ft, "command_list_alias", "%s", s);
if (entry->usage != NULL)
s = entry->usage;
else
s = "";
format_add(ft, "command_list_usage", "%s", s);
line = format_expand(ft, template);
if (*line != '\0')
cmdq_print(item, "%s", line);
free(line);
keywidth = strlen(key) + 1;
if (keywidth > width)
width = keywidth;
}
format_free(ft);
return (CMD_RETURN_NORMAL);
SPLAY_FOREACH(mbind, mode_key_tree, mtab->tree) {
key = key_string_lookup_key(mbind->key);
if (key == NULL)
continue;
mode = "";
if (mbind->mode != 0)
mode = "(command mode) ";
cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd);
if (cmdstr != NULL)
ctx->print(ctx, "%*s: %s%s", width, key, mode, cmdstr);
}
return (0);
}

View File

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

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-list-sessions.c,v 1.21 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -28,54 +27,39 @@
* List all sessions.
*/
#define LIST_SESSIONS_TEMPLATE \
"#{session_name}: #{session_windows} windows " \
"(created #{t:session_created}) " \
"[#{session_width}x#{session_height}]" \
"#{?session_grouped, (group ,}" \
"#{session_group}#{?session_grouped,),}" \
"#{?session_attached, (attached),}"
static enum cmd_retval cmd_list_sessions_exec(struct cmd *,
struct cmdq_item *);
int cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_sessions_entry = {
.name = "list-sessions",
.alias = "ls",
.args = { "F:", 0, 0 },
.usage = "[-F format]",
.flags = CMD_AFTERHOOK,
.exec = cmd_list_sessions_exec
"list-sessions", "ls", "",
0, 0,
NULL,
NULL,
cmd_list_sessions_exec,
NULL,
NULL
};
static enum cmd_retval
cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s;
u_int n;
struct format_tree *ft;
const char *template;
char *line;
struct session *s;
char *tim;
u_int i;
time_t t;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_SESSIONS_TEMPLATE;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
n = 0;
RB_FOREACH(s, sessions, &sessions) {
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, NULL, NULL);
t = s->tv.tv_sec;
tim = ctime(&t);
*strchr(tim, '\n') = '\0';
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
format_free(ft);
n++;
ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s",
s->name, winlink_count(&s->windows), tim, s->sx, s->sy,
s->flags & SESSION_UNATTACHED ? "" : " (attached)");
}
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-list-windows.c,v 1.40 2009-08-09 17:28:23 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include "tmux.h"
@@ -27,93 +26,62 @@
* List windows on given session.
*/
#define LIST_WINDOWS_TEMPLATE \
"#{window_index}: #{window_name}#{window_flags} " \
"(#{window_panes} panes) " \
"[#{window_width}x#{window_height}] " \
"[layout #{window_layout}] #{window_id}" \
"#{?window_active, (active),}";
#define LIST_WINDOWS_WITH_SESSION_TEMPLATE \
"#{session_name}:" \
"#{window_index}: #{window_name}#{window_flags} " \
"(#{window_panes} panes) " \
"[#{window_width}x#{window_height}] "
static enum cmd_retval cmd_list_windows_exec(struct cmd *, struct cmdq_item *);
static void cmd_list_windows_server(struct cmd *, struct cmdq_item *);
static void cmd_list_windows_session(struct cmd *, struct session *,
struct cmdq_item *, int);
int cmd_list_windows_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_windows_entry = {
.name = "list-windows",
.alias = "lsw",
.args = { "F:at:", 0, 0 },
.usage = "[-a] [-F format] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_list_windows_exec
"list-windows", "lsw",
CMD_TARGET_SESSION_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_list_windows_exec,
cmd_target_free,
cmd_target_print
};
static enum cmd_retval
cmd_list_windows_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
if (args_has(args, 'a'))
cmd_list_windows_server(self, item);
else
cmd_list_windows_session(self, item->target.s, item, 0);
return (CMD_RETURN_NORMAL);
}
static void
cmd_list_windows_server(struct cmd *self, struct cmdq_item *item)
{
struct session *s;
RB_FOREACH(s, sessions, &sessions)
cmd_list_windows_session(self, s, item, 1);
}
static void
cmd_list_windows_session(struct cmd *self, struct session *s,
struct cmdq_item *item, int type)
{
struct args *args = self->args;
struct cmd_target_data *data = self->data;
struct session *s;
struct winlink *wl;
u_int n;
struct format_tree *ft;
const char *template;
char *line;
struct window *w;
struct window_pane *wp;
struct grid *gd;
struct grid_line *gl;
u_int i;
unsigned long long size;
const char *name;
template = args_get(args, 'F');
if (template == NULL) {
switch (type) {
case 0:
template = LIST_WINDOWS_TEMPLATE;
break;
case 1:
template = LIST_WINDOWS_WITH_SESSION_TEMPLATE;
break;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
RB_FOREACH(wl, winlinks, &s->windows) {
w = wl->window;
ctx->print(ctx,
"%3d: %s [%ux%u]", wl->idx, w->name, w->sx, w->sy);
TAILQ_FOREACH(wp, &w->panes, entry) {
gd = wp->base.grid;
size = 0;
for (i = 0; i < gd->hsize; i++) {
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);
}
}
n = 0;
RB_FOREACH(wl, winlinks, &s->windows) {
ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, NULL);
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
format_free(ft);
n++;
}
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-list.c,v 1.6 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,109 +18,102 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
struct cmd_list *
cmd_list_parse(int argc, char **argv, const char *file, u_int line,
char **cause)
cmd_list_parse(int argc, char **argv, char **cause)
{
struct cmd_list *cmdlist;
struct cmd *cmd;
int i, lastsplit;
size_t arglen, new_argc;
char **copy_argv, **new_argv;
char **new_argv;
copy_argv = cmd_copy_argv(argc, argv);
cmdlist = xcalloc(1, sizeof *cmdlist);
cmdlist->references = 1;
TAILQ_INIT(&cmdlist->list);
cmdlist = xmalloc(sizeof *cmdlist);
TAILQ_INIT(cmdlist);
lastsplit = 0;
for (i = 0; i < argc; i++) {
arglen = strlen(copy_argv[i]);
if (arglen == 0 || copy_argv[i][arglen - 1] != ';')
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, file, line, cause);
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,
file, line, 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);
}
int
cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx)
{
struct cmd *cmd;
int n;
TAILQ_FOREACH(cmd, cmdlist, qentry) {
if ((n = cmd_exec(cmd, ctx)) != 0)
return (n);
}
return (0);
}
void
cmd_list_free(struct cmd_list *cmdlist)
{
struct cmd *cmd, *cmd1;
struct cmd *cmd;
if (--cmdlist->references != 0)
return;
TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) {
TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
args_free(cmd->args);
free(cmd->file);
free(cmd);
while (!TAILQ_EMPTY(cmdlist)) {
cmd = TAILQ_FIRST(cmdlist);
TAILQ_REMOVE(cmdlist, cmd, qentry);
cmd_free(cmd);
}
free(cmdlist);
xfree(cmdlist);
}
char *
cmd_list_print(struct cmd_list *cmdlist)
size_t
cmd_list_print(struct cmd_list *cmdlist, char *buf, size_t len)
{
struct cmd *cmd;
char *buf, *this;
size_t len;
size_t off;
len = 1;
buf = xcalloc(1, len);
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
this = cmd_print(cmd);
len += strlen(this) + 3;
buf = xrealloc(buf, len);
strlcat(buf, this, len);
off = 0;
TAILQ_FOREACH(cmd, cmdlist, qentry) {
if (off >= len)
break;
off += cmd_print(cmd, buf + off, len - off);
if (off >= len)
break;
if (TAILQ_NEXT(cmd, qentry) != NULL)
strlcat(buf, " ; ", len);
free(this);
off += xsnprintf(buf + off, len - off, " ; ");
}
return (buf);
return (off);
}

View File

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

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-lock-server.c,v 1.6 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,65 +18,33 @@
#include <sys/types.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
/*
* Lock commands.
* Lock server.
*/
static enum cmd_retval cmd_lock_server_exec(struct cmd *, struct cmdq_item *);
int cmd_lock_server_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_lock_server_entry = {
.name = "lock-server",
.alias = "lock",
.args = { "", 0, 0 },
.usage = "",
.flags = CMD_AFTERHOOK,
.exec = cmd_lock_server_exec
"lock-server", "lock",
"",
0, 0,
NULL,
NULL,
cmd_lock_server_exec,
NULL,
NULL,
};
const struct cmd_entry cmd_lock_session_entry = {
.name = "lock-session",
.alias = "locks",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_lock_server_exec
};
const struct cmd_entry cmd_lock_client_entry = {
.name = "lock-client",
.alias = "lockc",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE,
.flags = CMD_AFTERHOOK,
.exec = cmd_lock_server_exec
};
static enum cmd_retval
cmd_lock_server_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_lock_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c;
server_lock();
if (self->entry == &cmd_lock_server_entry)
server_lock();
else if (self->entry == &cmd_lock_session_entry)
server_lock_session(item->target.s);
else {
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
server_lock_client(c);
}
recalculate_sizes();
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-move-window.c,v 1.9 2009-08-16 19:16:27 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -26,93 +26,87 @@
* Move a window.
*/
static enum cmd_retval cmd_move_window_exec(struct cmd *, struct cmdq_item *);
int cmd_move_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_move_window_entry = {
.name = "move-window",
.alias = "movew",
.args = { "adkrs:t:", 0, 0 },
.usage = "[-dkr] " CMD_SRCDST_WINDOW_USAGE,
.source = { 's', CMD_FIND_WINDOW, 0 },
/* -t is special */
.flags = 0,
.exec = cmd_move_window_exec
"move-window", "movew",
"[-dk] " CMD_SRCDST_WINDOW_USAGE,
0, CMD_CHFLAG('d')|CMD_CHFLAG('k'),
cmd_srcdst_init,
cmd_srcdst_parse,
cmd_move_window_exec,
cmd_srcdst_free,
cmd_srcdst_print
};
const struct cmd_entry cmd_link_window_entry = {
.name = "link-window",
.alias = "linkw",
.args = { "adks:t:", 0, 0 },
.usage = "[-dk] " CMD_SRCDST_WINDOW_USAGE,
.source = { 's', CMD_FIND_WINDOW, 0 },
/* -t is special */
.flags = 0,
.exec = cmd_move_window_exec
};
static enum cmd_retval
cmd_move_window_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
const char *tflag = args_get(args, 't');
struct session *src;
struct session *dst;
struct winlink *wl;
char *cause;
int idx, kflag, dflag, sflag;
struct cmd_srcdst_data *data = self->data;
struct session *src, *dst;
struct winlink *wl_src, *wl_dst;
struct client *c;
u_int i;
int destroyed, idx;
char *cause;
if (args_has(args, 'r')) {
if (cmd_find_target(&item->target, item, tflag,
CMD_FIND_SESSION, CMD_FIND_QUIET) != 0)
return (CMD_RETURN_ERROR);
if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL)
return (-1);
if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2)
return (-1);
session_renumber_windows(item->target.s);
recalculate_sizes();
server_status_session(item->target.s);
wl_dst = NULL;
if (idx != -1)
wl_dst = winlink_find_by_index(&dst->windows, idx);
if (wl_dst != NULL) {
if (wl_dst->window == wl_src->window)
return (0);
return (CMD_RETURN_NORMAL);
}
if (cmd_find_target(&item->target, item, tflag, CMD_FIND_WINDOW,
CMD_FIND_WINDOW_INDEX) != 0)
return (CMD_RETURN_ERROR);
src = item->source.s;
dst = item->target.s;
wl = item->source.wl;
idx = item->target.idx;
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);
kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd');
sflag = args_has(self->args, 's');
if (args_has(self->args, 'a')) {
if ((idx = winlink_shuffle_up(dst, dst->curw)) == -1)
return (CMD_RETURN_ERROR);
/* Force select/redraw if current. */
if (wl_dst == dst->curw) {
data->chflags &= ~CMD_CHFLAG('d');
dst->curw = NULL;
}
}
}
if (server_link_window(src, wl, dst, idx, kflag, !dflag,
&cause) != 0) {
cmdq_error(item, "can't link window: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
if (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);
}
if (self->entry == &cmd_move_window_entry)
server_unlink_window(src, wl);
/*
* Renumber the winlinks in the src session only, the destination
* session already has the correct winlink id to us, either
* automatically or specified by -s.
*/
if (!sflag && options_get_number(src->options, "renumber-windows"))
session_renumber_windows(src);
destroyed = session_detach(src, wl_src);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != src)
continue;
if (destroyed) {
c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0);
} else
server_redraw_client(c);
}
if (data->chflags & CMD_CHFLAG('d'))
server_status_session(dst);
else {
session_select(dst, wl_dst->idx);
server_redraw_session(dst);
}
recalculate_sizes();
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-new-session.c,v 1.66 2009-09-16 12:36:27 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,9 +18,6 @@
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
@@ -31,310 +28,264 @@
* Create a new session and attach to the current terminal unless -d is given.
*/
#define NEW_SESSION_TEMPLATE "#{session_name}:"
int cmd_new_session_parse(struct cmd *, int, char **, char **);
int cmd_new_session_exec(struct cmd *, struct cmd_ctx *);
void cmd_new_session_free(struct cmd *);
void cmd_new_session_init(struct cmd *, int);
size_t cmd_new_session_print(struct cmd *, char *, size_t);
static enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmdq_item *);
struct cmd_new_session_data {
char *newname;
char *winname;
char *cmd;
int flag_detached;
};
const struct cmd_entry cmd_new_session_entry = {
.name = "new-session",
.alias = "new",
.args = { "Ac:dDEF:n:Ps:t:x:y:", 0, -1 },
.usage = "[-AdDEP] [-c start-directory] [-F format] [-n window-name] "
"[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
"[-y height] [command]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_STARTSERVER,
.exec = cmd_new_session_exec
"new-session", "new",
"[-d] [-n window-name] [-s session-name] [command]",
CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, 0,
cmd_new_session_init,
cmd_new_session_parse,
cmd_new_session_exec,
cmd_new_session_free,
cmd_new_session_print
};
const struct cmd_entry cmd_has_session_entry = {
.name = "has-session",
.alias = "has",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0,
.exec = cmd_new_session_exec
};
static enum cmd_retval
cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
void
cmd_new_session_init(struct cmd *self, unused int arg)
{
struct args *args = self->args;
struct client *c = item->client;
struct session *s, *as, *groupwith;
struct window *w;
struct environ *env;
struct termios tio, *tiop;
struct session_group *sg;
const char *newname, *errstr, *template, *group, *prefix;
const char *path, *cmd, *cwd;
char **argv, *cause, *cp, *to_free = NULL;
int detached, already_attached, idx, argc;
int is_control = 0;
u_int sx, sy;
struct environ_entry *envent;
struct cmd_find_state fs;
struct cmd_new_session_data *data;
if (self->entry == &cmd_has_session_entry) {
/*
* cmd_find_target() will fail if the session cannot be found,
* so always return success here.
*/
return (CMD_RETURN_NORMAL);
}
self->data = data = xmalloc(sizeof *data);
data->flag_detached = 0;
data->newname = NULL;
data->winname = NULL;
data->cmd = NULL;
}
if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) {
cmdq_error(item, "command or window name given with target");
return (CMD_RETURN_ERROR);
}
int
cmd_new_session_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_new_session_data *data;
int opt;
newname = args_get(args, 's');
if (newname != NULL) {
if (!session_check_name(newname)) {
cmdq_error(item, "bad session name: %s", newname);
return (CMD_RETURN_ERROR);
}
if ((as = session_find(newname)) != NULL) {
if (args_has(args, 'A')) {
return (cmd_attach_session(item,
newname, args_has(args, 'D'),
0, NULL, args_has(args, 'E')));
}
cmdq_error(item, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR);
self->entry->init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "ds:n:")) != -1) {
switch (opt) {
case 'd':
data->flag_detached = 1;
break;
case 's':
if (data->newname == NULL)
data->newname = xstrdup(optarg);
break;
case 'n':
if (data->winname == NULL)
data->winname = xstrdup(optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (argc != 0 && argc != 1)
goto usage;
/* Is this going to be part of a session group? */
group = args_get(args, 't');
if (group != NULL) {
groupwith = item->target.s;
if (groupwith == NULL) {
if (!session_check_name(group)) {
cmdq_error(item, "bad group name: %s", group);
goto error;
}
sg = session_group_find(group);
} else
sg = session_group_contains(groupwith);
if (sg != NULL)
prefix = sg->name;
else if (groupwith != NULL)
prefix = groupwith->name;
else
prefix = group;
} else {
groupwith = NULL;
sg = NULL;
prefix = NULL;
if (argc == 1)
data->cmd = xstrdup(argv[0]);
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
int
cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_new_session_data *data = self->data;
struct 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;
if (data->newname != NULL && session_find(data->newname) != NULL) {
ctx->error(ctx, "duplicate session: %s", data->newname);
return (-1);
}
/* Set -d if no client. */
detached = args_has(args, 'd');
if (c == NULL)
detached = 1;
else if (c->flags & CLIENT_CONTROL)
is_control = 1;
/* Is this client already attached? */
already_attached = 0;
if (c != NULL && c->session != NULL)
already_attached = 1;
/* Get the new session working directory. */
if (args_has(args, 'c')) {
cwd = args_get(args, 'c');
to_free = format_single(item, cwd, c, NULL, NULL, NULL);
cwd = to_free;
} else if (c != NULL && c->session == NULL && c->cwd != NULL)
cwd = c->cwd;
else
cwd = ".";
/*
* If this is a new client, check for nesting and save the termios
* settings (part of which is used for new windows in this session).
* There are three cases:
*
* tcgetattr() is used rather than using tty.tio since if the client is
* detached, tty_open won't be called. It must be done before opening
* the terminal as that calls tcsetattr() to prepare for tmux taking
* over.
* 1. If cmdclient is non-NULL, new-session has been called from the
* command-line - cmdclient is to become a new attached, interactive
* client. Unless -d is given, the terminal must be opened and then
* the client sent MSG_READY.
*
* 2. If cmdclient is NULL, new-session has been called from an
* existing client (such as a key binding).
*
* 3. Both are NULL, the command was in the configuration file. Treat
* this as if -d was given even if it was not.
*
* In all cases, a new additional session needs to be created and
* (unless -d) set as the current session for the client.
*/
if (!detached && !already_attached && c->tty.fd != -1) {
if (server_client_check_nested(item->client)) {
cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force");
return (CMD_RETURN_ERROR);
}
if (tcgetattr(c->tty.fd, &tio) != 0)
/* Set -d if no client. */
detached = data->flag_detached;
if (ctx->cmdclient == NULL && ctx->curclient == NULL)
detached = 1;
/*
* Save the termios settings, part of which is used for new windows in
* this session.
*
* This is read again with tcgetattr() rather than using tty.tio as if
* detached, tty_open won't be called. Because of this, it must be done
* before opening the terminal as that calls tcsetattr() to prepare for
* tmux taking over.
*/
if (ctx->cmdclient != NULL && ctx->cmdclient->tty.fd != -1) {
if (tcgetattr(ctx->cmdclient->tty.fd, &tio) != 0)
fatal("tcgetattr failed");
tiop = &tio;
} else
tiop = NULL;
/* Open the terminal if necessary. */
if (!detached && !already_attached) {
if (server_client_open(c, &cause) != 0) {
cmdq_error(item, "open terminal failed: %s", cause);
free(cause);
goto error;
if (!detached && ctx->cmdclient != NULL) {
if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) {
ctx->error(ctx, "not a terminal");
return (-1);
}
overrides =
options_get_string(&global_s_options, "terminal-overrides");
if (tty_open(&ctx->cmdclient->tty, overrides, &cause) != 0) {
ctx->error(ctx, "open terminal failed: %s", cause);
xfree(cause);
return (-1);
}
}
/* Get the new session working directory. */
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
cwd = ctx->cmdclient->cwd;
else
cwd = options_get_string(&global_s_options, "default-path");
/* Find new session size. */
if (!detached) {
sx = c->tty.sx;
sy = c->tty.sy;
if (!is_control &&
sy > 0 &&
options_get_number(global_s_options, "status"))
sy--;
} else {
if (detached) {
sx = 80;
sy = 24;
} else if (ctx->cmdclient != NULL) {
sx = ctx->cmdclient->tty.sx;
sy = ctx->cmdclient->tty.sy;
} else {
sx = ctx->curclient->tty.sx;
sy = ctx->curclient->tty.sy;
}
if ((is_control || detached) && args_has(args, 'x')) {
sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "width %s", errstr);
goto error;
}
}
if ((is_control || detached) && args_has(args, 'y')) {
sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
goto error;
}
}
if (sy > 0 && options_get_number(&global_s_options, "status"))
sy--;
if (sx == 0)
sx = 1;
if (sy == 0)
sy = 1;
/* Figure out the command for the new window. */
argc = -1;
argv = NULL;
if (!args_has(args, 't') && args->argc != 0) {
argc = args->argc;
argv = args->argv;
} else if (sg == NULL && groupwith == NULL) {
cmd = options_get_string(global_s_options, "default-command");
if (cmd != NULL && *cmd != '\0') {
argc = 1;
argv = (char **)&cmd;
} else {
argc = 0;
argv = NULL;
}
}
path = NULL;
if (c != NULL && c->session == NULL)
envent = environ_find(c->environ, "PATH");
if (data->cmd != NULL)
cmd = data->cmd;
else
envent = environ_find(global_environ, "PATH");
if (envent != NULL)
path = envent->value;
cmd = options_get_string(&global_s_options, "default-command");
/* Construct the environment. */
env = environ_create();
if (c != NULL && !args_has(args, 'E'))
environ_update(global_s_options, c->environ, env);
environ_init(&env);
update = options_get_string(&global_s_options, "update-environment");
if (ctx->cmdclient != NULL)
environ_update(update, &ctx->cmdclient->environ, &env);
/* Create the new session. */
idx = -1 - options_get_number(global_s_options, "base-index");
s = session_create(prefix, newname, argc, argv, path, cwd, env, tiop,
idx, sx, sy, &cause);
environ_free(env);
idx = -1 - options_get_number(&global_s_options, "base-index");
s = session_create(
data->newname, cmd, cwd, &env, tiop, idx, sx, sy, &cause);
if (s == NULL) {
cmdq_error(item, "create session failed: %s", cause);
free(cause);
goto error;
ctx->error(ctx, "create session failed: %s", cause);
xfree(cause);
return (-1);
}
environ_free(&env);
/* Set the initial window name if one given. */
if (argc >= 0 && args_has(args, 'n')) {
if (data->winname != NULL) {
w = s->curw->window;
window_set_name(w, args_get(args, 'n'));
options_set_number(w->options, "automatic-rename", 0);
}
/*
* If a target session is given, this is to be part of a session group,
* so add it to the group and synchronize.
*/
if (group != NULL) {
if (sg == NULL) {
if (groupwith != NULL) {
sg = session_group_new(groupwith->name);
session_group_add(sg, groupwith);
} else
sg = session_group_new(group);
}
session_group_add(sg, s);
session_group_synchronize_to(s);
session_select(s, RB_MIN(winlinks, &s->windows)->idx);
xfree(w->name);
w->name = xstrdup(data->winname);
options_set_number(&w->options, "automatic-rename", 0);
}
notify_session("session-created", s);
/*
* Set the client to the new session. If a command client exists, it is
* taking this session and needs to get MSG_READY and stay around.
*/
if (!detached) {
if (!already_attached) {
if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0);
} else if (c->session != NULL)
c->last_session = c->session;
c->session = s;
if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
if (!detached) {
if (ctx->cmdclient != NULL) {
server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
ctx->cmdclient->session = s;
server_redraw_client(ctx->cmdclient);
} else {
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)
cfg_show_causes(s);
/* Print if requested. */
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = NEW_SESSION_TEMPLATE;
cp = format_single(item, template, c, s, NULL, NULL);
cmdq_print(item, "%s", cp);
free(cp);
}
if (!detached) {
c->flags |= CLIENT_ATTACHED;
cmd_find_from_session(&item->shared->current, s, 0);
}
cmd_find_from_session(&fs, s, 0);
hooks_insert(s->hooks, item, &fs, "after-new-session");
free(to_free);
return (CMD_RETURN_NORMAL);
error:
free(to_free);
return (CMD_RETURN_ERROR);
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,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-new-window.c,v 1.37 2009-08-16 19:16:27 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,11 +18,7 @@
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
@@ -30,129 +26,181 @@
* Create a new window.
*/
#define NEW_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
int cmd_new_window_parse(struct cmd *, int, char **, char **);
int cmd_new_window_exec(struct cmd *, struct cmd_ctx *);
void cmd_new_window_free(struct cmd *);
void cmd_new_window_init(struct cmd *, int);
size_t cmd_new_window_print(struct cmd *, char *, size_t);
static enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_new_window_entry = {
.name = "new-window",
.alias = "neww",
.args = { "ac:dF:kn:Pt:", 0, -1 },
.usage = "[-adkP] [-c start-directory] [-F format] [-n window-name] "
CMD_TARGET_WINDOW_USAGE " [command]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
.flags = 0,
.exec = cmd_new_window_exec
struct cmd_new_window_data {
char *target;
char *name;
char *cmd;
int flag_detached;
int flag_kill;
};
static enum cmd_retval
cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
const struct cmd_entry cmd_new_window_entry = {
"new-window", "neww",
"[-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 args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct client *c = cmd_find_client(item, NULL, 1);
int idx = item->target.idx;
const char *cmd, *path, *template, *cwd;
char **argv, *cause, *cp, *to_free = NULL;
int argc, detached;
struct environ_entry *envent;
struct cmd_find_state fs;
struct cmd_new_window_data *data;
if (args_has(args, 'a')) {
if ((idx = winlink_shuffle_up(s, wl)) == -1) {
cmdq_error(item, "no free window indexes");
return (CMD_RETURN_ERROR);
self->data = data = xmalloc(sizeof *data);
data->target = NULL;
data->name = NULL;
data->cmd = NULL;
data->flag_detached = 0;
data->flag_kill = 0;
}
int
cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_new_window_data *data;
int opt;
self->entry->init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "dkt:n:")) != -1) {
switch (opt) {
case 'd':
data->flag_detached = 1;
break;
case 'k':
data->flag_kill = 1;
break;
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
case 'n':
if (data->name == NULL)
data->name = xstrdup(optarg);
break;
default:
goto usage;
}
}
detached = args_has(args, 'd');
argc -= optind;
argv += optind;
if (argc != 0 && argc != 1)
goto usage;
if (args->argc == 0) {
cmd = options_get_string(s->options, "default-command");
if (cmd != NULL && *cmd != '\0') {
argc = 1;
argv = (char **)&cmd;
} else {
argc = 0;
argv = NULL;
}
} else {
argc = args->argc;
argv = args->argv;
}
if (argc == 1)
data->cmd = xstrdup(argv[0]);
path = NULL;
if (item->client != NULL && item->client->session == NULL)
envent = environ_find(item->client->environ, "PATH");
else
envent = environ_find(s->environ, "PATH");
if (envent != NULL)
path = envent->value;
return (0);
if (args_has(args, 'c')) {
cwd = args_get(args, 'c');
to_free = format_single(item, cwd, c, s, NULL, NULL);
cwd = to_free;
} else if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
else
cwd = s->cwd;
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
int
cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_new_window_data *data = self->data;
struct session *s;
struct winlink *wl;
char *cmd, *cwd, *cause;
int idx;
if (data == NULL)
return (0);
if ((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.
*/
notify_session_window("window-unlinked", s, wl->window);
wl->flags &= ~WINLINK_ALERTFLAGS;
winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl);
if (wl != NULL) {
if (data->flag_kill) {
/*
* Can't use session_detach as it will destroy session
* if this makes it empty.
*/
session_alert_cancel(s, wl);
winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl);
/* Force select/redraw if current. */
if (wl == s->curw) {
detached = 0;
s->curw = NULL;
/* Force select/redraw if current. */
if (wl == s->curw) {
data->flag_detached = 0;
s->curw = NULL;
}
}
}
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
cwd = ctx->cmdclient->cwd;
if (idx == -1)
idx = -1 - options_get_number(s->options, "base-index");
wl = session_new(s, args_get(args, 'n'), argc, argv, path, cwd, idx,
&cause);
idx = -1 - options_get_number(&s->options, "base-index");
wl = session_new(s, data->name, cmd, cwd, idx, &cause);
if (wl == NULL) {
cmdq_error(item, "create window failed: %s", cause);
free(cause);
goto error;
ctx->error(ctx, "create window failed: %s", cause);
xfree(cause);
return (-1);
}
if (!detached) {
if (!data->flag_detached) {
session_select(s, wl->idx);
cmd_find_from_winlink(current, wl, 0);
server_redraw_session_group(s);
server_redraw_session(s);
} else
server_status_session_group(s);
server_status_session(s);
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = NEW_WINDOW_TEMPLATE;
cp = format_single(item, template, c, s, wl, NULL);
cmdq_print(item, "%s", cp);
free(cp);
}
cmd_find_from_winlink(&fs, wl, 0);
hooks_insert(s->hooks, item, &fs, "after-new-window");
free(to_free);
return (CMD_RETURN_NORMAL);
error:
free(to_free);
return (CMD_RETURN_ERROR);
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);
}

54
cmd-next-layout.c Normal file
View File

@@ -0,0 +1,54 @@
/* $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>
*
* 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"
/*
* Switch window to next layout.
*/
int cmd_next_layout_exec(struct cmd *, struct cmd_ctx *);
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_next_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
{
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_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,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-paste-buffer.c,v 1.20 2009-09-07 23:48:54 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -27,81 +26,75 @@
* Paste paste buffer if present.
*/
static enum cmd_retval cmd_paste_buffer_exec(struct cmd *, struct cmdq_item *);
int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_paste_buffer_lf2cr(struct buffer *, const char *, size_t);
const struct cmd_entry cmd_paste_buffer_entry = {
.name = "paste-buffer",
.alias = "pasteb",
.args = { "db:prs:t:", 0, 0 },
.usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " "
CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_paste_buffer_exec
"paste-buffer", "pasteb",
"[-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
};
static enum cmd_retval
cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct window_pane *wp = item->target.wp;
struct cmd_buffer_data *data = self->data;
struct winlink *wl;
struct window_pane *wp;
struct session *s;
struct paste_buffer *pb;
const char *sepstr, *bufname, *bufdata, *bufend, *line;
size_t seplen, bufsize;
int bracket = args_has(args, 'p');
bufname = NULL;
if (args_has(args, 'b'))
bufname = args_get(args, 'b');
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
wp = wl->window->active;
if (bufname == NULL)
pb = paste_get_top(NULL);
if (data->buffer == -1)
pb = paste_get_top(&s->buffers);
else {
pb = paste_get_name(bufname);
if (pb == NULL) {
cmdq_error(item, "no buffer %s", bufname);
return (CMD_RETURN_ERROR);
if ((pb = paste_get_index(&s->buffers, data->buffer)) == NULL) {
ctx->error(ctx, "no buffer %d", data->buffer);
return (-1);
}
}
if (pb != NULL && ~wp->flags & PANE_INPUTOFF) {
sepstr = args_get(args, 's');
if (sepstr == NULL) {
if (args_has(args, 'r'))
sepstr = "\n";
else
sepstr = "\r";
}
seplen = strlen(sepstr);
if (bracket && (wp->screen->mode & MODE_BRACKETPASTE))
bufferevent_write(wp->event, "\033[200~", 6);
bufdata = paste_buffer_data(pb, &bufsize);
bufend = bufdata + bufsize;
for (;;) {
line = memchr(bufdata, '\n', bufend - bufdata);
if (line == NULL)
break;
bufferevent_write(wp->event, bufdata, line - bufdata);
bufferevent_write(wp->event, sepstr, seplen);
bufdata = line + 1;
}
if (bufdata != bufend)
bufferevent_write(wp->event, bufdata, bufend - bufdata);
if (bracket && (wp->screen->mode & MODE_BRACKETPASTE))
bufferevent_write(wp->event, "\033[201~", 6);
if (pb != NULL && *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);
}
if (pb != NULL && args_has(args, 'd'))
paste_free(pb);
/* Delete the buffer if -d. */
if (data->chflags & CMD_CHFLAG('d')) {
if (data->buffer == -1)
paste_free_top(&s->buffers);
else
paste_free_index(&s->buffers, data->buffer);
}
return (CMD_RETURN_NORMAL);
return (0);
}
/* Add bytes to a buffer but change every '\n' to '\r'. */
void
cmd_paste_buffer_lf2cr(struct buffer *b, const char *data, size_t size)
{
const char *end = data + size;
const char *lf;
while ((lf = memchr(data, '\n', end - data)) != NULL) {
if (lf != data)
buffer_write(b, data, lf - data);
buffer_write8(b, '\r');
data = lf + 1;
}
if (end != data)
buffer_write(b, data, end - data);
}

View File

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

54
cmd-previous-layout.c Normal file
View File

@@ -0,0 +1,54 @@
/* $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>
*
* 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"
/*
* Switch window to previous layout.
*/
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)
{
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,477 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "tmux.h"
/* Global command queue. */
static struct cmdq_list global_queue = TAILQ_HEAD_INITIALIZER(global_queue);
/* Get command queue name. */
static const char *
cmdq_name(struct client *c)
{
static char s[32];
if (c == NULL)
return ("<global>");
xsnprintf(s, sizeof s, "<%p>", c);
return (s);
}
/* Get command queue from client. */
static struct cmdq_list *
cmdq_get(struct client *c)
{
if (c == NULL)
return (&global_queue);
return (&c->queue);
}
/* Append an item. */
void
cmdq_append(struct client *c, struct cmdq_item *item)
{
struct cmdq_list *queue = cmdq_get(c);
struct cmdq_item *next;
do {
next = item->next;
item->next = NULL;
if (c != NULL)
c->references++;
item->client = c;
item->queue = queue;
TAILQ_INSERT_TAIL(queue, item, entry);
item = next;
} while (item != NULL);
}
/* Insert an item. */
void
cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
{
struct client *c = after->client;
struct cmdq_list *queue = after->queue;
struct cmdq_item *next;
do {
next = item->next;
item->next = NULL;
if (c != NULL)
c->references++;
item->client = c;
item->queue = queue;
if (after->next != NULL)
TAILQ_INSERT_AFTER(queue, after->next, item, entry);
else
TAILQ_INSERT_AFTER(queue, after, item, entry);
after->next = item;
item = next;
} while (item != NULL);
}
/* Remove an item. */
static void
cmdq_remove(struct cmdq_item *item)
{
if (item->shared != NULL && --item->shared->references == 0) {
if (item->shared->formats != NULL)
format_free(item->shared->formats);
free(item->shared);
}
if (item->client != NULL)
server_client_unref(item->client);
if (item->type == CMDQ_COMMAND)
cmd_list_free(item->cmdlist);
TAILQ_REMOVE(item->queue, item, entry);
free((void *)item->name);
free(item);
}
/* Set command group. */
static u_int
cmdq_next_group(void)
{
static u_int group;
return (++group);
}
/* Remove all subsequent items that match this item's group. */
static void
cmdq_remove_group(struct cmdq_item *item)
{
struct cmdq_item *this, *next;
this = TAILQ_NEXT(item, entry);
while (this != NULL) {
next = TAILQ_NEXT(this, entry);
if (this->group == item->group)
cmdq_remove(this);
this = next;
}
}
/* Get a command for the command queue. */
struct cmdq_item *
cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
struct mouse_event *m, int flags)
{
struct cmdq_item *item, *first = NULL, *last = NULL;
struct cmd *cmd;
u_int group = cmdq_next_group();
char *tmp;
struct cmdq_shared *shared;
shared = xcalloc(1, sizeof *shared);
if (current != NULL)
cmd_find_copy_state(&shared->current, current);
else
cmd_find_clear_state(&shared->current, 0);
if (m != NULL)
memcpy(&shared->mouse, m, sizeof shared->mouse);
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
xasprintf(&tmp, "command[%s]", cmd->entry->name);
item = xcalloc(1, sizeof *item);
item->name = tmp;
item->type = CMDQ_COMMAND;
item->group = group;
item->flags = flags;
item->shared = shared;
item->cmdlist = cmdlist;
item->cmd = cmd;
shared->references++;
cmdlist->references++;
if (first == NULL)
first = item;
if (last != NULL)
last->next = item;
last = item;
}
return (first);
}
/* Fill in flag for a command. */
static enum cmd_retval
cmdq_find_flag(struct cmdq_item *item, struct cmd_find_state *fs,
const struct cmd_entry_flag *flag)
{
const char *value;
if (flag->flag == 0) {
cmd_find_clear_state(fs, 0);
return (CMD_RETURN_NORMAL);
}
value = args_get(item->cmd->args, flag->flag);
if (cmd_find_target(fs, item, value, flag->type, flag->flags) != 0) {
cmd_find_clear_state(fs, 0);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
/* Fire command on command queue. */
static enum cmd_retval
cmdq_fire_command(struct cmdq_item *item)
{
struct client *c = item->client;
struct cmd *cmd = item->cmd;
const struct cmd_entry *entry = cmd->entry;
enum cmd_retval retval;
struct cmd_find_state *fsp, fs;
int flags;
flags = !!(cmd->flags & CMD_CONTROL);
cmdq_guard(item, "begin", flags);
if (item->client == NULL)
item->client = cmd_find_client(item, NULL, 1);
retval = cmdq_find_flag(item, &item->source, &entry->source);
if (retval == CMD_RETURN_ERROR)
goto out;
retval = cmdq_find_flag(item, &item->target, &entry->target);
if (retval == CMD_RETURN_ERROR)
goto out;
retval = entry->exec(cmd, item);
if (retval == CMD_RETURN_ERROR)
goto out;
if (entry->flags & CMD_AFTERHOOK) {
if (cmd_find_valid_state(&item->target))
fsp = &item->target;
else if (cmd_find_valid_state(&item->shared->current))
fsp = &item->shared->current;
else if (cmd_find_from_client(&fs, item->client, 0) == 0)
fsp = &fs;
else
goto out;
hooks_insert(fsp->s->hooks, item, fsp, "after-%s", entry->name);
}
out:
item->client = c;
if (retval == CMD_RETURN_ERROR)
cmdq_guard(item, "error", flags);
else
cmdq_guard(item, "end", flags);
return (retval);
}
/* Get a callback for the command queue. */
struct cmdq_item *
cmdq_get_callback1(const char *name, cmdq_cb cb, void *data)
{
struct cmdq_item *item;
char *tmp;
xasprintf(&tmp, "callback[%s]", name);
item = xcalloc(1, sizeof *item);
item->name = tmp;
item->type = CMDQ_CALLBACK;
item->group = 0;
item->flags = 0;
item->cb = cb;
item->data = data;
return (item);
}
/* Fire callback on callback queue. */
static enum cmd_retval
cmdq_fire_callback(struct cmdq_item *item)
{
return (item->cb(item, item->data));
}
/* Add a format to command queue. */
void
cmdq_format(struct cmdq_item *item, const char *key, const char *fmt, ...)
{
struct cmdq_shared *shared = item->shared;
va_list ap;
char *value;
va_start(ap, fmt);
xvasprintf(&value, fmt, ap);
va_end(ap);
if (shared->formats == NULL)
shared->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
format_add(shared->formats, key, "%s", value);
free(value);
}
/* Process next item on command queue. */
u_int
cmdq_next(struct client *c)
{
struct cmdq_list *queue = cmdq_get(c);
const char *name = cmdq_name(c);
struct cmdq_item *item;
enum cmd_retval retval;
u_int items = 0;
static u_int number;
if (TAILQ_EMPTY(queue)) {
log_debug("%s %s: empty", __func__, name);
return (0);
}
if (TAILQ_FIRST(queue)->flags & CMDQ_WAITING) {
log_debug("%s %s: waiting", __func__, name);
return (0);
}
log_debug("%s %s: enter", __func__, name);
for (;;) {
item = TAILQ_FIRST(queue);
if (item == NULL)
break;
log_debug("%s %s: %s (%d), flags %x", __func__, name,
item->name, item->type, item->flags);
/*
* Any item with the waiting flag set waits until an external
* event clears the flag (for example, a job - look at
* run-shell).
*/
if (item->flags & CMDQ_WAITING)
goto waiting;
/*
* Items are only fired once, once the fired flag is set, a
* waiting flag can only be cleared by an external event.
*/
if (~item->flags & CMDQ_FIRED) {
item->time = time(NULL);
item->number = ++number;
switch (item->type) {
case CMDQ_COMMAND:
retval = cmdq_fire_command(item);
/*
* If a command returns an error, remove any
* subsequent commands in the same group.
*/
if (retval == CMD_RETURN_ERROR)
cmdq_remove_group(item);
break;
case CMDQ_CALLBACK:
retval = cmdq_fire_callback(item);
break;
default:
retval = CMD_RETURN_ERROR;
break;
}
item->flags |= CMDQ_FIRED;
if (retval == CMD_RETURN_WAIT) {
item->flags |= CMDQ_WAITING;
goto waiting;
}
items++;
}
cmdq_remove(item);
}
log_debug("%s %s: exit (empty)", __func__, name);
return (items);
waiting:
log_debug("%s %s: exit (wait)", __func__, name);
return (items);
}
/* Print a guard line. */
void
cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
{
struct client *c = item->client;
if (c == NULL || !(c->flags & CLIENT_CONTROL))
return;
evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
(long)item->time, item->number, flags);
server_client_push_stdout(c);
}
/* Show message from command. */
void
cmdq_print(struct cmdq_item *item, const char *fmt, ...)
{
struct client *c = item->client;
struct window *w;
va_list ap;
char *tmp, *msg;
va_start(ap, fmt);
if (c == NULL)
/* nothing */;
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
if (~c->flags & CLIENT_UTF8) {
xvasprintf(&tmp, fmt, ap);
msg = utf8_sanitize(tmp);
free(tmp);
evbuffer_add(c->stdout_data, msg, strlen(msg));
free(msg);
} else
evbuffer_add_vprintf(c->stdout_data, fmt, ap);
evbuffer_add(c->stdout_data, "\n", 1);
server_client_push_stdout(c);
} else {
w = c->session->curw->window;
if (w->active->mode != &window_copy_mode) {
window_pane_reset_mode(w->active);
window_pane_set_mode(w->active, &window_copy_mode, NULL,
NULL);
window_copy_init_for_output(w->active);
}
window_copy_vadd(w->active, fmt, ap);
}
va_end(ap);
}
/* Show error from command. */
void
cmdq_error(struct cmdq_item *item, const char *fmt, ...)
{
struct client *c = item->client;
struct cmd *cmd = item->cmd;
va_list ap;
char *msg;
size_t msglen;
char *tmp;
va_start(ap, fmt);
msglen = xvasprintf(&msg, fmt, ap);
va_end(ap);
log_debug("%s: %s", __func__, msg);
if (c == NULL)
cfg_add_cause("%s:%u: %s", cmd->file, cmd->line, msg);
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
if (~c->flags & CLIENT_UTF8) {
tmp = msg;
msg = utf8_sanitize(tmp);
free(tmp);
msglen = strlen(msg);
}
evbuffer_add(c->stderr_data, msg, msglen);
evbuffer_add(c->stderr_data, "\n", 1);
server_client_push_stderr(c);
c->retval = 1;
} else {
*msg = toupper((u_char) *msg);
status_message_set(c, "%s", msg);
}
free(msg);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-refresh-client.c,v 1.10 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -24,59 +24,29 @@
* Refresh client.
*/
static enum cmd_retval cmd_refresh_client_exec(struct cmd *,
struct cmdq_item *);
int cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client",
.alias = "refresh",
.args = { "C:St:", 0, 0 },
.usage = "[-S] [-C size] " CMD_TARGET_CLIENT_USAGE,
.flags = CMD_AFTERHOOK,
.exec = cmd_refresh_client_exec
"refresh-client", "refresh",
CMD_TARGET_CLIENT_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_refresh_client_exec,
cmd_target_free,
cmd_target_print
};
static enum cmd_retval
cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c;
const char *size;
u_int w, h;
struct cmd_target_data *data = self->data;
struct client *c;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
if (args_has(args, 'C')) {
if ((size = args_get(args, 'C')) == NULL) {
cmdq_error(item, "missing size");
return (CMD_RETURN_ERROR);
}
if (sscanf(size, "%u,%u", &w, &h) != 2) {
cmdq_error(item, "bad size argument");
return (CMD_RETURN_ERROR);
}
if (w < PANE_MINIMUM || w > 5000 ||
h < PANE_MINIMUM || h > 5000) {
cmdq_error(item, "size too small or too big");
return (CMD_RETURN_ERROR);
}
if (!(c->flags & CLIENT_CONTROL)) {
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}
tty_set_size(&c->tty, w, h);
c->flags |= CLIENT_SIZECHANGED;
recalculate_sizes();
} else if (args_has(args, 'S')) {
c->flags |= CLIENT_STATUSFORCE;
server_status_client(c);
} else {
c->flags |= CLIENT_STATUSFORCE;
server_redraw_client(c);
}
server_redraw_client(c);
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-rename-session.c,v 1.18 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -19,7 +19,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -27,49 +26,32 @@
* Change session name.
*/
static enum cmd_retval cmd_rename_session_exec(struct cmd *,
struct cmdq_item *);
int cmd_rename_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_rename_session_entry = {
.name = "rename-session",
.alias = "rename",
.args = { "t:", 1, 1 },
.usage = CMD_TARGET_SESSION_USAGE " new-name",
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_rename_session_exec
"rename-session", "rename",
CMD_TARGET_SESSION_USAGE " new-name",
CMD_ARG1, 0,
cmd_target_init,
cmd_target_parse,
cmd_rename_session_exec,
cmd_target_free,
cmd_target_print
};
static enum cmd_retval
cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s = item->target.s;
const char *newname;
struct cmd_target_data *data = self->data;
struct session *s;
newname = args->argv[0];
if (strcmp(newname, s->name) == 0)
return (CMD_RETURN_NORMAL);
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (!session_check_name(newname)) {
cmdq_error(item, "bad session name: %s", newname);
return (CMD_RETURN_ERROR);
}
if (session_find(newname) != NULL) {
cmdq_error(item, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR);
}
RB_REMOVE(sessions, &sessions, s);
free(s->name);
s->name = xstrdup(newname);
RB_INSERT(sessions, &sessions, s);
xfree(s->name);
s->name = xstrdup(data->arg);
server_status_session(s);
notify_session("session-renamed", s);
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-rename-window.c,v 1.29 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -26,32 +26,34 @@
* Rename a window.
*/
static enum cmd_retval cmd_rename_window_exec(struct cmd *,
struct cmdq_item *);
int cmd_rename_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_rename_window_entry = {
.name = "rename-window",
.alias = "renamew",
.args = { "t:", 1, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " new-name",
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_rename_window_exec
"rename-window", "renamew",
CMD_TARGET_WINDOW_USAGE " new-name",
CMD_ARG1, 0,
cmd_target_init,
cmd_target_parse,
cmd_rename_window_exec,
cmd_target_free,
cmd_target_print
};
static enum cmd_retval
cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct winlink *wl = item->target.wl;
struct cmd_target_data *data = self->data;
struct session *s;
struct winlink *wl;
window_set_name(wl->window, args->argv[0]);
options_set_number(wl->window->options, "automatic-rename", 0);
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
server_status_window(wl->window);
xfree(wl->window->name);
wl->window->name = xstrdup(data->arg);
options_set_number(&wl->window->options, "automatic-rename", 0);
return (CMD_RETURN_NORMAL);
server_status_session(s);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-resize-pane.c,v 1.12 2009-07-30 20:45:20 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -26,160 +26,88 @@
* Increase or decrease pane size.
*/
static enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmdq_item *);
static void cmd_resize_pane_mouse_update(struct client *,
struct mouse_event *);
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 = {
.name = "resize-pane",
.alias = "resizep",
.args = { "DLMRt:Ux:y:Z", 0, 1 },
.usage = "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
"[adjustment]",
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_resize_pane_exec
"resize-pane", "resizep",
"[-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
};
static enum cmd_retval
cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
void
cmd_resize_pane_init(struct cmd *self, int key)
{
struct args *args = self->args;
struct cmdq_shared *shared = item->shared;
struct window_pane *wp = item->target.wp;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct client *c = item->client;
struct session *s = item->target.s;
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 cmd_target_data *data = self->data;
struct winlink *wl;
const char *errstr;
char *cause;
struct window_pane *wp;
u_int adjust;
int x, y;
if (args_has(args, 'M')) {
if (cmd_mouse_window(&shared->mouse, &s) == NULL)
return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update;
cmd_resize_pane_mouse_update(c, &shared->mouse);
return (CMD_RETURN_NORMAL);
}
if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL)
return (-1);
if (args_has(args, 'Z')) {
if (w->flags & WINDOW_ZOOMED)
window_unzoom(w);
else
window_zoom(wp);
server_redraw_window(w);
server_status_window(w);
return (CMD_RETURN_NORMAL);
}
server_unzoom_window(w);
if (args->argc == 0)
if (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) {
cmdq_error(item, "adjustment %s", errstr);
return (CMD_RETURN_ERROR);
ctx->error(ctx, "adjustment %s: %s", errstr, data->arg);
return (-1);
}
}
if (args_has(self->args, 'x')) {
x = args_strtonum(self->args, 'x', PANE_MINIMUM, INT_MAX,
&cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
if (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 (data->chflags & CMD_CHFLAG('U'))
adjust = -adjust;
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust);
}
if (args_has(self->args, 'y')) {
y = args_strtonum(self->args, 'y', PANE_MINIMUM, INT_MAX,
&cause);
if (cause != NULL) {
cmdq_error(item, "height %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
}
if (args_has(self->args, 'L'))
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust, 1);
else if (args_has(self->args, 'R'))
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust, 1);
else if (args_has(self->args, 'U'))
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, -adjust, 1);
else if (args_has(self->args, 'D'))
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust, 1);
server_redraw_window(wl->window);
return (CMD_RETURN_NORMAL);
}
static void
cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m)
{
struct winlink *wl;
struct window_pane *loop, *wp_x, *wp_y;
u_int y, ly, x, lx, sx, sy, ex, ey;
wl = cmd_mouse_window(m, NULL);
if (wl == NULL) {
c->tty.mouse_drag_update = NULL;
return;
}
y = m->y; x = m->x;
if (m->statusat == 0 && y > 0)
y--;
else if (m->statusat > 0 && y >= (u_int)m->statusat)
y = m->statusat - 1;
ly = m->ly; lx = m->lx;
if (m->statusat == 0 && ly > 0)
ly--;
else if (m->statusat > 0 && ly >= (u_int)m->statusat)
ly = m->statusat - 1;
wp_x = wp_y = NULL;
TAILQ_FOREACH(loop, &wl->window->panes, entry) {
if (!window_pane_visible(loop))
continue;
sx = loop->xoff;
if (sx != 0)
sx--;
ex = loop->xoff + loop->sx;
sy = loop->yoff;
if (sy != 0)
sy--;
ey = loop->yoff + loop->sy;
if ((lx == sx || lx == ex) &&
(ly >= sy && ly <= ey) &&
(wp_x == NULL || loop->sy > wp_x->sy))
wp_x = loop;
if ((ly == sy || ly == ey) &&
(lx >= sx && lx <= ex) &&
(wp_y == NULL || loop->sx > wp_y->sx))
wp_y = loop;
}
if (wp_x == NULL && wp_y == NULL) {
c->tty.mouse_drag_update = NULL;
return;
}
if (wp_x != NULL)
layout_resize_pane(wp_x, LAYOUT_LEFTRIGHT, x - lx, 0);
if (wp_y != NULL)
layout_resize_pane(wp_y, LAYOUT_TOPBOTTOM, y - ly, 0);
server_redraw_window(wl->window);
return (0);
}

View File

@@ -1,100 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2011 Marcel P. Partap <mpartap@gmx.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include "tmux.h"
/*
* Respawn a pane (restart the command). Kill existing if -k given.
*/
static enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_respawn_pane_entry = {
.name = "respawn-pane",
.alias = "respawnp",
.args = { "c:kt:", 0, -1 },
.usage = "[-c start-directory] [-k] " CMD_TARGET_PANE_USAGE
" [command]",
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_respawn_pane_exec
};
static enum cmd_retval
cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct window_pane *wp = item->target.wp;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct environ *env;
const char *path = NULL, *cp;
char *cause, *cwd = NULL;
u_int idx;
struct environ_entry *envent;
if (!args_has(self->args, 'k') && wp->fd != -1) {
if (window_pane_index(wp, &idx) != 0)
fatalx("index not found");
cmdq_error(item, "pane still active: %s:%d.%u",
s->name, wl->idx, idx);
return (CMD_RETURN_ERROR);
}
window_pane_reset_mode(wp);
screen_reinit(&wp->base);
input_init(wp);
if (item->client != NULL && item->client->session == NULL)
envent = environ_find(item->client->environ, "PATH");
else
envent = environ_find(s->environ, "PATH");
if (envent != NULL)
path = envent->value;
if ((cp = args_get(args, 'c')) != NULL)
cwd = format_single(item, cp, c, s, NULL, NULL);
env = environ_for_session(s, 0);
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, cwd, env,
s->tio, &cause) != 0) {
cmdq_error(item, "respawn pane failed: %s", cause);
free(cause);
environ_free(env);
free(cwd);
return (CMD_RETURN_ERROR);
}
environ_free(env);
free(cwd);
wp->flags |= PANE_REDRAW;
server_status_window(w);
return (CMD_RETURN_NORMAL);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-respawn-window.c,v 1.22 2009-09-16 12:36:27 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include "tmux.h"
@@ -27,85 +26,69 @@
* Respawn a window (restart the command). Kill existing if -k given.
*/
static enum cmd_retval cmd_respawn_window_exec(struct cmd *,
struct cmdq_item *);
int cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_respawn_window_entry = {
.name = "respawn-window",
.alias = "respawnw",
.args = { "c:kt:", 0, -1 },
.usage = "[-c start-directory] [-k] " CMD_TARGET_WINDOW_USAGE
" [command]",
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_respawn_window_exec
"respawn-window", "respawnw",
"[-k] " CMD_TARGET_WINDOW_USAGE " [command]",
CMD_ARG01, CMD_CHFLAG('k'),
cmd_target_init,
cmd_target_parse,
cmd_respawn_window_exec,
cmd_target_free,
cmd_target_print
};
static enum cmd_retval
cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct window *w;
struct window_pane *wp;
struct client *c = cmd_find_client(item, NULL, 1);
struct environ *env;
const char *path = NULL, *cp;
char *cause, *cwd = NULL;
struct environ_entry *envent;
struct session *s;
struct environ env;
char *cause;
if (!args_has(self->args, 'k')) {
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
w = wl->window;
if (!(data->chflags & CMD_CHFLAG('k'))) {
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd == -1)
continue;
cmdq_error(item, "window still active: %s:%d", s->name,
wl->idx);
return (CMD_RETURN_ERROR);
ctx->error(ctx,
"window still active: %s:%d", s->name, wl->idx);
return (-1);
}
}
environ_init(&env);
environ_copy(&global_environ, &env);
environ_copy(&s->environ, &env);
server_fill_environ(s, &env);
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 (item->client != NULL && item->client->session == NULL)
envent = environ_find(item->client->environ, "PATH");
else
envent = environ_find(s->environ, "PATH");
if (envent != NULL)
path = envent->value;
if ((cp = args_get(args, 'c')) != NULL)
cwd = format_single(item, cp, c, s, NULL, NULL);
env = environ_for_session(s, 0);
if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, cwd, env,
s->tio, &cause) != 0) {
cmdq_error(item, "respawn window failed: %s", cause);
free(cause);
environ_free(env);
free(cwd);
server_destroy_pane(wp, 0);
return (CMD_RETURN_ERROR);
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);
return (-1);
}
environ_free(env);
free(cwd);
layout_init(w, wp);
window_pane_reset_mode(wp);
layout_init(w);
screen_reinit(&wp->base);
input_init(wp);
window_set_active_pane(w, wp);
recalculate_sizes();
server_redraw_window(w);
return (CMD_RETURN_NORMAL);
environ_free(&env);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-rotate-window.c,v 1.9 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -24,35 +24,47 @@
* Rotate the panes in a window.
*/
static enum cmd_retval cmd_rotate_window_exec(struct cmd *,
struct cmdq_item *);
void cmd_rotate_window_init(struct cmd *, int);
int cmd_rotate_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_rotate_window_entry = {
.name = "rotate-window",
.alias = "rotatew",
.args = { "Dt:U", 0, 0 },
.usage = "[-DU] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_rotate_window_exec
"rotate-window", "rotatew",
"[-DU] " CMD_TARGET_WINDOW_USAGE,
0, CMD_CHFLAG('D')|CMD_CHFLAG('U'),
cmd_rotate_window_init,
cmd_target_parse,
cmd_rotate_window_exec,
cmd_target_free,
cmd_target_print
};
static enum cmd_retval
cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
void
cmd_rotate_window_init(struct cmd *self, int key)
{
struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct cmd_target_data *data;
cmd_target_init(self, key);
data = self->data;
if (key == ('o' | KEYC_ESCAPE))
data->chflags |= CMD_CHFLAG('D');
}
int
cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct window *w;
struct window_pane *wp, *wp2;
struct layout_cell *lc;
u_int sx, sy, xoff, yoff;
server_unzoom_window(w);
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);
@@ -78,7 +90,6 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL)
wp = TAILQ_LAST(&w->panes, window_panes);
window_set_active_pane(w, wp);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
} else {
wp = TAILQ_FIRST(&w->panes);
@@ -106,9 +117,8 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_NEXT(w->active, entry)) == NULL)
wp = TAILQ_FIRST(&w->panes);
window_set_active_pane(w, wp);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
}
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,170 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
* Copyright (c) 2009 Nicholas Marriott <nicm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Runs a command without a window.
*/
static enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmdq_item *);
static void cmd_run_shell_callback(struct job *);
static void cmd_run_shell_free(void *);
static void cmd_run_shell_print(struct job *, const char *);
const struct cmd_entry cmd_run_shell_entry = {
.name = "run-shell",
.alias = "run",
.args = { "bt:", 1, 1 },
.usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = 0,
.exec = cmd_run_shell_exec
};
struct cmd_run_shell_data {
char *cmd;
struct cmdq_item *item;
int wp_id;
};
static void
cmd_run_shell_print(struct job *job, const char *msg)
{
struct cmd_run_shell_data *cdata = job->data;
struct window_pane *wp = NULL;
struct cmd_find_state fs;
if (cdata->wp_id != -1)
wp = window_pane_find_by_id(cdata->wp_id);
if (wp == NULL) {
if (cdata->item != NULL) {
cmdq_print(cdata->item, "%s", msg);
return;
}
if (cmd_find_from_nothing(&fs, 0) != 0)
return;
wp = fs.wp;
if (wp == NULL)
return;
}
if (window_pane_set_mode(wp, &window_copy_mode, NULL, NULL) == 0)
window_copy_init_for_output(wp);
if (wp->mode == &window_copy_mode)
window_copy_add(wp, "%s", msg);
}
static enum cmd_retval
cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_run_shell_data *cdata;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
const char *cwd;
if (item->client != NULL && item->client->session == NULL)
cwd = item->client->cwd;
else if (s != NULL)
cwd = s->cwd;
else
cwd = NULL;
cdata = xcalloc(1, sizeof *cdata);
cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp);
if (args_has(args, 't') && wp != NULL)
cdata->wp_id = wp->id;
else
cdata->wp_id = -1;
if (!args_has(args, 'b'))
cdata->item = item;
job_run(cdata->cmd, s, cwd, NULL, cmd_run_shell_callback,
cmd_run_shell_free, cdata);
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
static void
cmd_run_shell_callback(struct job *job)
{
struct cmd_run_shell_data *cdata = job->data;
char *cmd = cdata->cmd, *msg, *line;
size_t size;
int retcode;
do {
if ((line = evbuffer_readline(job->event->input)) != NULL) {
cmd_run_shell_print(job, line);
free(line);
}
} while (line != NULL);
size = EVBUFFER_LENGTH(job->event->input);
if (size != 0) {
line = xmalloc(size + 1);
memcpy(line, EVBUFFER_DATA(job->event->input), size);
line[size] = '\0';
cmd_run_shell_print(job, line);
free(line);
}
msg = NULL;
if (WIFEXITED(job->status)) {
if ((retcode = WEXITSTATUS(job->status)) != 0)
xasprintf(&msg, "'%s' returned %d", cmd, retcode);
} else if (WIFSIGNALED(job->status)) {
retcode = WTERMSIG(job->status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
}
if (msg != NULL)
cmd_run_shell_print(job, msg);
free(msg);
if (cdata->item != NULL)
cdata->item->flags &= ~CMDQ_WAITING;
}
static void
cmd_run_shell_free(void *data)
{
struct cmd_run_shell_data *cdata = data;
free(cdata->cmd);
free(cdata);
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD$ */
/* $Id: cmd-save-buffer.c,v 1.8 2009-09-07 23:48:54 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -20,136 +20,69 @@
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
/*
* Saves a paste buffer to a file.
* Saves a session paste buffer to a file.
*/
static enum cmd_retval cmd_save_buffer_exec(struct cmd *, struct cmdq_item *);
int cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_save_buffer_entry = {
.name = "save-buffer",
.alias = "saveb",
.args = { "ab:", 1, 1 },
.usage = "[-a] " CMD_BUFFER_USAGE " path",
.flags = CMD_AFTERHOOK,
.exec = cmd_save_buffer_exec
"save-buffer", "saveb",
"[-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
};
const struct cmd_entry cmd_show_buffer_entry = {
.name = "show-buffer",
.alias = "showb",
.args = { "b:", 0, 0 },
.usage = CMD_BUFFER_USAGE,
.flags = CMD_AFTERHOOK,
.exec = cmd_save_buffer_exec
};
static enum cmd_retval
cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct client *c = item->client;
struct cmd_buffer_data *data = self->data;
struct session *s;
struct paste_buffer *pb;
const char *path, *bufname, *bufdata, *start, *end;
const char *flags;
char *msg, *file;
size_t size, used, msglen, bufsize;
mode_t mask;
FILE *f;
if (!args_has(args, 'b')) {
if ((pb = paste_get_top(NULL)) == NULL) {
cmdq_error(item, "no buffers");
return (CMD_RETURN_ERROR);
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (data->buffer == -1) {
if ((pb = paste_get_top(&s->buffers)) == NULL) {
ctx->error(ctx, "no buffers");
return (-1);
}
} else {
bufname = args_get(args, 'b');
pb = paste_get_name(bufname);
if (pb == NULL) {
cmdq_error(item, "no buffer %s", bufname);
return (CMD_RETURN_ERROR);
if ((pb = paste_get_index(&s->buffers, data->buffer)) == NULL) {
ctx->error(ctx, "no buffer %d", data->buffer);
return (-1);
}
}
bufdata = paste_buffer_data(pb, &bufsize);
if (self->entry == &cmd_show_buffer_entry)
path = "-";
mask = umask(S_IRWXG | S_IRWXO);
if (data->chflags & CMD_CHFLAG('a'))
f = fopen(data->arg, "ab");
else
path = args->argv[0];
if (strcmp(path, "-") == 0) {
if (c == NULL) {
cmdq_error(item, "can't write to stdout");
return (CMD_RETURN_ERROR);
}
if (c->session == NULL || (c->flags & CLIENT_CONTROL))
goto do_stdout;
goto do_print;
}
flags = "wb";
if (args_has(self->args, 'a'))
flags = "ab";
file = server_client_get_path(c, path);
f = fopen(file, flags);
f = fopen(data->arg, "wb");
if (f == NULL) {
cmdq_error(item, "%s: %s", file, strerror(errno));
free(file);
return (CMD_RETURN_ERROR);
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1);
}
if (fwrite(bufdata, 1, bufsize, f) != bufsize) {
cmdq_error(item, "%s: write error", file);
fclose(f);
free(file);
return (CMD_RETURN_ERROR);
if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
ctx->error(ctx, "%s: fwrite error", data->arg);
fclose(f);
return (-1);
}
fclose(f);
free(file);
umask(mask);
return (CMD_RETURN_NORMAL);
do_stdout:
evbuffer_add(c->stdout_data, bufdata, bufsize);
server_client_push_stdout(c);
return (CMD_RETURN_NORMAL);
do_print:
if (bufsize > (INT_MAX / 4) - 1) {
cmdq_error(item, "buffer too big");
return (CMD_RETURN_ERROR);
}
msg = NULL;
used = 0;
while (used != bufsize) {
start = bufdata + used;
end = memchr(start, '\n', bufsize - used);
if (end != NULL)
size = end - start;
else
size = bufsize - used;
msglen = size * 4 + 1;
msg = xrealloc(msg, msglen);
strvisx(msg, start, size, VIS_OCTAL|VIS_TAB);
cmdq_print(item, "%s", msg);
used += size + (end != NULL);
}
free(msg);
return (CMD_RETURN_NORMAL);
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,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-select-layout.c,v 1.8 2009-07-28 23:04:29 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,123 +18,71 @@
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Switch window to selected layout.
*/
static enum cmd_retval cmd_select_layout_exec(struct cmd *,
struct cmdq_item *);
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 = {
.name = "select-layout",
.alias = "selectl",
.args = { "nopt:", 0, 1 },
.usage = "[-nop] " CMD_TARGET_WINDOW_USAGE " [layout-name]",
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec
"select-layout", "selectl",
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
};
const struct cmd_entry cmd_next_layout_entry = {
.name = "next-layout",
.alias = "nextl",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec
};
const struct cmd_entry cmd_previous_layout_entry = {
.name = "previous-layout",
.alias = "prevl",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_select_layout_exec
};
static enum cmd_retval
cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
void
cmd_select_layout_init(struct cmd *self, int key)
{
struct args *args = self->args;
struct winlink *wl = item->target.wl;
struct window *w;
const char *layoutname;
char *oldlayout;
int next, previous, layout;
struct cmd_target_data *data;
w = wl->window;
server_unzoom_window(w);
cmd_target_init(self, key);
data = self->data;
next = self->entry == &cmd_next_layout_entry;
if (args_has(args, 'n'))
next = 1;
previous = self->entry == &cmd_previous_layout_entry;
if (args_has(args, 'p'))
previous = 1;
oldlayout = w->old_layout;
w->old_layout = layout_dump(w->layout_root);
if (next || previous) {
if (next)
layout_set_next(w);
else
layout_set_previous(w);
goto changed;
switch (key) {
case ('1' | KEYC_ESCAPE):
data->arg = xstrdup("even-horizontal");
break;
case ('2' | KEYC_ESCAPE):
data->arg = xstrdup("even-vertical");
break;
case ('3' | KEYC_ESCAPE):
data->arg = xstrdup("main-horizontal");
break;
case ('4' | KEYC_ESCAPE):
data->arg = xstrdup("main-vertical");
break;
}
if (!args_has(args, 'o')) {
if (args->argc == 0)
layout = w->lastlayout;
else
layout = layout_set_lookup(args->argv[0]);
if (layout != -1) {
layout_set_select(w, layout);
goto changed;
}
}
if (args->argc != 0)
layoutname = args->argv[0];
else if (args_has(args, 'o'))
layoutname = oldlayout;
else
layoutname = NULL;
if (layoutname != NULL) {
if (layout_parse(w, layoutname) == -1) {
cmdq_error(item, "can't set layout: %s", layoutname);
goto error;
}
goto changed;
}
free(oldlayout);
return (CMD_RETURN_NORMAL);
changed:
free(oldlayout);
server_redraw_window(w);
return (CMD_RETURN_NORMAL);
error:
free(w->old_layout);
w->old_layout = oldlayout;
return (CMD_RETURN_ERROR);
}
int
cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
int layout;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (data->arg == NULL) {
layout = wl->window->lastlayout;
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,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-select-pane.c,v 1.10 2009-07-30 20:45:20 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -24,148 +24,35 @@
* Select pane.
*/
static enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmdq_item *);
int cmd_select_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_select_pane_entry = {
.name = "select-pane",
.alias = "selectp",
.args = { "DdegLlMmP:RT:t:U", 0, 0 },
.usage = "[-DdegLlMmRU] [-P style] [-T title] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_select_pane_exec
"select-pane", "selectp",
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 = {
.name = "last-pane",
.alias = "lastp",
.args = { "det:", 0, 0 },
.usage = "[-de] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_select_pane_exec
};
static enum cmd_retval
cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct session *s = item->target.s;
struct window_pane *wp = item->target.wp, *lastwp, *markedwp;
const char *style;
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')) {
lastwp = w->last;
if (lastwp == NULL) {
cmdq_error(item, "no last pane");
return (CMD_RETURN_ERROR);
}
if (args_has(self->args, 'e'))
lastwp->flags &= ~PANE_INPUTOFF;
else if (args_has(self->args, 'd'))
lastwp->flags |= PANE_INPUTOFF;
else {
server_unzoom_window(w);
window_redraw_active_switch(w, lastwp);
if (window_set_active_pane(w, lastwp)) {
cmd_find_from_winlink(current, wl, 0);
server_status_window(w);
server_redraw_window_borders(w);
}
}
return (CMD_RETURN_NORMAL);
}
if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL)
return (-1);
if (args_has(args, 'm') || args_has(args, 'M')) {
if (args_has(args, 'm') && !window_pane_visible(wp))
return (CMD_RETURN_NORMAL);
lastwp = marked_pane.wp;
if (args_has(args, 'M') || server_is_marked(s, wl, wp))
server_clear_marked();
else
server_set_marked(s, wl, wp);
markedwp = marked_pane.wp;
if (lastwp != NULL) {
server_redraw_window_borders(lastwp->window);
server_status_window(lastwp->window);
}
if (markedwp != NULL) {
server_redraw_window_borders(markedwp->window);
server_status_window(markedwp->window);
}
return (CMD_RETURN_NORMAL);
}
if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
if (args_has(args, 'P')) {
style = args_get(args, 'P');
if (style_parse(&grid_default_cell, &wp->colgc,
style) == -1) {
cmdq_error(item, "bad style: %s", style);
return (CMD_RETURN_ERROR);
}
wp->flags |= PANE_REDRAW;
}
if (args_has(self->args, 'g'))
cmdq_print(item, "%s", style_tostring(&wp->colgc));
return (CMD_RETURN_NORMAL);
}
if (args_has(self->args, 'L')) {
server_unzoom_window(wp->window);
wp = window_pane_find_left(wp);
} else if (args_has(self->args, 'R')) {
server_unzoom_window(wp->window);
wp = window_pane_find_right(wp);
} else if (args_has(self->args, 'U')) {
server_unzoom_window(wp->window);
wp = window_pane_find_up(wp);
} else if (args_has(self->args, 'D')) {
server_unzoom_window(wp->window);
wp = window_pane_find_down(wp);
}
if (wp == NULL)
return (CMD_RETURN_NORMAL);
if (args_has(self->args, 'e')) {
wp->flags &= ~PANE_INPUTOFF;
return (CMD_RETURN_NORMAL);
}
if (args_has(self->args, 'd')) {
wp->flags |= PANE_INPUTOFF;
return (CMD_RETURN_NORMAL);
}
if (args_has(self->args, 'T')) {
screen_set_title(&wp->base, args_get(self->args, 'T'));
server_status_window(wp->window);
}
if (wp == w->active)
return (CMD_RETURN_NORMAL);
server_unzoom_window(wp->window);
if (!window_pane_visible(wp)) {
cmdq_error(item, "pane not visible");
return (CMD_RETURN_ERROR);
}
window_redraw_active_switch(w, wp);
if (window_set_active_pane(w, wp)) {
cmd_find_from_winlink_pane(current, wl, wp, 0);
hooks_insert(s->hooks, item, current, "after-select-pane");
server_status_window(w);
server_redraw_window_borders(w);
ctx->error(ctx, "pane not visible: %s", data->target);
return (-1);
}
window_set_active_pane(wl->window, wp);
server_status_window(wl->window);
return (CMD_RETURN_NORMAL);
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,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-select-window.c,v 1.23 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -26,120 +26,44 @@
* Select window by index.
*/
static enum cmd_retval cmd_select_window_exec(struct cmd *,
struct cmdq_item *);
void cmd_select_window_init(struct cmd *, int);
int cmd_select_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_select_window_entry = {
.name = "select-window",
.alias = "selectw",
.args = { "lnpTt:", 0, 0 },
.usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = 0,
.exec = cmd_select_window_exec
"select-window", "selectw",
CMD_TARGET_WINDOW_USAGE,
0, 0,
cmd_select_window_init,
cmd_target_parse,
cmd_select_window_exec,
cmd_target_free,
cmd_target_print
};
const struct cmd_entry cmd_next_window_entry = {
.name = "next-window",
.alias = "next",
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0,
.exec = cmd_select_window_exec
};
const struct cmd_entry cmd_previous_window_entry = {
.name = "previous-window",
.alias = "prev",
.args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0,
.exec = cmd_select_window_exec
};
const struct cmd_entry cmd_last_window_entry = {
.name = "last-window",
.alias = "last",
.args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
.flags = 0,
.exec = cmd_select_window_exec
};
static enum cmd_retval
cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
void
cmd_select_window_init(struct cmd *self, int key)
{
struct cmd_find_state *current = &item->shared->current;
struct winlink *wl = item->target.wl;
struct session *s = item->target.s;
int next, previous, last, activity;
struct cmd_target_data *data;
next = self->entry == &cmd_next_window_entry;
if (args_has(self->args, 'n'))
next = 1;
previous = self->entry == &cmd_previous_window_entry;
if (args_has(self->args, 'p'))
previous = 1;
last = self->entry == &cmd_last_window_entry;
if (args_has(self->args, 'l'))
last = 1;
cmd_target_init(self, key);
data = self->data;
if (next || previous || last) {
activity = args_has(self->args, 'a');
if (next) {
if (session_next(s, activity) != 0) {
cmdq_error(item, "no next window");
return (CMD_RETURN_ERROR);
}
} else if (previous) {
if (session_previous(s, activity) != 0) {
cmdq_error(item, "no previous window");
return (CMD_RETURN_ERROR);
}
} else {
if (session_last(s) != 0) {
cmdq_error(item, "no last window");
return (CMD_RETURN_ERROR);
}
}
cmd_find_from_session(current, s, 0);
xasprintf(&data->target, ":%d", key - '0');
}
int
cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct session *s;
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
if (session_select(s, wl->idx) == 0)
server_redraw_session(s);
hooks_insert(s->hooks, item, current, "after-select-window");
} else {
/*
* If -T and select-window is invoked on same window as
* current, switch to previous window.
*/
if (args_has(self->args, 'T') && wl == s->curw) {
if (session_last(s) != 0) {
cmdq_error(item, "no last window");
return (-1);
}
if (current->s == s)
cmd_find_from_session(current, s, 0);
server_redraw_session(s);
} else if (session_select(s, wl->idx) == 0) {
cmd_find_from_session(current, s, 0);
server_redraw_session(s);
}
hooks_insert(s->hooks, item, current, "after-select-window");
}
recalculate_sizes();
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-send-keys.c,v 1.21 2009-08-20 11:37:46 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -19,7 +19,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -27,143 +26,131 @@
* Send keys to client.
*/
static enum cmd_retval cmd_send_keys_exec(struct cmd *, struct cmdq_item *);
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 = {
.name = "send-keys",
.alias = "send",
.args = { "lXRMN:t:", 0, -1 },
.usage = "[-lXRM] [-N repeat-count] " CMD_TARGET_PANE_USAGE " key ...",
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_send_keys_exec
"send-keys", "send",
"[-t target-pane] key ...",
0, 0,
NULL,
cmd_send_keys_parse,
cmd_send_keys_exec,
cmd_send_keys_free,
cmd_send_keys_print
};
const struct cmd_entry cmd_send_prefix_entry = {
.name = "send-prefix",
.alias = NULL,
.args = { "2t:", 0, 0 },
.usage = "[-2] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_send_keys_exec
};
static void
cmd_send_keys_inject(struct client *c, struct cmdq_item *item, key_code key)
int
cmd_send_keys_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct window_pane *wp = item->target.wp;
struct session *s = item->target.s;
struct key_table *table;
struct key_binding *bd, bd_find;
struct cmd_send_keys_data *data;
int opt, key;
char *s;
if (wp->mode == NULL || wp->mode->key_table == NULL) {
if (options_get_number(wp->window->options, "xterm-keys"))
key |= KEYC_XTERM;
window_pane_key(wp, NULL, s, key, NULL);
return;
}
table = key_bindings_get_table(wp->mode->key_table(wp), 1);
self->data = data = xmalloc(sizeof *data);
data->target = NULL;
data->idx = -1;
data->nkeys = 0;
data->keys = NULL;
bd_find.key = (key & ~KEYC_XTERM);
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
if (bd != NULL) {
table->references++;
key_bindings_dispatch(bd, item, c, NULL, &item->target);
key_bindings_unref_table(table);
}
}
static enum cmd_retval
cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = cmd_find_client(item, NULL, 1);
struct window_pane *wp = item->target.wp;
struct session *s = item->target.s;
struct mouse_event *m = &item->shared->mouse;
struct utf8_data *ud, *uc;
wchar_t wc;
int i, literal;
key_code key;
u_int np = 1;
char *cause = NULL;
if (args_has(args, 'N')) {
np = args_strtonum(args, 'N', 1, UINT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "repeat count %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
while ((opt = getopt(argc, argv, "t:")) != -1) {
switch (opt) {
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
default:
goto usage;
}
if (args_has(args, 'X') || args->argc == 0)
wp->modeprefix = np;
}
argc -= optind;
argv += optind;
if (argc == 0)
goto usage;
if (args_has(args, 'X')) {
if (wp->mode == NULL || wp->mode->command == NULL) {
cmdq_error(item, "not in a mode");
return (CMD_RETURN_ERROR);
}
if (!m->valid)
wp->mode->command(wp, c, s, args, NULL);
else
wp->mode->command(wp, c, s, args, m);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'M')) {
wp = cmd_mouse_pane(m, &s, NULL);
if (wp == NULL) {
cmdq_error(item, "no mouse target");
return (CMD_RETURN_ERROR);
}
window_pane_key(wp, NULL, s, m->key, m);
return (CMD_RETURN_NORMAL);
}
if (self->entry == &cmd_send_prefix_entry) {
if (args_has(args, '2'))
key = options_get_number(s->options, "prefix2");
else
key = options_get_number(s->options, "prefix");
cmd_send_keys_inject(c, item, key);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'R')) {
window_pane_reset_palette(wp);
input_reset(wp, 1);
}
for (; np != 0; np--) {
for (i = 0; i < args->argc; i++) {
literal = args_has(args, 'l');
if (!literal) {
key = key_string_lookup_string(args->argv[i]);
if (key != KEYC_NONE && key != KEYC_UNKNOWN)
cmd_send_keys_inject(c, item, key);
else
literal = 1;
}
if (literal) {
ud = utf8_fromcstr(args->argv[i]);
for (uc = ud; uc->size != 0; uc++) {
if (utf8_combine(uc, &wc) != UTF8_DONE)
continue;
cmd_send_keys_inject(c, item, wc);
}
free(ud);
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 (CMD_RETURN_NORMAL);
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
int
cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_send_keys_data *data = self->data;
struct window_pane *wp;
u_int i;
if (data == NULL)
return (-1);
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
return (-1);
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);
}

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

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

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

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

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-set-buffer.c,v 1.10 2009-09-07 23:48:54 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,106 +18,51 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Add, set, append to or delete a paste buffer.
* Add or set a session paste buffer.
*/
static enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmdq_item *);
int cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_set_buffer_entry = {
.name = "set-buffer",
.alias = "setb",
.args = { "ab:n:", 0, 1 },
.usage = "[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data",
.flags = CMD_AFTERHOOK,
.exec = cmd_set_buffer_exec
"set-buffer", "setb",
CMD_BUFFER_SESSION_USAGE " data",
CMD_ARG1, 0,
cmd_buffer_init,
cmd_buffer_parse,
cmd_set_buffer_exec,
cmd_buffer_free,
cmd_buffer_print
};
const struct cmd_entry cmd_delete_buffer_entry = {
.name = "delete-buffer",
.alias = "deleteb",
.args = { "b:", 0, 0 },
.usage = CMD_BUFFER_USAGE,
.flags = CMD_AFTERHOOK,
.exec = cmd_set_buffer_exec
};
static enum cmd_retval
cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct paste_buffer *pb;
char *bufdata, *cause;
const char *bufname, *olddata;
size_t bufsize, newsize;
struct cmd_buffer_data *data = self->data;
struct session *s;
u_int limit;
u_char *pdata;
size_t psize;
bufname = args_get(args, 'b');
if (bufname == NULL)
pb = NULL;
else
pb = paste_get_name(bufname);
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
limit = options_get_number(&s->options, "buffer-limit");
if (self->entry == &cmd_delete_buffer_entry) {
if (pb == NULL)
pb = paste_get_top(&bufname);
if (pb == NULL) {
cmdq_error(item, "no buffer");
return (CMD_RETURN_ERROR);
}
paste_free(pb);
return (CMD_RETURN_NORMAL);
pdata = xstrdup(data->arg);
psize = strlen(pdata);
if (data->buffer == -1) {
paste_add(&s->buffers, pdata, psize, limit);
return (0);
}
if (args_has(args, 'n')) {
if (pb == NULL)
pb = paste_get_top(&bufname);
if (pb == NULL) {
cmdq_error(item, "no buffer");
return (CMD_RETURN_ERROR);
}
if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
if (paste_replace(&s->buffers, data->buffer, pdata, psize) != 0) {
ctx->error(ctx, "no buffer %d", data->buffer);
xfree(pdata);
return (-1);
}
if (args->argc != 1) {
cmdq_error(item, "no data specified");
return (CMD_RETURN_ERROR);
}
if ((newsize = strlen(args->argv[0])) == 0)
return (CMD_RETURN_NORMAL);
bufsize = 0;
bufdata = NULL;
if (args_has(args, 'a') && pb != NULL) {
olddata = paste_buffer_data(pb, &bufsize);
bufdata = xmalloc(bufsize);
memcpy(bufdata, olddata, bufsize);
}
bufdata = xrealloc(bufdata, bufsize + newsize);
memcpy(bufdata + bufsize, args->argv[0], newsize);
bufsize += newsize;
if (paste_set(bufdata, bufsize, bufname, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(bufdata);
free(cause);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
return (0);
}

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-set-environment.c,v 1.2 2009-08-11 14:42:59 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -27,77 +27,62 @@
* Set an environment variable.
*/
static enum cmd_retval cmd_set_environment_exec(struct cmd *,
struct cmdq_item *);
int cmd_set_environment_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_set_environment_entry = {
.name = "set-environment",
.alias = "setenv",
.args = { "grt:u", 1, 2 },
.usage = "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_set_environment_exec
"set-environment", "setenv",
"[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
CMD_ARG12, CMD_CHFLAG('g')|CMD_CHFLAG('r')|CMD_CHFLAG('u'),
NULL,
cmd_target_parse,
cmd_set_environment_exec,
cmd_target_free,
cmd_target_print
};
static enum cmd_retval
cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
struct environ *env;
const char *name, *value, *target;
struct cmd_target_data *data = self->data;
struct session *s;
struct environ *env;
name = args->argv[0];
if (*name == '\0') {
cmdq_error(item, "empty variable name");
return (CMD_RETURN_ERROR);
if (*data->arg == '\0') {
ctx->error(ctx, "empty variable name");
return (-1);
}
if (strchr(name, '=') != NULL) {
cmdq_error(item, "variable name contains =");
return (CMD_RETURN_ERROR);
if (strchr(data->arg, '=') != NULL) {
ctx->error(ctx, "variable name contains =");
return (-1);
}
if (args->argc < 2)
value = NULL;
else
value = args->argv[1];
if (args_has(self->args, 'g'))
env = global_environ;
if (data->chflags & CMD_CHFLAG('g'))
env = &global_environ;
else {
if (item->target.s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(item, "no such session: %s", target);
else
cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR);
}
env = item->target.s->environ;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
env = &s->environ;
}
if (args_has(self->args, 'u')) {
if (value != NULL) {
cmdq_error(item, "can't specify a value with -u");
return (CMD_RETURN_ERROR);
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) {
cmdq_error(item, "can't specify a value with -r");
return (CMD_RETURN_ERROR);
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_clear(env, name);
environ_set(env, data->arg, NULL);
} else {
if (value == NULL) {
cmdq_error(item, "no value specified");
return (CMD_RETURN_ERROR);
if (data->arg2 == NULL) {
ctx->error(ctx, "no value specified");
return (-1);
}
environ_set(env, name, "%s", value);
environ_set(env, data->arg, data->arg2);
}
return (CMD_RETURN_NORMAL);
return (0);
}

View File

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

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/* $Id: cmd-set-option.c,v 1.79 2009-09-19 18:53:01 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -27,388 +27,165 @@
* Set an option.
*/
static enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmdq_item *);
static int cmd_set_option_set(struct cmd *, struct cmdq_item *,
struct options *, struct options_entry *, const char *);
static int cmd_set_option_flag(struct cmdq_item *,
const struct options_table_entry *, struct options *,
const char *);
static int cmd_set_option_choice(struct cmdq_item *,
const struct options_table_entry *, struct options *,
const char *);
int cmd_set_option_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_set_option_entry = {
.name = "set-option",
.alias = "set",
.args = { "aFgoqst:uw", 1, 2 },
.usage = "[-aFgosquw] [-t target-window] option [value]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec
"set-option", "set",
"[-agu] " CMD_TARGET_SESSION_USAGE " option [value]",
CMD_ARG12, CMD_CHFLAG('a')|CMD_CHFLAG('g')|CMD_CHFLAG('u'),
NULL,
cmd_target_parse,
cmd_set_option_exec,
cmd_target_free,
cmd_target_print
};
const struct cmd_entry cmd_set_window_option_entry = {
.name = "set-window-option",
.alias = "setw",
.args = { "aFgoqt:u", 1, 2 },
.usage = "[-aFgoqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK,
.exec = 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 }
};
static enum cmd_retval
cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
int
cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct args *args = self->args;
int append = args_has(args, 'a');
struct cmd_find_state *fs = &item->target;
struct client *c, *loop;
struct session *s = fs->s;
struct winlink *wl = fs->wl;
struct window *w;
enum options_table_scope scope;
struct cmd_target_data *data = self->data;
struct session *s;
struct client *c;
struct options *oo;
struct options_entry *parent, *o;
char *name, *argument, *value = NULL, *cause;
const char *target;
int window, idx, already, error, ambiguous;
const struct set_option_entry *entry, *opt;
u_int i;
/* Expand argument. */
c = cmd_find_client(item, NULL, 1);
argument = format_single(item, args->argv[0], c, s, wl, NULL);
/* Parse option name and index. */
name = options_match(argument, &idx, &ambiguous);
if (name == NULL) {
if (args_has(args, 'q'))
goto out;
if (ambiguous)
cmdq_error(item, "ambiguous option: %s", argument);
else
cmdq_error(item, "invalid option: %s", argument);
goto fail;
}
if (args->argc < 2)
value = NULL;
else if (args_has(args, 'F'))
value = format_single(item, args->argv[1], c, s, wl, NULL);
else
value = xstrdup(args->argv[1]);
/*
* Figure out the scope: for user options it comes from the arguments,
* otherwise from the option name.
*/
if (*name == '@') {
window = (self->entry == &cmd_set_window_option_entry);
scope = options_scope_from_flags(args, window, fs, &oo, &cause);
} else {
if (options_get_only(global_options, name) != NULL)
scope = OPTIONS_TABLE_SERVER;
else if (options_get_only(global_s_options, name) != NULL)
scope = OPTIONS_TABLE_SESSION;
else if (options_get_only(global_w_options, name) != NULL)
scope = OPTIONS_TABLE_WINDOW;
else {
scope = OPTIONS_TABLE_NONE;
xasprintf(&cause, "unknown option: %s", argument);
}
}
if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q'))
goto out;
cmdq_error(item, "%s", cause);
free(cause);
goto fail;
}
/* Which table should this option go into? */
if (scope == OPTIONS_TABLE_SERVER)
oo = global_options;
else if (scope == OPTIONS_TABLE_SESSION) {
if (args_has(self->args, 'g'))
oo = global_s_options;
else if (s == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(item, "no such session: %s", target);
else
cmdq_error(item, "no current session");
goto fail;
} else
oo = s->options;
} else if (scope == OPTIONS_TABLE_WINDOW) {
if (args_has(self->args, 'g'))
oo = global_w_options;
else if (wl == NULL) {
target = args_get(args, 't');
if (target != NULL)
cmdq_error(item, "no such window: %s", target);
else
cmdq_error(item, "no current window");
goto fail;
} else
oo = wl->window->options;
}
o = options_get_only(oo, name);
parent = options_get(oo, name);
/* Check that array options and indexes match up. */
if (idx != -1) {
if (*name == '@' || options_array_size(parent, NULL) == -1) {
cmdq_error(item, "not an array: %s", argument);
goto fail;
}
}
/* With -o, check this option is not already set. */
if (!args_has(args, 'u') && args_has(args, 'o')) {
if (idx == -1)
already = (o != NULL);
else {
if (o == NULL)
already = 0;
else
already = (options_array_get(o, idx) != NULL);
}
if (already) {
if (args_has(args, 'q'))
goto out;
cmdq_error(item, "already set: %s", argument);
goto fail;
}
}
/* Change the option. */
if (args_has(args, 'u')) {
if (o == NULL)
goto out;
if (idx == -1) {
if (oo == global_options ||
oo == global_s_options ||
oo == global_w_options)
options_default(oo, options_table_entry(o));
else
options_remove(o);
} else
options_array_set(o, idx, NULL, 0);
} else if (*name == '@') {
if (value == NULL) {
cmdq_error(item, "empty value");
goto fail;
}
options_set_string(oo, name, append, "%s", value);
} else if (idx == -1 && options_array_size(parent, NULL) == -1) {
error = cmd_set_option_set(self, item, oo, parent, value);
if (error != 0)
goto fail;
} else {
if (value == NULL) {
cmdq_error(item, "empty value");
goto fail;
}
if (o == NULL)
o = options_empty(oo, options_table_entry(parent));
if (idx == -1) {
if (!append)
options_array_clear(o);
options_array_assign(o, value);
} else if (options_array_set(o, idx, value, append) != 0) {
cmdq_error(item, "invalid index: %s", argument);
goto fail;
}
}
/* Update timers and so on for various options. */
if (strcmp(name, "automatic-rename") == 0) {
RB_FOREACH(w, windows, &windows) {
if (w->active == NULL)
continue;
if (options_get_number(w->options, "automatic-rename"))
w->active->flags |= PANE_CHANGED;
}
}
if (strcmp(name, "key-table") == 0) {
TAILQ_FOREACH(loop, &clients, entry)
server_client_set_key_table(loop, NULL);
}
if (strcmp(name, "user-keys") == 0) {
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->tty.flags & TTY_OPENED)
tty_keys_build(&loop->tty);
}
}
if (strcmp(name, "status") == 0 ||
strcmp(name, "status-interval") == 0)
status_timer_start_all();
if (strcmp(name, "monitor-silence") == 0)
alerts_reset_all();
if (strcmp(name, "window-style") == 0 ||
strcmp(name, "window-active-style") == 0) {
RB_FOREACH(w, windows, &windows)
w->flags |= WINDOW_STYLECHANGED;
}
if (strcmp(name, "pane-border-status") == 0) {
RB_FOREACH(w, windows, &windows)
layout_fix_panes(w, w->sx, w->sy);
}
RB_FOREACH(s, sessions, &sessions)
status_update_saved(s);
/*
* Update sizes and redraw. May not always be necessary but do it
* anyway.
*/
recalculate_sizes();
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->session != NULL)
server_redraw_client(loop);
}
out:
free(argument);
free(value);
free(name);
return (CMD_RETURN_NORMAL);
fail:
free(argument);
free(value);
free(name);
return (CMD_RETURN_ERROR);
}
static int
cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
struct options_entry *parent, const char *value)
{
const struct options_table_entry *oe;
struct args *args = self->args;
int append = args_has(args, 'a');
struct options_entry *o;
long long number;
const char *errstr;
key_code key;
oe = options_table_entry(parent);
if (value == NULL &&
oe->type != OPTIONS_TABLE_FLAG &&
oe->type != OPTIONS_TABLE_CHOICE) {
cmdq_error(item, "empty value");
return (-1);
}
switch (oe->type) {
case OPTIONS_TABLE_STRING:
options_set_string(oo, oe->name, append, "%s", value);
return (0);
case OPTIONS_TABLE_NUMBER:
number = strtonum(value, oe->minimum, oe->maximum, &errstr);
if (errstr != NULL) {
cmdq_error(item, "value is %s: %s", errstr, value);
return (-1);
}
options_set_number(oo, oe->name, number);
return (0);
case OPTIONS_TABLE_KEY:
key = key_string_lookup_string(value);
if (key == KEYC_UNKNOWN) {
cmdq_error(item, "bad key: %s", value);
return (-1);
}
options_set_number(oo, oe->name, key);
return (0);
case OPTIONS_TABLE_COLOUR:
if ((number = colour_fromstring(value)) == -1) {
cmdq_error(item, "bad colour: %s", value);
return (-1);
}
o = options_set_number(oo, oe->name, number);
options_style_update_new(oo, o);
return (0);
case OPTIONS_TABLE_ATTRIBUTES:
if ((number = attributes_fromstring(value)) == -1) {
cmdq_error(item, "bad attributes: %s", value);
return (-1);
}
o = options_set_number(oo, oe->name, number);
options_style_update_new(oo, o);
return (0);
case OPTIONS_TABLE_FLAG:
return (cmd_set_option_flag(item, oe, oo, value));
case OPTIONS_TABLE_CHOICE:
return (cmd_set_option_choice(item, oe, oo, value));
case OPTIONS_TABLE_STYLE:
o = options_set_style(oo, oe->name, append, value);
if (o == NULL) {
cmdq_error(item, "bad style: %s", value);
return (-1);
}
options_style_update_old(oo, o);
return (0);
case OPTIONS_TABLE_ARRAY:
break;
}
return (-1);
}
static int
cmd_set_option_flag(struct cmdq_item *item,
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 (strcmp(value, "1") == 0 ||
strcasecmp(value, "on") == 0 ||
strcasecmp(value, "yes") == 0)
flag = 1;
else if (strcmp(value, "0") == 0 ||
strcasecmp(value, "off") == 0 ||
strcasecmp(value, "no") == 0)
flag = 0;
if (data->chflags & CMD_CHFLAG('g'))
oo = &global_s_options;
else {
cmdq_error(item, "bad value: %s", value);
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);
}
options_set_number(oo, oe->name, flag);
return (0);
}
static int
cmd_set_option_choice(struct cmdq_item *item,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
const char **cp;
int n, choice = -1;
if (value == NULL) {
choice = options_get_number(oo, oe->name);
if (choice < 2)
choice = !choice;
} else {
n = 0;
for (cp = oe->choices; *cp != NULL; cp++) {
if (strcmp(*cp, value) == 0)
choice = n;
n++;
}
if (choice == -1) {
cmdq_error(item, "unknown value: %s", value);
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;
}
options_set_number(oo, oe->name, choice);
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);
}

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);
}

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