mirror of
https://github.com/tmate-io/tmate.git
synced 2024-11-23 00:23:08 +01:00
Merge branch 'master' of ssh://git.code.sf.net/p/tmux/tmux-code
This commit is contained in:
commit
543420ccd2
@ -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 \
|
||||
|
2
client.c
2
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;
|
||||
|
@ -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);
|
||||
|
||||
|
39
cmd-queue.c
39
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;
|
||||
|
@ -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++;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
197
cmd-wait-for.c
Normal file
197
cmd-wait-for.c
Normal file
@ -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);
|
||||
}
|
||||
|
25
cmd.c
25
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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
8
format.c
8
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);
|
||||
|
2
grid.c
2
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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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++;
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
14
session.c
14
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);
|
||||
|
117
tmux.1
117
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
|
||||
|
8
tmux.c
8
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 *
|
||||
|
17
tmux.h
17
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 **);
|
||||
|
@ -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 },
|
||||
|
@ -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++;
|
||||
|
Loading…
Reference in New Issue
Block a user