aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Marriott <nicholas.marriott@gmail.com>2013-03-11 21:31:46 +0000
committerNicholas Marriott <nicholas.marriott@gmail.com>2013-03-11 21:31:46 +0000
commit543420ccd2c3c23437405b391e3f9fe1d05223f7 (patch)
tree7581f8eb90cd26fd51c5e406f31f561e0e4eb603
parent064022548bcbf4d45705fdbff8441f2b5da5f682 (diff)
parent7c009509676b4580065fdc6f0084a93b9758fac0 (diff)
downloadrtmux-543420ccd2c3c23437405b391e3f9fe1d05223f7.tar.gz
rtmux-543420ccd2c3c23437405b391e3f9fe1d05223f7.tar.bz2
rtmux-543420ccd2c3c23437405b391e3f9fe1d05223f7.zip
Merge branch 'master' of ssh://git.code.sf.net/p/tmux/tmux-code
-rw-r--r--Makefile.am1
-rw-r--r--client.c2
-rw-r--r--cmd-if-shell.c20
-rw-r--r--cmd-queue.c39
-rw-r--r--cmd-run-shell.c29
-rw-r--r--cmd-select-pane.c1
-rw-r--r--cmd-server-info.c2
-rw-r--r--cmd-wait-for.c197
-rw-r--r--cmd.c25
-rw-r--r--configure.ac5
-rw-r--r--control-notify.c6
-rw-r--r--control.c9
-rw-r--r--examples/tmux-zoom.sh57
-rw-r--r--format.c8
-rw-r--r--grid.c2
-rw-r--r--layout-custom.c9
-rw-r--r--screen-redraw.c3
-rw-r--r--server-client.c5
-rw-r--r--server-fn.c6
-rw-r--r--session.c14
-rw-r--r--tmux.1117
-rw-r--r--tmux.c8
-rw-r--r--tmux.h17
-rw-r--r--tty-keys.c7
-rw-r--r--window-choose.c2
25 files changed, 459 insertions, 132 deletions
diff --git a/Makefile.am b/Makefile.am
index 5caa4983..19220d8e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -135,6 +135,7 @@ dist_tmux_SOURCES = \
cmd-switch-client.c \
cmd-unbind-key.c \
cmd-unlink-window.c \
+ cmd-wait-for.c \
cmd.c \
colour.c \
control.c \
diff --git a/client.c b/client.c
index 612572d0..91f47650 100644
--- a/client.c
+++ b/client.c
@@ -270,7 +270,7 @@ client_main(int argc, char **argv, int flags)
if (msg == MSG_COMMAND) {
/* Fill in command line arguments. */
cmddata.pid = environ_pid;
- cmddata.idx = environ_idx;
+ cmddata.session_id = environ_session_id;
/* Prepare command for server. */
cmddata.argc = argc;
diff --git a/cmd-if-shell.c b/cmd-if-shell.c
index b921f418..b22e3269 100644
--- a/cmd-if-shell.c
+++ b/cmd-if-shell.c
@@ -59,19 +59,21 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
struct args *args = self->args;
struct cmd_if_shell_data *cdata;
char *shellcmd;
- struct session *s;
- struct winlink *wl;
- struct window_pane *wp;
+ struct session *s = NULL;
+ struct winlink *wl = NULL;
+ struct window_pane *wp = NULL;
struct format_tree *ft;
- wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
- if (wl == NULL)
- return (CMD_RETURN_ERROR);
+ if (args_has(args, 't'))
+ wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
ft = format_create();
- format_session(ft, s);
- format_winlink(ft, s, wl);
- format_window_pane(ft, wp);
+ if (s != NULL)
+ format_session(ft, s);
+ if (s != NULL && wl != NULL)
+ format_winlink(ft, s, wl);
+ if (wp != NULL)
+ format_window_pane(ft, wp);
shellcmd = format_expand(ft, args->argv[0]);
format_free(ft);
diff --git a/cmd-queue.c b/cmd-queue.c
index 4b00fceb..17992a37 100644
--- a/cmd-queue.c
+++ b/cmd-queue.c
@@ -151,6 +151,22 @@ cmdq_error(struct cmd_q *cmdq, const char *fmt, ...)
free(msg);
}
+/* Print a guard line. */
+void
+cmdq_guard(struct cmd_q *cmdq, const char *guard)
+{
+ struct client *c = cmdq->client;
+
+ if (c == NULL || c->session == NULL)
+ return;
+ if (!(c->flags & CLIENT_CONTROL))
+ return;
+
+ evbuffer_add_printf(c->stdout_data, "%%%s %ld %u\n", guard,
+ (long) cmdq->time, cmdq->number);
+ server_push_stdout(c);
+}
+
/* Add command list to queue and begin processing if needed. */
void
cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist)
@@ -179,16 +195,11 @@ cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist)
int
cmdq_continue(struct cmd_q *cmdq)
{
- struct client *c = cmdq->client;
struct cmd_q_item *next;
enum cmd_retval retval;
- int guards, empty;
+ int empty;
char s[1024];
- guards = 0;
- if (c != NULL && c->session != NULL)
- guards = c->flags & CLIENT_CONTROL;
-
notify_disable();
empty = TAILQ_EMPTY(&cmdq->queue);
@@ -209,15 +220,15 @@ cmdq_continue(struct cmd_q *cmdq)
log_debug("cmdq %p: %s (client %d)", cmdq, s,
cmdq->client != NULL ? cmdq->client->ibuf.fd : -1);
- if (guards)
- cmdq_print(cmdq, "%%begin");
+ cmdq->time = time(NULL);
+ cmdq->number++;
+
+ cmdq_guard(cmdq, "begin");
retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq);
- if (guards) {
- if (retval == CMD_RETURN_ERROR)
- cmdq_print(cmdq, "%%error");
- else
- cmdq_print(cmdq, "%%end");
- }
+ if (retval == CMD_RETURN_ERROR)
+ cmdq_guard(cmdq, "error");
+ else
+ cmdq_guard(cmdq, "end");
if (retval == CMD_RETURN_ERROR)
break;
diff --git a/cmd-run-shell.c b/cmd-run-shell.c
index aaa310b9..b163542f 100644
--- a/cmd-run-shell.c
+++ b/cmd-run-shell.c
@@ -49,16 +49,17 @@ struct cmd_run_shell_data {
char *cmd;
struct cmd_q *cmdq;
int bflag;
- u_int wp_id;
+ int wp_id;
};
void
cmd_run_shell_print(struct job *job, const char *msg)
{
struct cmd_run_shell_data *cdata = job->data;
- struct window_pane *wp;
+ struct window_pane *wp = NULL;
- wp = window_pane_find_by_id(cdata->wp_id);
+ if (cdata->wp_id != -1)
+ wp = window_pane_find_by_id(cdata->wp_id);
if (wp == NULL) {
cmdq_print(cdata->cmdq, "%s", msg);
return;
@@ -76,26 +77,28 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq)
struct args *args = self->args;
struct cmd_run_shell_data *cdata;
char *shellcmd;
- struct session *s;
- struct winlink *wl;
- struct window_pane *wp;
+ struct session *s = NULL;
+ struct winlink *wl = NULL;
+ struct window_pane *wp = NULL;
struct format_tree *ft;
- wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
- if (wl == NULL)
- return (CMD_RETURN_ERROR);
+ if (args_has(args, 't'))
+ wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
ft = format_create();
- format_session(ft, s);
- format_winlink(ft, s, wl);
- format_window_pane(ft, wp);
+ if (s != NULL)
+ format_session(ft, s);
+ if (s != NULL && wl != NULL)
+ format_winlink(ft, s, wl);
+ if (wp != NULL)
+ format_window_pane(ft, wp);
shellcmd = format_expand(ft, args->argv[0]);
format_free(ft);
cdata = xmalloc(sizeof *cdata);
cdata->cmd = shellcmd;
cdata->bflag = args_has(args, 'b');
- cdata->wp_id = wp->id;
+ cdata->wp_id = wp != NULL ? (int) wp->id : -1;
cdata->cmdq = cmdq;
cmdq->references++;
diff --git a/cmd-select-pane.c b/cmd-select-pane.c
index d24d7b3d..b8a12671 100644
--- a/cmd-select-pane.c
+++ b/cmd-select-pane.c
@@ -80,6 +80,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR);
}
+ server_unzoom_window(wl->window);
window_set_active_pane(wl->window, wl->window->last);
server_status_window(wl->window);
server_redraw_window_borders(wl->window);
diff --git a/cmd-server-info.c b/cmd-server-info.c
index b044649c..8eba172a 100644
--- a/cmd-server-info.c
+++ b/cmd-server-info.c
@@ -102,7 +102,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_q *cmdq)
*strchr(tim, '\n') = '\0';
cmdq_print(cmdq, "%2u: %s: %u windows (created %s) [%ux%u] "
- "[flags=0x%x]", s->idx, s->name,
+ "[flags=0x%x]", s->id, s->name,
winlink_count(&s->windows), tim, s->sx, s->sy, s->flags);
RB_FOREACH(wl, winlinks, &s->windows) {
w = wl->window;
diff --git a/cmd-wait-for.c b/cmd-wait-for.c
new file mode 100644
index 00000000..d40ba49e
--- /dev/null
+++ b/cmd-wait-for.c
@@ -0,0 +1,197 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net>
+ * Copyright (c) 2013 Thiago de Arruda <tpadilha84@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "tmux.h"
+
+/*
+ * Block or wake a client on a named wait channel.
+ */
+
+enum cmd_retval cmd_wait_for_exec(struct cmd *, struct cmd_q *);
+
+const struct cmd_entry cmd_wait_for_entry = {
+ "wait-for", "wait",
+ "LSU", 1, 1,
+ "[-LSU] channel",
+ 0,
+ NULL,
+ NULL,
+ cmd_wait_for_exec
+};
+
+struct wait_channel {
+ const char *name;
+ int locked;
+
+ TAILQ_HEAD(, cmd_q) waiters;
+ TAILQ_HEAD(, cmd_q) lockers;
+
+ RB_ENTRY(wait_channel) entry;
+};
+RB_HEAD(wait_channels, wait_channel);
+struct wait_channels wait_channels = RB_INITIALIZER(wait_channels);
+
+int wait_channel_cmp(struct wait_channel *, struct wait_channel *);
+RB_PROTOTYPE(wait_channels, wait_channel, entry, wait_channel_cmp);
+RB_GENERATE(wait_channels, wait_channel, entry, wait_channel_cmp);
+
+int
+wait_channel_cmp(struct wait_channel *wc1, struct wait_channel *wc2)
+{
+ return (strcmp(wc1->name, wc2->name));
+}
+
+enum cmd_retval cmd_wait_for_signal(struct cmd_q *, const char *,
+ struct wait_channel *);
+enum cmd_retval cmd_wait_for_wait(struct cmd_q *, const char *,
+ struct wait_channel *);
+enum cmd_retval cmd_wait_for_lock(struct cmd_q *, const char *,
+ struct wait_channel *);
+enum cmd_retval cmd_wait_for_unlock(struct cmd_q *, const char *,
+ struct wait_channel *);
+
+enum cmd_retval
+cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+ const char *name = args->argv[0];
+ struct wait_channel *wc, wc0;
+
+ wc0.name = name;
+ wc = RB_FIND(wait_channels, &wait_channels, &wc0);
+
+ if (args_has(args, 'S'))
+ return (cmd_wait_for_signal(cmdq, name, wc));
+ if (args_has(args, 'L'))
+ return (cmd_wait_for_lock(cmdq, name, wc));
+ if (args_has(args, 'U'))
+ return (cmd_wait_for_unlock(cmdq, name, wc));
+ return (cmd_wait_for_wait(cmdq, name, wc));
+}
+
+enum cmd_retval
+cmd_wait_for_signal(struct cmd_q *cmdq, const char *name,
+ struct wait_channel *wc)
+{
+ struct cmd_q *wq, *wq1;
+
+ if (wc == NULL || TAILQ_EMPTY(&wc->waiters)) {
+ cmdq_error(cmdq, "no waiting clients on %s", name);
+ return (CMD_RETURN_ERROR);
+ }
+
+ TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) {
+ TAILQ_REMOVE(&wc->waiters, wq, waitentry);
+ if (!cmdq_free(wq))
+ cmdq_continue(wq);
+ }
+
+ if (!wc->locked) {
+ RB_REMOVE(wait_channels, &wait_channels, wc);
+ free((void*) wc->name);
+ free(wc);
+ }
+
+ return (CMD_RETURN_NORMAL);
+}
+
+enum cmd_retval
+cmd_wait_for_wait(struct cmd_q *cmdq, const char *name,
+ struct wait_channel *wc)
+{
+ if (cmdq->client == NULL || cmdq->client->session != NULL) {
+ cmdq_error(cmdq, "not able to wait");
+ return (CMD_RETURN_ERROR);
+ }
+
+ if (wc == NULL) {
+ wc = xmalloc(sizeof *wc);
+ wc->name = xstrdup(name);
+ wc->locked = 0;
+ TAILQ_INIT(&wc->waiters);
+ TAILQ_INIT(&wc->lockers);
+ RB_INSERT(wait_channels, &wait_channels, wc);
+ }
+
+ TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry);
+ cmdq->references++;
+
+ return (CMD_RETURN_WAIT);
+}
+
+enum cmd_retval
+cmd_wait_for_lock(struct cmd_q *cmdq, const char *name,
+ struct wait_channel *wc)
+{
+ if (cmdq->client == NULL || cmdq->client->session != NULL) {
+ cmdq_error(cmdq, "not able to lock");
+ return (CMD_RETURN_ERROR);
+ }
+
+ if (wc == NULL) {
+ wc = xmalloc(sizeof *wc);
+ wc->name = xstrdup(name);
+ wc->locked = 0;
+ TAILQ_INIT(&wc->waiters);
+ TAILQ_INIT(&wc->lockers);
+ RB_INSERT(wait_channels, &wait_channels, wc);
+ }
+
+ if (wc->locked) {
+ TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry);
+ cmdq->references++;
+ return (CMD_RETURN_WAIT);
+ }
+ wc->locked = 1;
+
+ return (CMD_RETURN_NORMAL);
+}
+
+enum cmd_retval
+cmd_wait_for_unlock(struct cmd_q *cmdq, const char *name,
+ struct wait_channel *wc)
+{
+ struct cmd_q *wq;
+
+ if (wc == NULL || !wc->locked) {
+ cmdq_error(cmdq, "channel %s not locked", name);
+ return (CMD_RETURN_ERROR);
+ }
+
+ if ((wq = TAILQ_FIRST(&wc->lockers)) != NULL) {
+ TAILQ_REMOVE(&wc->lockers, wq, waitentry);
+ if (!cmdq_free(wq))
+ cmdq_continue(wq);
+ } else {
+ wc->locked = 0;
+ if (TAILQ_EMPTY(&wc->waiters)) {
+ RB_REMOVE(wait_channels, &wait_channels, wc);
+ free((void*) wc->name);
+ free(wc);
+ }
+ }
+
+ return (CMD_RETURN_NORMAL);
+}
+
diff --git a/cmd.c b/cmd.c
index 0d6a85ff..c8e9702d 100644
--- a/cmd.c
+++ b/cmd.c
@@ -112,6 +112,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_switch_client_entry,
&cmd_unbind_key_entry,
&cmd_unlink_window_entry,
+ &cmd_wait_for_entry,
NULL
};
@@ -121,6 +122,7 @@ struct session *cmd_choose_session(int);
struct client *cmd_choose_client(struct clients *);
struct client *cmd_lookup_client(const char *);
struct session *cmd_lookup_session(const char *, int *);
+struct session *cmd_lookup_session_id(const char *);
struct winlink *cmd_lookup_window(struct session *, const char *, int *);
int cmd_lookup_index(struct session *, const char *, int *);
struct window_pane *cmd_lookup_paneid(const char *);
@@ -356,8 +358,8 @@ cmd_current_session(struct cmd_q *cmdq, int prefer_unattached)
}
/* Use the session from the TMUX environment variable. */
- if (data != NULL && data->pid == getpid() && data->idx != -1) {
- s = session_find_by_index(data->idx);
+ if (data != NULL && data->pid == getpid() && data->session_id != -1) {
+ s = session_find_by_id(data->session_id);
if (s != NULL)
return (s);
}
@@ -549,6 +551,21 @@ cmd_lookup_client(const char *name)
return (NULL);
}
+/* Find the target session or report an error and return NULL. */
+struct session *
+cmd_lookup_session_id(const char *arg)
+{
+ char *endptr;
+ long id;
+
+ if (arg[0] != '$')
+ return (NULL);
+ id = strtol(arg + 1, &endptr, 10);
+ if (arg[1] != '\0' && *endptr == '\0')
+ return (session_find_by_id(id));
+ return (NULL);
+}
+
/* Lookup a session by name. If no session is found, NULL is returned. */
struct session *
cmd_lookup_session(const char *name, int *ambiguous)
@@ -557,6 +574,10 @@ cmd_lookup_session(const char *name, int *ambiguous)
*ambiguous = 0;
+ /* Look for $id first. */
+ if ((s = cmd_lookup_session_id(name)) != NULL)
+ return (s);
+
/*
* Look for matches. First look for exact matches - session names must
* be unique so an exact match can't be ambigious and can just be
diff --git a/configure.ac b/configure.ac
index 84aec0fb..9e060df7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -53,8 +53,11 @@ AM_CONDITIONAL(IS_DEBUG, test "x$found_debug" = xyes)
AC_ARG_ENABLE(
static,
AC_HELP_STRING(--enable-static, create a static build),
- [LDFLAGS="$LDFLAGS -static"]
+ found_static=$enable_static
)
+if test "x$found_static" = xyes; then
+ LDFLAGS="$LDFLAGS -static"
+fi
# Is this gcc?
AM_CONDITIONAL(IS_GCC, test "x$GCC" = xyes)
diff --git a/control-notify.c b/control-notify.c
index bb9708c8..90ee4ffa 100644
--- a/control-notify.c
+++ b/control-notify.c
@@ -45,7 +45,7 @@ control_notify_input(struct client *c, struct window_pane *wp,
*/
if (winlink_find_by_window(&c->session->windows, wp->window) != NULL) {
message = evbuffer_new();
- evbuffer_add_printf(message, "%%output %%%u ", wp->id);
+ evbuffer_add_printf(message, "%%output %u ", wp->id);
for (i = 0; i < len; i++)
evbuffer_add_printf(message, "%02hhx", buf[i]);
control_write_buffer(c, message);
@@ -141,7 +141,7 @@ control_notify_window_renamed(struct window *w)
continue;
s = c->session;
- control_write(c, "%%window-renamed %u %s", w->id, w->name);
+ control_write(c, "%%window-renamed %u %s", w->id, w->name);
}
}
@@ -154,7 +154,7 @@ control_notify_attached_session_changed(struct client *c)
return;
s = c->session;
- control_write(c, "%%session-changed %d %s", s->idx, s->name);
+ control_write(c, "%%session-changed %u %s", s->id, s->name);
}
void
diff --git a/control.c b/control.c
index 06f20bbb..c888877e 100644
--- a/control.c
+++ b/control.c
@@ -68,8 +68,13 @@ control_callback(struct client *c, int closed, unused void *data)
}
if (cmd_string_parse(line, &cmdlist, NULL, 0, &cause) != 0) {
- control_write(c, "%%error in line \"%s\": %s", line,
- cause);
+ c->cmdq->time = time(NULL);
+ c->cmdq->number++;
+
+ cmdq_guard(c->cmdq, "begin");
+ control_write(c, "parse error: %s", cause);
+ cmdq_guard(c->cmdq, "error");
+
free(cause);
} else {
cmdq_run(c->cmdq, cmdlist);
diff --git a/examples/tmux-zoom.sh b/examples/tmux-zoom.sh
deleted file mode 100644
index 3a604564..00000000
--- a/examples/tmux-zoom.sh
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/bin/bash
-
-# Copyright (c) 2012 Juan Ignacio Pumarino, jipumarino@gmail.com
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-# Instructions
-# ------------
-#
-# 1. Install this script and give it execute permission somewhere in your PATH.
-# For example:
-#
-# $ mkdir -p ~/bin
-# $ wget https://raw.github.com/jipumarino/tmux-zoom/master/tmux-zoom.sh -O ~/bin/tmux-zoom.sh
-# $ chmod +x ~/bin/tmux-zoom.sh
-#
-# 2. Add a shortcut in your ~/.tmux.conf file:
-#
-# bind C-k run "tmux-zoom.sh"
-#
-# 3. When using this shortcut, the current tmux pane will open in a new window by itself.
-# Running it again in the zoomed window will return it to its original pane. You can have
-# as many zoomed windows as you want.
-
-current=$(tmux display-message -p '#W-#I-#P')
-list=$(tmux list-window)
-
-[[ "$current" =~ ^(.*)-([0-9]+)-([0-9]+) ]]
-current_window=${BASH_REMATCH[1]}
-current_pane=${BASH_REMATCH[2]}-${BASH_REMATCH[3]}
-new_zoom_window=ZOOM-$current_pane
-
-if [[ $current_window =~ ZOOM-([0-9]+)-([0-9+]) ]]; then
- old_zoom_window=ZOOM-${BASH_REMATCH[1]}-${BASH_REMATCH[2]}
- tmux select-window -t ${BASH_REMATCH[1]} \; select-pane -t ${BASH_REMATCH[2]} \; swap-pane -s $old_zoom_window.1 \; kill-window -t $old_zoom_window
-elif [[ $list =~ $new_zoom_window ]]; then
- tmux select-window -t $new_zoom_window
-else
- tmux new-window -d -n $new_zoom_window \; swap-pane -s $new_zoom_window.1 \; select-window -t $new_zoom_window
-fi
diff --git a/format.c b/format.c
index ad52caea..4d70d59b 100644
--- a/format.c
+++ b/format.c
@@ -280,6 +280,7 @@ format_session(struct format_tree *ft, struct session *s)
format_add(ft, "session_windows", "%u", winlink_count(&s->windows));
format_add(ft, "session_width", "%u", s->sx);
format_add(ft, "session_height", "%u", s->sy);
+ format_add(ft, "session_id", "%u", s->id);
sg = session_group_find(s);
format_add(ft, "session_grouped", "%d", sg != NULL);
@@ -398,7 +399,8 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp)
struct grid_line *gl;
unsigned long long size;
u_int i, idx;
- const char *cwd, *cmd;
+ const char *cwd;
+ char *cmd;
size = 0;
for (i = 0; i < gd->hsize; i++) {
@@ -432,8 +434,10 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp)
format_add(ft, "pane_start_path", "%s", wp->cwd);
if ((cwd = osdep_get_cwd(wp->fd)) != NULL)
format_add(ft, "pane_current_path", "%s", cwd);
- if ((cmd = osdep_get_name(wp->fd, wp->tty)) != NULL)
+ if ((cmd = osdep_get_name(wp->fd, wp->tty)) != NULL) {
format_add(ft, "pane_current_command", "%s", cmd);
+ free(cmd);
+ }
format_add(ft, "cursor_x", "%d", wp->base.cx);
format_add(ft, "cursor_y", "%d", wp->base.cy);
diff --git a/grid.c b/grid.c
index b30127f3..551a7dc9 100644
--- a/grid.c
+++ b/grid.c
@@ -595,7 +595,7 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx);
- if (*lastgc == NULL) {
+ if (lastgc != NULL && *lastgc == NULL) {
memcpy(&lastgc1, &grid_default_cell, sizeof lastgc1);
*lastgc = &lastgc1;
}
diff --git a/layout-custom.c b/layout-custom.c
index c076232f..e32d9d9d 100644
--- a/layout-custom.c
+++ b/layout-custom.c
@@ -63,7 +63,7 @@ layout_dump(struct window *w)
if (layout_append(w->layout_root, layout, sizeof layout) != 0)
return (NULL);
- xasprintf(&out, "%4x,%s", layout_checksum(layout), layout);
+ xasprintf(&out, "%04x,%s", layout_checksum(layout), layout);
return (out);
}
@@ -206,11 +206,11 @@ layout_construct(struct layout_cell *lcparent, const char **layout)
{
struct layout_cell *lc, *lcchild;
u_int sx, sy, xoff, yoff;
+ const char *saved;
if (!isdigit((u_char) **layout))
return (NULL);
- if (sscanf(*layout, "%ux%u,%u,%u,%*u", &sx, &sy, &xoff, &yoff) != 4 &&
- sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4)
+ if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4)
return (NULL);
while (isdigit((u_char) **layout))
@@ -231,9 +231,12 @@ layout_construct(struct layout_cell *lcparent, const char **layout)
while (isdigit((u_char) **layout))
(*layout)++;
if (**layout == ',') {
+ saved = *layout;
(*layout)++;
while (isdigit((u_char) **layout))
(*layout)++;
+ if (**layout == 'x')
+ *layout = saved;
}
lc = layout_create_cell(lcparent);
diff --git a/screen-redraw.c b/screen-redraw.c
index 899f741b..14b73164 100644
--- a/screen-redraw.c
+++ b/screen-redraw.c
@@ -273,6 +273,9 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
{
u_int i, yoff;
+ if (!window_pane_visible(wp))
+ return;
+
yoff = wp->yoff;
if (status_at_line(c) == 0)
yoff++;
diff --git a/server-client.c b/server-client.c
index b905a7c7..77e6de78 100644
--- a/server-client.c
+++ b/server-client.c
@@ -153,7 +153,8 @@ server_client_lost(struct client *c)
evbuffer_free (c->stdin_data);
evbuffer_free (c->stdout_data);
- evbuffer_free (c->stderr_data);
+ if (c->stderr_data != c->stdout_data)
+ evbuffer_free (c->stderr_data);
status_free_jobs(&c->status_new);
status_free_jobs(&c->status_old);
@@ -955,6 +956,8 @@ server_client_msg_identify(
if (data->flags & IDENTIFY_CONTROL) {
c->stdin_callback = control_callback;
+ evbuffer_free(c->stderr_data);
+ c->stderr_data = c->stdout_data;
c->flags |= CLIENT_CONTROL;
if (data->flags & IDENTIFY_TERMIOS)
evbuffer_add_printf(c->stdout_data, "\033P1000p");
diff --git a/server-fn.c b/server-fn.c
index b09415e0..566925f0 100644
--- a/server-fn.c
+++ b/server-fn.c
@@ -39,7 +39,7 @@ server_fill_environ(struct session *s, struct environ *env)
term = options_get_string(&s->options, "default-terminal");
environ_set(env, "TERM", term);
- idx = s->idx;
+ idx = s->id;
} else
idx = -1;
pid = getpid();
@@ -546,6 +546,10 @@ server_push_stderr(struct client *c)
struct msg_stderr_data data;
size_t size;
+ if (c->stderr_data == c->stdout_data) {
+ server_push_stdout(c);
+ return;
+ }
size = EVBUFFER_LENGTH(c->stderr_data);
if (size == 0)
return;
diff --git a/session.c b/session.c
index 72e8fb05..74eb06a5 100644
--- a/session.c
+++ b/session.c
@@ -29,7 +29,7 @@
/* Global session list. */
struct sessions sessions;
struct sessions dead_sessions;
-u_int next_session;
+u_int next_session_id;
struct session_groups session_groups;
struct winlink *session_next_alert(struct winlink *);
@@ -69,14 +69,14 @@ session_find(const char *name)
return (RB_FIND(sessions, &sessions, &s));
}
-/* Find session by index. */
+/* Find session by id. */
struct session *
-session_find_by_index(u_int idx)
+session_find_by_id(u_int id)
{
struct session *s;
RB_FOREACH(s, sessions, &sessions) {
- if (s->idx == idx)
+ if (s->id == id)
return (s);
}
return (NULL);
@@ -120,13 +120,13 @@ session_create(const char *name, const char *cmd, const char *cwd,
if (name != NULL) {
s->name = xstrdup(name);
- s->idx = next_session++;
+ s->id = next_session_id++;
} else {
s->name = NULL;
do {
- s->idx = next_session++;
+ s->id = next_session_id++;
free (s->name);
- xasprintf(&s->name, "%u", s->idx);
+ xasprintf(&s->name, "%u", s->id);
} while (RB_FIND(sessions, &sessions, s) != NULL);
}
RB_INSERT(sessions, &sessions, s);
diff --git a/tmux.1 b/tmux.1
index a65ce221..519bf6fa 100644
--- a/tmux.1
+++ b/tmux.1
@@ -23,7 +23,7 @@
.Sh SYNOPSIS
.Nm tmux
.Bk -words
-.Op Fl 28lquvV
+.Op Fl 28lCquvV
.Op Fl c Ar shell-command
.Op Fl f Ar file
.Op Fl L Ar socket-name
@@ -102,6 +102,11 @@ to assume the terminal supports 256 colours.
Like
.Fl 2 ,
but indicates that the terminal supports 88 colours.
+.It Fl C
+Start in control mode.
+Given twice
+.Xo ( Fl CC ) Xc
+disables echo.
.It Fl c Ar shell-command
Execute
.Ar shell-command
@@ -369,9 +374,9 @@ Clients may be listed with the
command.
.Pp
.Ar target-session
-is either the name of a session (as listed by the
+is the session id prefixed with a $, the name of a session (as listed by the
.Ic list-sessions
-command) or the name of a client with the same syntax as
+command), or the name of a client with the same syntax as
.Ar target-client ,
in which case the session attached to the client is used.
When looking for the session name,
@@ -1619,7 +1624,7 @@ is given in lines or cells (the default is 1).
.Pp
With
.Fl Z ,
-the active pane is toggled between occupying the whole of the window and it's
+the active pane is toggled between occupying the whole of the window and its
normal position in the layout.
.It Xo Ic respawn-pane
.Op Fl k
@@ -3085,6 +3090,7 @@ The following variables are available, where appropriate:
.It Li "session_group" Ta "Number of session group"
.It Li "session_grouped" Ta "1 if session in a group"
.It Li "session_height" Ta "Height of session"
+.It Li "session_id" Ta "Unique session ID"
.It Li "session_name" Ta "Name of session"
.It Li "session_width" Ta "Width of session"
.It Li "session_windows" Ta "Number of windows in session"
@@ -3553,6 +3559,23 @@ If the command doesn't return success, the exit status is also displayed.
.It Ic server-info
.D1 (alias: Ic info )
Show server information and terminal details.
+.It Xo Ic wait-for
+.Fl LSU
+.Ar channel
+.Xc
+.D1 (alias: Ic wait )
+When used without options, prevents the client from exiting until woken using
+.Ic wait-for
+.Fl S
+with the same channel.
+When
+.Fl L
+is used, the channel is locked and any clients that try to lock the same
+channel are made to wait until the channel is unlocked with
+.Ic wait-for
+.Fl U .
+This command only works from outside
+.Nm .
.El
.Sh TERMINFO EXTENSIONS
.Nm
@@ -3592,6 +3615,92 @@ option above and the
.Xr xterm 1
man page.
.El
+.Sh CONTROL MODE
+.Nm
+offers a textual interface called
+.Em control mode .
+This allows applications to communicate with
+.Nm
+using a simple text-only protocol.
+.Pp
+In control mode, a client sends
+.Nm
+commands or command sequences terminated by newlines on standard input.
+Each command will produce one block of output on standard output.
+An output block consists of a
+.Em %begin
+line followed by the output (which may be empty).
+The output block ends with a
+.Em %end
+or
+.Em %error .
+.Em %begin
+and matching
+.Em %end
+or
+.Em %error
+have two arguments: an integer time (as seconds from epoch) and command number.
+For example:
+.Bd -literal -offset indent
+%begin 1363006971 2
+0: ksh* (1 panes) [80x24] [layout b25f,80x24,0,0,2] @2 (active)
+%end 1363006971 2
+.Ed
+.Pp
+In control mode,
+.Nm
+outputs notifications.
+A notification will never occur inside an output block.
+.Pp
+The following notifications are defined:
+.Pp
+.Bl -tag -width Ds
+.It Ic %exit Op Ar reason
+The
+.Nm
+client is exiting immediately, either because it is not attached to any session
+or an error occurred.
+If present,
+.Ar reason
+describes why the client exited.
+.It Ic %layout-change Ar window-id Ar window-layout
+The layout of a window with ID
+.Ar window-id
+changed.
+The new layout is
+.Ar window-layout .
+.It Ic %output Ar pane-id Ar value
+A window pane produced output.
+.Ar value
+contains that output with each byte encoded as two hex digits.
+.It Ic %session-changed Ar session-id Ar name
+The client is now attached to the session with ID
+.Ar session-id ,
+which is named
+.Ar name .
+.It Ic %session-renamed Ar name
+The current session was renamed to
+.Ar name .
+.It Ic %sessions-changed
+A session was created or destroyed.
+.It Ic %unlinked-window-add Ar window-id
+The window with ID
+.Ar window-id
+was created but is not linked to the current session.
+.It Ic %window-add Ar window-id
+The window with ID
+.Ar window-id
+was linked to the current session.
+.It Ic %window-close Ar window-id
+The window with ID
+.Ar window-id
+closed.
+.It Ic %window-renamed Ar window-id Ar name
+The window with ID
+.Ar window-id
+was renamed to
+.Ar name .
+.El
.Sh FILES
.Bl -tag -width "/etc/tmux.confXXX" -compact
.It Pa ~/.tmux.conf
diff --git a/tmux.c b/tmux.c
index f6856605..8ea91ebe 100644
--- a/tmux.c
+++ b/tmux.c
@@ -48,7 +48,7 @@ char socket_path[MAXPATHLEN];
int login_shell;
char *environ_path;
pid_t environ_pid = -1;
-int environ_idx = -1;
+int environ_session_id = -1;
__dead void usage(void);
void parseenvironment(void);
@@ -147,16 +147,16 @@ parseenvironment(void)
{
char *env, path[256];
long pid;
- int idx;
+ int id;
if ((env = getenv("TMUX")) == NULL)
return;
- if (sscanf(env, "%255[^,],%ld,%d", path, &pid, &idx) != 3)
+ if (sscanf(env, "%255[^,],%ld,%d", path, &pid, &id) != 3)
return;
environ_path = xstrdup(path);
environ_pid = pid;
- environ_idx = idx;
+ environ_session_id = id;
}
char *
diff --git a/tmux.h b/tmux.h
index c1ad6628..89860cb8 100644
--- a/tmux.h
+++ b/tmux.h
@@ -462,8 +462,8 @@ enum msgtype {
* Don't forget to bump PROTOCOL_VERSION if any of these change!
*/
struct msg_command_data {
- pid_t pid; /* PID from $TMUX or -1 */
- int idx; /* index from $TMUX or -1 */
+ pid_t pid; /* from $TMUX or -1 */
+ int session_id; /* from $TMUX or -1 */
int argc;
char argv[COMMAND_LENGTH];
@@ -1086,7 +1086,7 @@ struct session_group {
TAILQ_HEAD(session_groups, session_group);
struct session {
- u_int idx;
+ u_int id;
char *name;
char *cwd;
@@ -1412,10 +1412,15 @@ struct cmd_q {
struct cmd_q_item *item;
struct cmd *cmd;
+ time_t time;
+ u_int number;
+
void (*emptyfn)(struct cmd_q *);
void *data;
struct msg_command_data *msgdata;
+
+ TAILQ_ENTRY(cmd_q) waitentry;
};
/* Command definition. */
@@ -1511,7 +1516,7 @@ extern char socket_path[MAXPATHLEN];
extern int login_shell;
extern char *environ_path;
extern pid_t environ_pid;
-extern int environ_idx;
+extern int environ_session_id;
void logfile(const char *);
const char *getshell(void);
int checkshell(const char *);
@@ -1835,6 +1840,7 @@ extern const struct cmd_entry cmd_switch_client_entry;
extern const struct cmd_entry cmd_unbind_key_entry;
extern const struct cmd_entry cmd_unlink_window_entry;
extern const struct cmd_entry cmd_up_pane_entry;
+extern const struct cmd_entry cmd_wait_for_entry;
/* cmd-attach-session.c */
enum cmd_retval cmd_attach_session(struct cmd_q *, const char*, int, int);
@@ -1850,6 +1856,7 @@ int cmdq_free(struct cmd_q *);
void printflike2 cmdq_print(struct cmd_q *, const char *, ...);
void printflike2 cmdq_info(struct cmd_q *, const char *, ...);
void printflike2 cmdq_error(struct cmd_q *, const char *, ...);
+void cmdq_guard(struct cmd_q *, const char *);
void cmdq_run(struct cmd_q *, struct cmd_list *);
void cmdq_append(struct cmd_q *, struct cmd_list *);
int cmdq_continue(struct cmd_q *);
@@ -2284,7 +2291,7 @@ int session_cmp(struct session *, struct session *);
RB_PROTOTYPE(sessions, session, entry, session_cmp);
int session_alive(struct session *);
struct session *session_find(const char *);
-struct session *session_find_by_index(u_int);
+struct session *session_find_by_id(u_int);
struct session *session_create(const char *, const char *, const char *,
struct environ *, struct termios *, int, u_int, u_int,
char **);
diff --git a/tty-keys.c b/tty-keys.c
index 575920e6..fab8c3fb 100644
--- a/tty-keys.c
+++ b/tty-keys.c
@@ -82,6 +82,13 @@ const struct tty_default_key_raw tty_default_raw_keys[] = {
{ "\033[C", KEYC_RIGHT },
{ "\033[D", KEYC_LEFT },
+ /* Other (xterm) "cursor" keys. */
+ { "\033OH", KEYC_HOME },
+ { "\033OF", KEYC_END },
+
+ { "\033[H", KEYC_HOME },
+ { "\033[F", KEYC_END },
+
/* rxvt-style arrow + modifier keys. */
{ "\033Oa", KEYC_UP|KEYC_CTRL },
{ "\033Ob", KEYC_DOWN|KEYC_CTRL },
diff --git a/window-choose.c b/window-choose.c
index b56b2022..3c68d101 100644
--- a/window-choose.c
+++ b/window-choose.c
@@ -859,7 +859,7 @@ window_choose_add_session(struct window_pane *wp, struct client *c,
struct window_choose_data *wcd;
wcd = window_choose_data_create(TREE_SESSION, c, c->session);
- wcd->idx = s->idx;
+ wcd->idx = s->id;
wcd->tree_session = s;
wcd->tree_session->references++;