mirror of
https://github.com/tmate-io/tmate.git
synced 2024-11-27 02:23:15 +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-switch-client.c \
|
||||||
cmd-unbind-key.c \
|
cmd-unbind-key.c \
|
||||||
cmd-unlink-window.c \
|
cmd-unlink-window.c \
|
||||||
|
cmd-wait-for.c \
|
||||||
cmd.c \
|
cmd.c \
|
||||||
colour.c \
|
colour.c \
|
||||||
control.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) {
|
if (msg == MSG_COMMAND) {
|
||||||
/* Fill in command line arguments. */
|
/* Fill in command line arguments. */
|
||||||
cmddata.pid = environ_pid;
|
cmddata.pid = environ_pid;
|
||||||
cmddata.idx = environ_idx;
|
cmddata.session_id = environ_session_id;
|
||||||
|
|
||||||
/* Prepare command for server. */
|
/* Prepare command for server. */
|
||||||
cmddata.argc = argc;
|
cmddata.argc = argc;
|
||||||
|
@ -59,19 +59,21 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
struct args *args = self->args;
|
struct args *args = self->args;
|
||||||
struct cmd_if_shell_data *cdata;
|
struct cmd_if_shell_data *cdata;
|
||||||
char *shellcmd;
|
char *shellcmd;
|
||||||
struct session *s;
|
struct session *s = NULL;
|
||||||
struct winlink *wl;
|
struct winlink *wl = NULL;
|
||||||
struct window_pane *wp;
|
struct window_pane *wp = NULL;
|
||||||
struct format_tree *ft;
|
struct format_tree *ft;
|
||||||
|
|
||||||
wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
|
if (args_has(args, 't'))
|
||||||
if (wl == NULL)
|
wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
|
|
||||||
ft = format_create();
|
ft = format_create();
|
||||||
format_session(ft, s);
|
if (s != NULL)
|
||||||
format_winlink(ft, s, wl);
|
format_session(ft, s);
|
||||||
format_window_pane(ft, wp);
|
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]);
|
shellcmd = format_expand(ft, args->argv[0]);
|
||||||
format_free(ft);
|
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);
|
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. */
|
/* Add command list to queue and begin processing if needed. */
|
||||||
void
|
void
|
||||||
cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist)
|
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
|
int
|
||||||
cmdq_continue(struct cmd_q *cmdq)
|
cmdq_continue(struct cmd_q *cmdq)
|
||||||
{
|
{
|
||||||
struct client *c = cmdq->client;
|
|
||||||
struct cmd_q_item *next;
|
struct cmd_q_item *next;
|
||||||
enum cmd_retval retval;
|
enum cmd_retval retval;
|
||||||
int guards, empty;
|
int empty;
|
||||||
char s[1024];
|
char s[1024];
|
||||||
|
|
||||||
guards = 0;
|
|
||||||
if (c != NULL && c->session != NULL)
|
|
||||||
guards = c->flags & CLIENT_CONTROL;
|
|
||||||
|
|
||||||
notify_disable();
|
notify_disable();
|
||||||
|
|
||||||
empty = TAILQ_EMPTY(&cmdq->queue);
|
empty = TAILQ_EMPTY(&cmdq->queue);
|
||||||
@ -209,15 +220,15 @@ cmdq_continue(struct cmd_q *cmdq)
|
|||||||
log_debug("cmdq %p: %s (client %d)", cmdq, s,
|
log_debug("cmdq %p: %s (client %d)", cmdq, s,
|
||||||
cmdq->client != NULL ? cmdq->client->ibuf.fd : -1);
|
cmdq->client != NULL ? cmdq->client->ibuf.fd : -1);
|
||||||
|
|
||||||
if (guards)
|
cmdq->time = time(NULL);
|
||||||
cmdq_print(cmdq, "%%begin");
|
cmdq->number++;
|
||||||
|
|
||||||
|
cmdq_guard(cmdq, "begin");
|
||||||
retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq);
|
retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq);
|
||||||
if (guards) {
|
if (retval == CMD_RETURN_ERROR)
|
||||||
if (retval == CMD_RETURN_ERROR)
|
cmdq_guard(cmdq, "error");
|
||||||
cmdq_print(cmdq, "%%error");
|
else
|
||||||
else
|
cmdq_guard(cmdq, "end");
|
||||||
cmdq_print(cmdq, "%%end");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (retval == CMD_RETURN_ERROR)
|
if (retval == CMD_RETURN_ERROR)
|
||||||
break;
|
break;
|
||||||
|
@ -49,16 +49,17 @@ struct cmd_run_shell_data {
|
|||||||
char *cmd;
|
char *cmd;
|
||||||
struct cmd_q *cmdq;
|
struct cmd_q *cmdq;
|
||||||
int bflag;
|
int bflag;
|
||||||
u_int wp_id;
|
int wp_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
cmd_run_shell_print(struct job *job, const char *msg)
|
cmd_run_shell_print(struct job *job, const char *msg)
|
||||||
{
|
{
|
||||||
struct cmd_run_shell_data *cdata = job->data;
|
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) {
|
if (wp == NULL) {
|
||||||
cmdq_print(cdata->cmdq, "%s", msg);
|
cmdq_print(cdata->cmdq, "%s", msg);
|
||||||
return;
|
return;
|
||||||
@ -76,26 +77,28 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
struct args *args = self->args;
|
struct args *args = self->args;
|
||||||
struct cmd_run_shell_data *cdata;
|
struct cmd_run_shell_data *cdata;
|
||||||
char *shellcmd;
|
char *shellcmd;
|
||||||
struct session *s;
|
struct session *s = NULL;
|
||||||
struct winlink *wl;
|
struct winlink *wl = NULL;
|
||||||
struct window_pane *wp;
|
struct window_pane *wp = NULL;
|
||||||
struct format_tree *ft;
|
struct format_tree *ft;
|
||||||
|
|
||||||
wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
|
if (args_has(args, 't'))
|
||||||
if (wl == NULL)
|
wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
|
|
||||||
ft = format_create();
|
ft = format_create();
|
||||||
format_session(ft, s);
|
if (s != NULL)
|
||||||
format_winlink(ft, s, wl);
|
format_session(ft, s);
|
||||||
format_window_pane(ft, wp);
|
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]);
|
shellcmd = format_expand(ft, args->argv[0]);
|
||||||
format_free(ft);
|
format_free(ft);
|
||||||
|
|
||||||
cdata = xmalloc(sizeof *cdata);
|
cdata = xmalloc(sizeof *cdata);
|
||||||
cdata->cmd = shellcmd;
|
cdata->cmd = shellcmd;
|
||||||
cdata->bflag = args_has(args, 'b');
|
cdata->bflag = args_has(args, 'b');
|
||||||
cdata->wp_id = wp->id;
|
cdata->wp_id = wp != NULL ? (int) wp->id : -1;
|
||||||
|
|
||||||
cdata->cmdq = cmdq;
|
cdata->cmdq = cmdq;
|
||||||
cmdq->references++;
|
cmdq->references++;
|
||||||
|
@ -80,6 +80,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server_unzoom_window(wl->window);
|
||||||
window_set_active_pane(wl->window, wl->window->last);
|
window_set_active_pane(wl->window, wl->window->last);
|
||||||
server_status_window(wl->window);
|
server_status_window(wl->window);
|
||||||
server_redraw_window_borders(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';
|
*strchr(tim, '\n') = '\0';
|
||||||
|
|
||||||
cmdq_print(cmdq, "%2u: %s: %u windows (created %s) [%ux%u] "
|
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);
|
winlink_count(&s->windows), tim, s->sx, s->sy, s->flags);
|
||||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||||
w = wl->window;
|
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_switch_client_entry,
|
||||||
&cmd_unbind_key_entry,
|
&cmd_unbind_key_entry,
|
||||||
&cmd_unlink_window_entry,
|
&cmd_unlink_window_entry,
|
||||||
|
&cmd_wait_for_entry,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -121,6 +122,7 @@ struct session *cmd_choose_session(int);
|
|||||||
struct client *cmd_choose_client(struct clients *);
|
struct client *cmd_choose_client(struct clients *);
|
||||||
struct client *cmd_lookup_client(const char *);
|
struct client *cmd_lookup_client(const char *);
|
||||||
struct session *cmd_lookup_session(const char *, int *);
|
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 *);
|
struct winlink *cmd_lookup_window(struct session *, const char *, int *);
|
||||||
int cmd_lookup_index(struct session *, const char *, int *);
|
int cmd_lookup_index(struct session *, const char *, int *);
|
||||||
struct window_pane *cmd_lookup_paneid(const char *);
|
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. */
|
/* Use the session from the TMUX environment variable. */
|
||||||
if (data != NULL && data->pid == getpid() && data->idx != -1) {
|
if (data != NULL && data->pid == getpid() && data->session_id != -1) {
|
||||||
s = session_find_by_index(data->idx);
|
s = session_find_by_id(data->session_id);
|
||||||
if (s != NULL)
|
if (s != NULL)
|
||||||
return (s);
|
return (s);
|
||||||
}
|
}
|
||||||
@ -549,6 +551,21 @@ cmd_lookup_client(const char *name)
|
|||||||
return (NULL);
|
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. */
|
/* Lookup a session by name. If no session is found, NULL is returned. */
|
||||||
struct session *
|
struct session *
|
||||||
cmd_lookup_session(const char *name, int *ambiguous)
|
cmd_lookup_session(const char *name, int *ambiguous)
|
||||||
@ -557,6 +574,10 @@ cmd_lookup_session(const char *name, int *ambiguous)
|
|||||||
|
|
||||||
*ambiguous = 0;
|
*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
|
* 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
|
* 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(
|
AC_ARG_ENABLE(
|
||||||
static,
|
static,
|
||||||
AC_HELP_STRING(--enable-static, create a static build),
|
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?
|
# Is this gcc?
|
||||||
AM_CONDITIONAL(IS_GCC, test "x$GCC" = xyes)
|
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) {
|
if (winlink_find_by_window(&c->session->windows, wp->window) != NULL) {
|
||||||
message = evbuffer_new();
|
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++)
|
for (i = 0; i < len; i++)
|
||||||
evbuffer_add_printf(message, "%02hhx", buf[i]);
|
evbuffer_add_printf(message, "%02hhx", buf[i]);
|
||||||
control_write_buffer(c, message);
|
control_write_buffer(c, message);
|
||||||
@ -141,7 +141,7 @@ control_notify_window_renamed(struct window *w)
|
|||||||
continue;
|
continue;
|
||||||
s = c->session;
|
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;
|
return;
|
||||||
s = c->session;
|
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
|
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) {
|
if (cmd_string_parse(line, &cmdlist, NULL, 0, &cause) != 0) {
|
||||||
control_write(c, "%%error in line \"%s\": %s", line,
|
c->cmdq->time = time(NULL);
|
||||||
cause);
|
c->cmdq->number++;
|
||||||
|
|
||||||
|
cmdq_guard(c->cmdq, "begin");
|
||||||
|
control_write(c, "parse error: %s", cause);
|
||||||
|
cmdq_guard(c->cmdq, "error");
|
||||||
|
|
||||||
free(cause);
|
free(cause);
|
||||||
} else {
|
} else {
|
||||||
cmdq_run(c->cmdq, cmdlist);
|
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_windows", "%u", winlink_count(&s->windows));
|
||||||
format_add(ft, "session_width", "%u", s->sx);
|
format_add(ft, "session_width", "%u", s->sx);
|
||||||
format_add(ft, "session_height", "%u", s->sy);
|
format_add(ft, "session_height", "%u", s->sy);
|
||||||
|
format_add(ft, "session_id", "%u", s->id);
|
||||||
|
|
||||||
sg = session_group_find(s);
|
sg = session_group_find(s);
|
||||||
format_add(ft, "session_grouped", "%d", sg != NULL);
|
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;
|
struct grid_line *gl;
|
||||||
unsigned long long size;
|
unsigned long long size;
|
||||||
u_int i, idx;
|
u_int i, idx;
|
||||||
const char *cwd, *cmd;
|
const char *cwd;
|
||||||
|
char *cmd;
|
||||||
|
|
||||||
size = 0;
|
size = 0;
|
||||||
for (i = 0; i < gd->hsize; i++) {
|
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);
|
format_add(ft, "pane_start_path", "%s", wp->cwd);
|
||||||
if ((cwd = osdep_get_cwd(wp->fd)) != NULL)
|
if ((cwd = osdep_get_cwd(wp->fd)) != NULL)
|
||||||
format_add(ft, "pane_current_path", "%s", cwd);
|
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);
|
format_add(ft, "pane_current_command", "%s", cmd);
|
||||||
|
free(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
format_add(ft, "cursor_x", "%d", wp->base.cx);
|
format_add(ft, "cursor_x", "%d", wp->base.cx);
|
||||||
format_add(ft, "cursor_y", "%d", wp->base.cy);
|
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);
|
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);
|
memcpy(&lastgc1, &grid_default_cell, sizeof lastgc1);
|
||||||
*lastgc = &lastgc1;
|
*lastgc = &lastgc1;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ layout_dump(struct window *w)
|
|||||||
if (layout_append(w->layout_root, layout, sizeof layout) != 0)
|
if (layout_append(w->layout_root, layout, sizeof layout) != 0)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
xasprintf(&out, "%4x,%s", layout_checksum(layout), layout);
|
xasprintf(&out, "%04x,%s", layout_checksum(layout), layout);
|
||||||
return (out);
|
return (out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,11 +206,11 @@ layout_construct(struct layout_cell *lcparent, const char **layout)
|
|||||||
{
|
{
|
||||||
struct layout_cell *lc, *lcchild;
|
struct layout_cell *lc, *lcchild;
|
||||||
u_int sx, sy, xoff, yoff;
|
u_int sx, sy, xoff, yoff;
|
||||||
|
const char *saved;
|
||||||
|
|
||||||
if (!isdigit((u_char) **layout))
|
if (!isdigit((u_char) **layout))
|
||||||
return (NULL);
|
return (NULL);
|
||||||
if (sscanf(*layout, "%ux%u,%u,%u,%*u", &sx, &sy, &xoff, &yoff) != 4 &&
|
if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4)
|
||||||
sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4)
|
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
while (isdigit((u_char) **layout))
|
while (isdigit((u_char) **layout))
|
||||||
@ -231,9 +231,12 @@ layout_construct(struct layout_cell *lcparent, const char **layout)
|
|||||||
while (isdigit((u_char) **layout))
|
while (isdigit((u_char) **layout))
|
||||||
(*layout)++;
|
(*layout)++;
|
||||||
if (**layout == ',') {
|
if (**layout == ',') {
|
||||||
|
saved = *layout;
|
||||||
(*layout)++;
|
(*layout)++;
|
||||||
while (isdigit((u_char) **layout))
|
while (isdigit((u_char) **layout))
|
||||||
(*layout)++;
|
(*layout)++;
|
||||||
|
if (**layout == 'x')
|
||||||
|
*layout = saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
lc = layout_create_cell(lcparent);
|
lc = layout_create_cell(lcparent);
|
||||||
|
@ -273,6 +273,9 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
|
|||||||
{
|
{
|
||||||
u_int i, yoff;
|
u_int i, yoff;
|
||||||
|
|
||||||
|
if (!window_pane_visible(wp))
|
||||||
|
return;
|
||||||
|
|
||||||
yoff = wp->yoff;
|
yoff = wp->yoff;
|
||||||
if (status_at_line(c) == 0)
|
if (status_at_line(c) == 0)
|
||||||
yoff++;
|
yoff++;
|
||||||
|
@ -153,7 +153,8 @@ server_client_lost(struct client *c)
|
|||||||
|
|
||||||
evbuffer_free (c->stdin_data);
|
evbuffer_free (c->stdin_data);
|
||||||
evbuffer_free (c->stdout_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_new);
|
||||||
status_free_jobs(&c->status_old);
|
status_free_jobs(&c->status_old);
|
||||||
@ -955,6 +956,8 @@ server_client_msg_identify(
|
|||||||
|
|
||||||
if (data->flags & IDENTIFY_CONTROL) {
|
if (data->flags & IDENTIFY_CONTROL) {
|
||||||
c->stdin_callback = control_callback;
|
c->stdin_callback = control_callback;
|
||||||
|
evbuffer_free(c->stderr_data);
|
||||||
|
c->stderr_data = c->stdout_data;
|
||||||
c->flags |= CLIENT_CONTROL;
|
c->flags |= CLIENT_CONTROL;
|
||||||
if (data->flags & IDENTIFY_TERMIOS)
|
if (data->flags & IDENTIFY_TERMIOS)
|
||||||
evbuffer_add_printf(c->stdout_data, "\033P1000p");
|
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");
|
term = options_get_string(&s->options, "default-terminal");
|
||||||
environ_set(env, "TERM", term);
|
environ_set(env, "TERM", term);
|
||||||
|
|
||||||
idx = s->idx;
|
idx = s->id;
|
||||||
} else
|
} else
|
||||||
idx = -1;
|
idx = -1;
|
||||||
pid = getpid();
|
pid = getpid();
|
||||||
@ -546,6 +546,10 @@ server_push_stderr(struct client *c)
|
|||||||
struct msg_stderr_data data;
|
struct msg_stderr_data data;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
|
if (c->stderr_data == c->stdout_data) {
|
||||||
|
server_push_stdout(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
size = EVBUFFER_LENGTH(c->stderr_data);
|
size = EVBUFFER_LENGTH(c->stderr_data);
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return;
|
return;
|
||||||
|
14
session.c
14
session.c
@ -29,7 +29,7 @@
|
|||||||
/* Global session list. */
|
/* Global session list. */
|
||||||
struct sessions sessions;
|
struct sessions sessions;
|
||||||
struct sessions dead_sessions;
|
struct sessions dead_sessions;
|
||||||
u_int next_session;
|
u_int next_session_id;
|
||||||
struct session_groups session_groups;
|
struct session_groups session_groups;
|
||||||
|
|
||||||
struct winlink *session_next_alert(struct winlink *);
|
struct winlink *session_next_alert(struct winlink *);
|
||||||
@ -69,14 +69,14 @@ session_find(const char *name)
|
|||||||
return (RB_FIND(sessions, &sessions, &s));
|
return (RB_FIND(sessions, &sessions, &s));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find session by index. */
|
/* Find session by id. */
|
||||||
struct session *
|
struct session *
|
||||||
session_find_by_index(u_int idx)
|
session_find_by_id(u_int id)
|
||||||
{
|
{
|
||||||
struct session *s;
|
struct session *s;
|
||||||
|
|
||||||
RB_FOREACH(s, sessions, &sessions) {
|
RB_FOREACH(s, sessions, &sessions) {
|
||||||
if (s->idx == idx)
|
if (s->id == id)
|
||||||
return (s);
|
return (s);
|
||||||
}
|
}
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@ -120,13 +120,13 @@ session_create(const char *name, const char *cmd, const char *cwd,
|
|||||||
|
|
||||||
if (name != NULL) {
|
if (name != NULL) {
|
||||||
s->name = xstrdup(name);
|
s->name = xstrdup(name);
|
||||||
s->idx = next_session++;
|
s->id = next_session_id++;
|
||||||
} else {
|
} else {
|
||||||
s->name = NULL;
|
s->name = NULL;
|
||||||
do {
|
do {
|
||||||
s->idx = next_session++;
|
s->id = next_session_id++;
|
||||||
free (s->name);
|
free (s->name);
|
||||||
xasprintf(&s->name, "%u", s->idx);
|
xasprintf(&s->name, "%u", s->id);
|
||||||
} while (RB_FIND(sessions, &sessions, s) != NULL);
|
} while (RB_FIND(sessions, &sessions, s) != NULL);
|
||||||
}
|
}
|
||||||
RB_INSERT(sessions, &sessions, s);
|
RB_INSERT(sessions, &sessions, s);
|
||||||
|
117
tmux.1
117
tmux.1
@ -23,7 +23,7 @@
|
|||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm tmux
|
.Nm tmux
|
||||||
.Bk -words
|
.Bk -words
|
||||||
.Op Fl 28lquvV
|
.Op Fl 28lCquvV
|
||||||
.Op Fl c Ar shell-command
|
.Op Fl c Ar shell-command
|
||||||
.Op Fl f Ar file
|
.Op Fl f Ar file
|
||||||
.Op Fl L Ar socket-name
|
.Op Fl L Ar socket-name
|
||||||
@ -102,6 +102,11 @@ to assume the terminal supports 256 colours.
|
|||||||
Like
|
Like
|
||||||
.Fl 2 ,
|
.Fl 2 ,
|
||||||
but indicates that the terminal supports 88 colours.
|
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
|
.It Fl c Ar shell-command
|
||||||
Execute
|
Execute
|
||||||
.Ar shell-command
|
.Ar shell-command
|
||||||
@ -369,9 +374,9 @@ Clients may be listed with the
|
|||||||
command.
|
command.
|
||||||
.Pp
|
.Pp
|
||||||
.Ar target-session
|
.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
|
.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 ,
|
.Ar target-client ,
|
||||||
in which case the session attached to the client is used.
|
in which case the session attached to the client is used.
|
||||||
When looking for the session name,
|
When looking for the session name,
|
||||||
@ -1619,7 +1624,7 @@ is given in lines or cells (the default is 1).
|
|||||||
.Pp
|
.Pp
|
||||||
With
|
With
|
||||||
.Fl Z ,
|
.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.
|
normal position in the layout.
|
||||||
.It Xo Ic respawn-pane
|
.It Xo Ic respawn-pane
|
||||||
.Op Fl k
|
.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_group" Ta "Number of session group"
|
||||||
.It Li "session_grouped" Ta "1 if session in a group"
|
.It Li "session_grouped" Ta "1 if session in a group"
|
||||||
.It Li "session_height" Ta "Height of session"
|
.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_name" Ta "Name of session"
|
||||||
.It Li "session_width" Ta "Width of session"
|
.It Li "session_width" Ta "Width of session"
|
||||||
.It Li "session_windows" Ta "Number of windows in 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
|
.It Ic server-info
|
||||||
.D1 (alias: Ic info )
|
.D1 (alias: Ic info )
|
||||||
Show server information and terminal details.
|
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
|
.El
|
||||||
.Sh TERMINFO EXTENSIONS
|
.Sh TERMINFO EXTENSIONS
|
||||||
.Nm
|
.Nm
|
||||||
@ -3592,6 +3615,92 @@ option above and the
|
|||||||
.Xr xterm 1
|
.Xr xterm 1
|
||||||
man page.
|
man page.
|
||||||
.El
|
.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
|
.Sh FILES
|
||||||
.Bl -tag -width "/etc/tmux.confXXX" -compact
|
.Bl -tag -width "/etc/tmux.confXXX" -compact
|
||||||
.It Pa ~/.tmux.conf
|
.It Pa ~/.tmux.conf
|
||||||
|
8
tmux.c
8
tmux.c
@ -48,7 +48,7 @@ char socket_path[MAXPATHLEN];
|
|||||||
int login_shell;
|
int login_shell;
|
||||||
char *environ_path;
|
char *environ_path;
|
||||||
pid_t environ_pid = -1;
|
pid_t environ_pid = -1;
|
||||||
int environ_idx = -1;
|
int environ_session_id = -1;
|
||||||
|
|
||||||
__dead void usage(void);
|
__dead void usage(void);
|
||||||
void parseenvironment(void);
|
void parseenvironment(void);
|
||||||
@ -147,16 +147,16 @@ parseenvironment(void)
|
|||||||
{
|
{
|
||||||
char *env, path[256];
|
char *env, path[256];
|
||||||
long pid;
|
long pid;
|
||||||
int idx;
|
int id;
|
||||||
|
|
||||||
if ((env = getenv("TMUX")) == NULL)
|
if ((env = getenv("TMUX")) == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (sscanf(env, "%255[^,],%ld,%d", path, &pid, &idx) != 3)
|
if (sscanf(env, "%255[^,],%ld,%d", path, &pid, &id) != 3)
|
||||||
return;
|
return;
|
||||||
environ_path = xstrdup(path);
|
environ_path = xstrdup(path);
|
||||||
environ_pid = pid;
|
environ_pid = pid;
|
||||||
environ_idx = idx;
|
environ_session_id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
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!
|
* Don't forget to bump PROTOCOL_VERSION if any of these change!
|
||||||
*/
|
*/
|
||||||
struct msg_command_data {
|
struct msg_command_data {
|
||||||
pid_t pid; /* PID from $TMUX or -1 */
|
pid_t pid; /* from $TMUX or -1 */
|
||||||
int idx; /* index from $TMUX or -1 */
|
int session_id; /* from $TMUX or -1 */
|
||||||
|
|
||||||
int argc;
|
int argc;
|
||||||
char argv[COMMAND_LENGTH];
|
char argv[COMMAND_LENGTH];
|
||||||
@ -1086,7 +1086,7 @@ struct session_group {
|
|||||||
TAILQ_HEAD(session_groups, session_group);
|
TAILQ_HEAD(session_groups, session_group);
|
||||||
|
|
||||||
struct session {
|
struct session {
|
||||||
u_int idx;
|
u_int id;
|
||||||
|
|
||||||
char *name;
|
char *name;
|
||||||
char *cwd;
|
char *cwd;
|
||||||
@ -1412,10 +1412,15 @@ struct cmd_q {
|
|||||||
struct cmd_q_item *item;
|
struct cmd_q_item *item;
|
||||||
struct cmd *cmd;
|
struct cmd *cmd;
|
||||||
|
|
||||||
|
time_t time;
|
||||||
|
u_int number;
|
||||||
|
|
||||||
void (*emptyfn)(struct cmd_q *);
|
void (*emptyfn)(struct cmd_q *);
|
||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
struct msg_command_data *msgdata;
|
struct msg_command_data *msgdata;
|
||||||
|
|
||||||
|
TAILQ_ENTRY(cmd_q) waitentry;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Command definition. */
|
/* Command definition. */
|
||||||
@ -1511,7 +1516,7 @@ extern char socket_path[MAXPATHLEN];
|
|||||||
extern int login_shell;
|
extern int login_shell;
|
||||||
extern char *environ_path;
|
extern char *environ_path;
|
||||||
extern pid_t environ_pid;
|
extern pid_t environ_pid;
|
||||||
extern int environ_idx;
|
extern int environ_session_id;
|
||||||
void logfile(const char *);
|
void logfile(const char *);
|
||||||
const char *getshell(void);
|
const char *getshell(void);
|
||||||
int checkshell(const char *);
|
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_unbind_key_entry;
|
||||||
extern const struct cmd_entry cmd_unlink_window_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_up_pane_entry;
|
||||||
|
extern const struct cmd_entry cmd_wait_for_entry;
|
||||||
|
|
||||||
/* cmd-attach-session.c */
|
/* cmd-attach-session.c */
|
||||||
enum cmd_retval cmd_attach_session(struct cmd_q *, const char*, int, int);
|
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_print(struct cmd_q *, const char *, ...);
|
||||||
void printflike2 cmdq_info(struct cmd_q *, const char *, ...);
|
void printflike2 cmdq_info(struct cmd_q *, const char *, ...);
|
||||||
void printflike2 cmdq_error(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_run(struct cmd_q *, struct cmd_list *);
|
||||||
void cmdq_append(struct cmd_q *, struct cmd_list *);
|
void cmdq_append(struct cmd_q *, struct cmd_list *);
|
||||||
int cmdq_continue(struct cmd_q *);
|
int cmdq_continue(struct cmd_q *);
|
||||||
@ -2284,7 +2291,7 @@ int session_cmp(struct session *, struct session *);
|
|||||||
RB_PROTOTYPE(sessions, session, entry, session_cmp);
|
RB_PROTOTYPE(sessions, session, entry, session_cmp);
|
||||||
int session_alive(struct session *);
|
int session_alive(struct session *);
|
||||||
struct session *session_find(const char *);
|
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 session *session_create(const char *, const char *, const char *,
|
||||||
struct environ *, struct termios *, int, u_int, u_int,
|
struct environ *, struct termios *, int, u_int, u_int,
|
||||||
char **);
|
char **);
|
||||||
|
@ -82,6 +82,13 @@ const struct tty_default_key_raw tty_default_raw_keys[] = {
|
|||||||
{ "\033[C", KEYC_RIGHT },
|
{ "\033[C", KEYC_RIGHT },
|
||||||
{ "\033[D", KEYC_LEFT },
|
{ "\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. */
|
/* rxvt-style arrow + modifier keys. */
|
||||||
{ "\033Oa", KEYC_UP|KEYC_CTRL },
|
{ "\033Oa", KEYC_UP|KEYC_CTRL },
|
||||||
{ "\033Ob", KEYC_DOWN|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;
|
struct window_choose_data *wcd;
|
||||||
|
|
||||||
wcd = window_choose_data_create(TREE_SESSION, c, c->session);
|
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 = s;
|
||||||
wcd->tree_session->references++;
|
wcd->tree_session->references++;
|
||||||
|
Loading…
Reference in New Issue
Block a user