mirror of
https://github.com/tmate-io/tmate.git
synced 2025-02-08 22:40:02 +01:00
Tidy up and improve target (-t) argument parsing:
- move the code back into cmd.c and merge with the existing functions where possible; - accept "-tttyp0" as well as "-t/dev/ttyp0" for clients; - when looking up session names, try an exact match first, and if that fails look for it as an fnmatch pattern and then as the start of a name - if more that one session matches an error is given; so if there is one session called "mysession", -tmysession, -tmysess, -tmysess* are equivalent but if there is also "mysession2", the last two are errors; - similarly for windows, if the argument is not a valid index or exact window name match, try it against the window names as an fnmatch pattern and a prefix.
This commit is contained in:
parent
359285928b
commit
023d8d38ec
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
|||||||
# $OpenBSD$
|
# $OpenBSD$
|
||||||
|
|
||||||
PROG= tmux
|
PROG= tmux
|
||||||
SRCS= arg.c attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \
|
SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \
|
||||||
client-msg.c client.c clock.c cmd-attach-session.c cmd-bind-key.c \
|
client-msg.c client.c clock.c cmd-attach-session.c cmd-bind-key.c \
|
||||||
cmd-break-pane.c cmd-choose-session.c cmd-choose-window.c \
|
cmd-break-pane.c cmd-choose-session.c cmd-choose-window.c \
|
||||||
cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \
|
cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \
|
||||||
|
194
arg.c
194
arg.c
@ -1,194 +0,0 @@
|
|||||||
/* $OpenBSD$ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
|
||||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#include <fnmatch.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "tmux.h"
|
|
||||||
|
|
||||||
struct client *arg_lookup_client(const char *);
|
|
||||||
struct session *arg_lookup_session(const char *);
|
|
||||||
|
|
||||||
struct client *
|
|
||||||
arg_lookup_client(const char *name)
|
|
||||||
{
|
|
||||||
struct client *c;
|
|
||||||
u_int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
|
||||||
c = ARRAY_ITEM(&clients, i);
|
|
||||||
if (c != NULL && strcmp(name, c->tty.path) == 0)
|
|
||||||
return (c);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct session *
|
|
||||||
arg_lookup_session(const char *name)
|
|
||||||
{
|
|
||||||
struct session *s, *newest = NULL;
|
|
||||||
struct timeval *tv;
|
|
||||||
u_int i;
|
|
||||||
|
|
||||||
tv = NULL;
|
|
||||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
|
||||||
s = ARRAY_ITEM(&sessions, i);
|
|
||||||
if (s == NULL || fnmatch(name, s->name, 0) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (tv == NULL || timercmp(&s->tv, tv, >)) {
|
|
||||||
newest = s;
|
|
||||||
tv = &s->tv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (newest);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct client *
|
|
||||||
arg_parse_client(const char *arg)
|
|
||||||
{
|
|
||||||
struct client *c;
|
|
||||||
char *arg2;
|
|
||||||
size_t n;
|
|
||||||
|
|
||||||
if (arg != NULL && (arg[0] != ':' || arg[1] != '\0')) {
|
|
||||||
arg2 = xstrdup(arg);
|
|
||||||
|
|
||||||
/* Trim a trailing : if any from the argument. */
|
|
||||||
n = strlen(arg2);
|
|
||||||
if (n && arg2[n - 1] == ':')
|
|
||||||
arg2[n - 1] = '\0';
|
|
||||||
|
|
||||||
/* Try and look up the client name. */
|
|
||||||
c = arg_lookup_client(arg2);
|
|
||||||
xfree(arg2);
|
|
||||||
return (c);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct session *
|
|
||||||
arg_parse_session(const char *arg)
|
|
||||||
{
|
|
||||||
struct session *s;
|
|
||||||
struct client *c;
|
|
||||||
char *arg2;
|
|
||||||
size_t n;
|
|
||||||
|
|
||||||
if (arg != NULL && (arg[0] != ':' || arg[1] != '\0')) {
|
|
||||||
arg2 = xstrdup(arg);
|
|
||||||
|
|
||||||
/* Trim a trailing : if any from the argument. */
|
|
||||||
n = strlen(arg2);
|
|
||||||
if (n && arg2[n - 1] == ':')
|
|
||||||
arg2[n - 1] = '\0';
|
|
||||||
|
|
||||||
/* See if the argument matches a session. */
|
|
||||||
if ((s = arg_lookup_session(arg2)) != NULL) {
|
|
||||||
xfree(arg2);
|
|
||||||
return (s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If not try a client. */
|
|
||||||
if ((c = arg_lookup_client(arg2)) != NULL) {
|
|
||||||
xfree(arg2);
|
|
||||||
return (c->session);
|
|
||||||
}
|
|
||||||
|
|
||||||
xfree(arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
arg_parse_window(const char *arg, struct session **s, int *idx)
|
|
||||||
{
|
|
||||||
char *arg2, *ptr;
|
|
||||||
const char *errstr;
|
|
||||||
|
|
||||||
*idx = -1;
|
|
||||||
|
|
||||||
/* Handle no argument or a single :. */
|
|
||||||
if (arg == NULL || (arg[0] == ':' && arg[1] == '\0')) {
|
|
||||||
*s = arg_parse_session(NULL);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the separator if any. */
|
|
||||||
arg2 = xstrdup(arg);
|
|
||||||
ptr = strrchr(arg2, ':');
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If it is first, this means no session name, so use current session
|
|
||||||
* and try to convert the rest as index.
|
|
||||||
*/
|
|
||||||
if (ptr == arg2) {
|
|
||||||
*idx = strtonum(ptr + 1, 0, INT_MAX, &errstr);
|
|
||||||
if (errstr != NULL) {
|
|
||||||
xfree(arg2);
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
xfree(arg2);
|
|
||||||
*s = arg_parse_session(NULL);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If missing, try as an index, else look up immediately. */
|
|
||||||
if (ptr == NULL) {
|
|
||||||
*idx = strtonum(arg2, 0, INT_MAX, &errstr);
|
|
||||||
if (errstr == NULL) {
|
|
||||||
/* This is good as an index; use current session. */
|
|
||||||
xfree(arg2);
|
|
||||||
*s = arg_parse_session(NULL);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
*idx = -1;
|
|
||||||
goto lookup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If last, strip it and look up as a session. */
|
|
||||||
if (ptr[1] == '\0') {
|
|
||||||
*ptr = '\0';
|
|
||||||
goto lookup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Present but not first and not last. Break and convert both. */
|
|
||||||
*ptr = '\0';
|
|
||||||
*idx = strtonum(ptr + 1, 0, INT_MAX, &errstr);
|
|
||||||
if (errstr != NULL) {
|
|
||||||
xfree(arg2);
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
lookup:
|
|
||||||
/* Look up as session. */
|
|
||||||
*s = arg_parse_session(arg2);
|
|
||||||
xfree(arg2);
|
|
||||||
if (*s == NULL)
|
|
||||||
return (1);
|
|
||||||
return (0);
|
|
||||||
}
|
|
@ -52,19 +52,8 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
|||||||
|
|
||||||
if ((wl_src = cmd_find_window(ctx, data->src, NULL)) == NULL)
|
if ((wl_src = cmd_find_window(ctx, data->src, NULL)) == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2)
|
||||||
if (arg_parse_window(data->dst, &dst, &idx) != 0) {
|
|
||||||
ctx->error(ctx, "bad window: %s", data->dst);
|
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
|
||||||
if (dst == NULL)
|
|
||||||
dst = ctx->cursession;
|
|
||||||
if (dst == NULL)
|
|
||||||
dst = cmd_current_session(ctx);
|
|
||||||
if (dst == NULL) {
|
|
||||||
ctx->error(ctx, "session not found: %s", data->dst);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
wl_dst = NULL;
|
wl_dst = NULL;
|
||||||
if (idx != -1)
|
if (idx != -1)
|
||||||
|
@ -54,19 +54,8 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
|||||||
|
|
||||||
if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL)
|
if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2)
|
||||||
if (arg_parse_window(data->dst, &dst, &idx) != 0) {
|
|
||||||
ctx->error(ctx, "bad window: %s", data->dst);
|
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
|
||||||
if (dst == NULL)
|
|
||||||
dst = ctx->cursession;
|
|
||||||
if (dst == NULL)
|
|
||||||
dst = cmd_current_session(ctx);
|
|
||||||
if (dst == NULL) {
|
|
||||||
ctx->error(ctx, "session not found: %s", data->dst);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
wl_dst = NULL;
|
wl_dst = NULL;
|
||||||
if (idx != -1)
|
if (idx != -1)
|
||||||
|
@ -126,18 +126,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
|||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
if (arg_parse_window(data->target, &s, &idx) != 0) {
|
if ((idx = cmd_find_index(ctx, data->target, &s)) == -2)
|
||||||
ctx->error(ctx, "bad window: %s", data->target);
|
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
|
||||||
if (s == NULL)
|
|
||||||
s = ctx->cursession;
|
|
||||||
if (s == NULL)
|
|
||||||
s = cmd_current_session(ctx);
|
|
||||||
if (s == NULL) {
|
|
||||||
ctx->error(ctx, "session not found: %s", data->target);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
wl = NULL;
|
wl = NULL;
|
||||||
if (idx != -1)
|
if (idx != -1)
|
||||||
|
420
cmd.c
420
cmd.c
@ -19,6 +19,8 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <paths.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -100,6 +102,11 @@ const struct cmd_entry *cmd_table[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct session *cmd_newest_session(void);
|
||||||
|
struct client *cmd_lookup_client(const char *);
|
||||||
|
struct session *cmd_lookup_session(const char *, int *);
|
||||||
|
struct winlink *cmd_lookup_window(struct session *, const char *, int *);
|
||||||
|
|
||||||
struct cmd *
|
struct cmd *
|
||||||
cmd_parse(int argc, char **argv, char **cause)
|
cmd_parse(int argc, char **argv, char **cause)
|
||||||
{
|
{
|
||||||
@ -294,106 +301,421 @@ cmd_recv_string(struct buffer *b)
|
|||||||
return (s);
|
return (s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Figure out the current session. Use: 1) the current session, if the command
|
||||||
|
* context has one; 2) the session specified in the TMUX variable from the
|
||||||
|
* environment (as passed from the client); 3) the newest session.
|
||||||
|
*/
|
||||||
struct session *
|
struct session *
|
||||||
cmd_current_session(struct cmd_ctx *ctx)
|
cmd_current_session(struct cmd_ctx *ctx)
|
||||||
{
|
{
|
||||||
struct msg_command_data *data = ctx->msgdata;
|
struct msg_command_data *data = ctx->msgdata;
|
||||||
struct timeval *tv;
|
struct session *s;
|
||||||
struct session *s, *newest = NULL;
|
|
||||||
u_int i;
|
|
||||||
|
|
||||||
if (ctx->cursession != NULL)
|
if (ctx->cursession != NULL)
|
||||||
return (ctx->cursession);
|
return (ctx->cursession);
|
||||||
|
|
||||||
if (data != NULL && data->pid != -1) {
|
if (data != NULL && data->pid != -1) {
|
||||||
if (data->pid != getpid()) {
|
if (data->pid != getpid())
|
||||||
ctx->error(ctx, "wrong server: %ld", (long) data->pid);
|
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
if (data->idx > ARRAY_LENGTH(&sessions))
|
||||||
if (data->idx > ARRAY_LENGTH(&sessions)) {
|
|
||||||
ctx->error(ctx, "index out of range: %d", data->idx);
|
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL)
|
||||||
if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL) {
|
|
||||||
ctx->error(ctx, "session doesn't exist: %u", data->idx);
|
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
|
||||||
return (s);
|
return (s);
|
||||||
}
|
}
|
||||||
|
|
||||||
tv = NULL;
|
return (cmd_newest_session());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the newest session. */
|
||||||
|
struct session *
|
||||||
|
cmd_newest_session(void)
|
||||||
|
{
|
||||||
|
struct session *s, *snewest;
|
||||||
|
struct timeval *tv = NULL;
|
||||||
|
u_int i;
|
||||||
|
|
||||||
|
snewest = NULL;
|
||||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||||
s = ARRAY_ITEM(&sessions, i);
|
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
|
||||||
if (s != NULL && (tv == NULL || timercmp(&s->tv, tv, >))) {
|
continue;
|
||||||
newest = ARRAY_ITEM(&sessions, i);
|
|
||||||
|
if (tv == NULL || timercmp(&s->tv, tv, >)) {
|
||||||
|
snewest = s;
|
||||||
tv = &s->tv;
|
tv = &s->tv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (newest);
|
|
||||||
|
return (snewest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find the target client or report an error and return NULL. */
|
||||||
struct client *
|
struct client *
|
||||||
cmd_find_client(struct cmd_ctx *ctx, const char *arg)
|
cmd_find_client(struct cmd_ctx *ctx, const char *arg)
|
||||||
{
|
{
|
||||||
struct client *c;
|
struct client *c;
|
||||||
|
char *tmparg;
|
||||||
|
size_t arglen;
|
||||||
|
|
||||||
|
/* A NULL argument means the current client. */
|
||||||
if (arg == NULL)
|
if (arg == NULL)
|
||||||
c = ctx->curclient;
|
return (ctx->curclient);
|
||||||
else {
|
tmparg = xstrdup(arg);
|
||||||
if ((c = arg_parse_client(arg)) == NULL) {
|
|
||||||
if (arg != NULL)
|
/* Trim a single trailing colon if any. */
|
||||||
ctx->error(ctx, "client not found: %s", arg);
|
arglen = strlen(tmparg);
|
||||||
else
|
if (arglen != 0 && tmparg[arglen - 1] == ':')
|
||||||
ctx->error(ctx, "no client found");
|
tmparg[arglen - 1] = '\0';
|
||||||
}
|
|
||||||
}
|
/* Find the client, if any. */
|
||||||
|
c = cmd_lookup_client(tmparg);
|
||||||
|
|
||||||
|
/* If no client found, report an error. */
|
||||||
|
if (c == NULL)
|
||||||
|
ctx->error(ctx, "client not found: %s", tmparg);
|
||||||
|
|
||||||
|
xfree(tmparg);
|
||||||
return (c);
|
return (c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lookup a client by device path. Either of a full match and a match without a
|
||||||
|
* leading _PATH_DEV ("/dev/") is accepted.
|
||||||
|
*/
|
||||||
|
struct client *
|
||||||
|
cmd_lookup_client(const char *name)
|
||||||
|
{
|
||||||
|
struct client *c;
|
||||||
|
const char *path;
|
||||||
|
u_int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||||
|
if ((c = ARRAY_ITEM(&clients, i)) == NULL)
|
||||||
|
continue;
|
||||||
|
path = c->tty.path;
|
||||||
|
|
||||||
|
/* Check for exact matches. */
|
||||||
|
if (strcmp(name, path) == 0)
|
||||||
|
return (c);
|
||||||
|
|
||||||
|
/* Check without leading /dev if present. */
|
||||||
|
if (strncmp(path, _PATH_DEV, (sizeof _PATH_DEV) - 1) != 0)
|
||||||
|
continue;
|
||||||
|
if (strcmp(name, path + (sizeof _PATH_DEV) - 1) == 0)
|
||||||
|
return (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
struct session *s, *sfound;
|
||||||
|
u_int i;
|
||||||
|
|
||||||
|
*ambiguous = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for matches. Session names must be unique so an exact match
|
||||||
|
* can't be ambigious and can just be returned.
|
||||||
|
*/
|
||||||
|
sfound = NULL;
|
||||||
|
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||||
|
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Check for an exact match and return it if found. */
|
||||||
|
if (strcmp(name, s->name) == 0)
|
||||||
|
return (s);
|
||||||
|
|
||||||
|
/* Then check for pattern matches. */
|
||||||
|
if (strncmp(name, s->name, strlen(name)) == 0 ||
|
||||||
|
fnmatch(name, s->name, 0) == 0) {
|
||||||
|
if (sfound != NULL) {
|
||||||
|
*ambiguous = 1;
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
sfound = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (sfound);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lookup a window or return -1 if not found or ambigious. First try as an index
|
||||||
|
* and if invalid, use fnmatch or leading prefix.
|
||||||
|
*/
|
||||||
|
struct winlink *
|
||||||
|
cmd_lookup_window(struct session *s, const char *name, int *ambiguous)
|
||||||
|
{
|
||||||
|
struct winlink *wl, *wlfound;
|
||||||
|
struct window *w;
|
||||||
|
const char *errstr;
|
||||||
|
u_int idx;
|
||||||
|
|
||||||
|
*ambiguous = 0;
|
||||||
|
|
||||||
|
/* First see if this is a valid window index in this session. */
|
||||||
|
idx = strtonum(name, 0, INT_MAX, &errstr);
|
||||||
|
if (errstr == NULL) {
|
||||||
|
if ((wl = winlink_find_by_index(&s->windows, idx)) != NULL)
|
||||||
|
return (wl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look for exact matches, error if more than one. */
|
||||||
|
wlfound = NULL;
|
||||||
|
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||||
|
w = wl->window;
|
||||||
|
if (strcmp(name, w->name) == 0) {
|
||||||
|
if (wlfound != NULL) {
|
||||||
|
*ambiguous = 1;
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
wlfound = wl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wlfound != NULL)
|
||||||
|
return (wlfound);
|
||||||
|
|
||||||
|
/* Now look for pattern matches, again error if multiple. */
|
||||||
|
wlfound = NULL;
|
||||||
|
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||||
|
w = wl->window;
|
||||||
|
if (strncmp(name, w->name, strlen(name)) == 0 ||
|
||||||
|
fnmatch(name, w->name, 0) == 0) {
|
||||||
|
if (wlfound != NULL) {
|
||||||
|
*ambiguous = 1;
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
wlfound = wl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wlfound != NULL)
|
||||||
|
return (wlfound);
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the target session or report an error and return NULL. */
|
||||||
struct session *
|
struct session *
|
||||||
cmd_find_session(struct cmd_ctx *ctx, const char *arg)
|
cmd_find_session(struct cmd_ctx *ctx, const char *arg)
|
||||||
{
|
{
|
||||||
struct session *s;
|
struct session *s;
|
||||||
|
struct client *c;
|
||||||
|
char *tmparg;
|
||||||
|
size_t arglen;
|
||||||
|
int ambiguous;
|
||||||
|
|
||||||
|
/* A NULL argument means the current session. */
|
||||||
if (arg == NULL)
|
if (arg == NULL)
|
||||||
s = cmd_current_session(ctx);
|
return (cmd_current_session(ctx));
|
||||||
else {
|
tmparg = xstrdup(arg);
|
||||||
if ((s = arg_parse_session(arg)) == NULL) {
|
|
||||||
if (arg != NULL)
|
/* Trim a single trailing colon if any. */
|
||||||
ctx->error(ctx, "session not found: %s", arg);
|
arglen = strlen(tmparg);
|
||||||
else
|
if (arglen != 0 && tmparg[arglen - 1] == ':')
|
||||||
ctx->error(ctx, "no session found");
|
tmparg[arglen - 1] = '\0';
|
||||||
}
|
|
||||||
|
/* Find the session, if any. */
|
||||||
|
s = cmd_lookup_session(tmparg, &ambiguous);
|
||||||
|
|
||||||
|
/* If it doesn't, try to match it as a client. */
|
||||||
|
if (s == NULL && (c = cmd_lookup_client(tmparg)) != NULL)
|
||||||
|
s = c->session;
|
||||||
|
|
||||||
|
/* If no session found, report an error. */
|
||||||
|
if (s == NULL) {
|
||||||
|
if (ambiguous)
|
||||||
|
ctx->error(ctx, "more than one session: %s", tmparg);
|
||||||
|
else
|
||||||
|
ctx->error(ctx, "session not found: %s", tmparg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xfree(tmparg);
|
||||||
return (s);
|
return (s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find the target session and window or report an error and return NULL. */
|
||||||
struct winlink *
|
struct winlink *
|
||||||
cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp)
|
cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp)
|
||||||
{
|
{
|
||||||
struct session *s;
|
struct session *s;
|
||||||
struct winlink *wl;
|
struct winlink *wl;
|
||||||
int idx;
|
const char *winptr;
|
||||||
|
char *sessptr = NULL;
|
||||||
|
int ambiguous = 0;
|
||||||
|
|
||||||
wl = NULL;
|
/*
|
||||||
if (arg_parse_window(arg, &s, &idx) != 0) {
|
* Find the current session. There must always be a current session, if
|
||||||
ctx->error(ctx, "bad window: %s", arg);
|
* it can't be found, report an error.
|
||||||
|
*/
|
||||||
|
if ((s = cmd_current_session(ctx)) == NULL) {
|
||||||
|
ctx->error(ctx, "can't establish current session");
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
if (s == NULL)
|
|
||||||
s = ctx->cursession;
|
/* A NULL argument means the current session and window. */
|
||||||
if (s == NULL)
|
if (arg == NULL) {
|
||||||
s = cmd_current_session(ctx);
|
if (sp != NULL)
|
||||||
if (s == NULL)
|
*sp = s;
|
||||||
return (NULL);
|
return (s->curw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Time to look at the argument. If it is empty, that is an error. */
|
||||||
|
if (*arg == '\0')
|
||||||
|
goto not_found;
|
||||||
|
|
||||||
|
/* Find the separating colon. If none, assume the current session. */
|
||||||
|
winptr = strchr(arg, ':');
|
||||||
|
if (winptr == NULL)
|
||||||
|
winptr = xstrdup(arg);
|
||||||
|
else {
|
||||||
|
winptr++; /* skip : */
|
||||||
|
sessptr = xstrdup(arg);
|
||||||
|
*strchr(sessptr, ':') = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("%s: winptr=%s, sessptr=%s", __func__, winptr, sessptr);
|
||||||
|
|
||||||
|
/* Try to lookup the session if present. */
|
||||||
|
if (sessptr != NULL && *sessptr != '\0') {
|
||||||
|
if ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL)
|
||||||
|
goto no_session;
|
||||||
|
}
|
||||||
if (sp != NULL)
|
if (sp != NULL)
|
||||||
*sp = s;
|
*sp = s;
|
||||||
|
|
||||||
if (idx == -1)
|
/*
|
||||||
|
* Then work out the window. An empty string is the current window,
|
||||||
|
* otherwise try to look it up in the session.
|
||||||
|
*/
|
||||||
|
if (winptr == NULL || *winptr == '\0')
|
||||||
wl = s->curw;
|
wl = s->curw;
|
||||||
else
|
else if ((wl = cmd_lookup_window(s, winptr, &ambiguous)) == NULL)
|
||||||
wl = winlink_find_by_index(&s->windows, idx);
|
goto not_found;
|
||||||
if (wl == NULL)
|
|
||||||
ctx->error(ctx, "window not found: %s:%d", s->name, idx);
|
if (sessptr != NULL)
|
||||||
|
xfree(sessptr);
|
||||||
return (wl);
|
return (wl);
|
||||||
|
|
||||||
|
no_session:
|
||||||
|
if (ambiguous)
|
||||||
|
ctx->error(ctx, "multiple sessions: %s", sessptr);
|
||||||
|
else
|
||||||
|
ctx->error(ctx, "session not found: %s", sessptr);
|
||||||
|
if (sessptr != NULL)
|
||||||
|
xfree(sessptr);
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
not_found:
|
||||||
|
if (ambiguous)
|
||||||
|
ctx->error(ctx, "multiple windows: %s", arg);
|
||||||
|
else
|
||||||
|
ctx->error(ctx, "window not found: %s", arg);
|
||||||
|
if (sessptr != NULL)
|
||||||
|
xfree(sessptr);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the target session and window index, whether or not it exists in the
|
||||||
|
* session. Return -2 on error or -1 if no window index is specified. This is
|
||||||
|
* used when parsing an argument for a window target that may not be exist (for
|
||||||
|
* example it is going to be created).
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp)
|
||||||
|
{
|
||||||
|
struct session *s;
|
||||||
|
struct winlink *wl;
|
||||||
|
const char *winptr, *errstr;
|
||||||
|
char *sessptr = NULL;
|
||||||
|
int idx, ambiguous = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the current session. There must always be a current session, if
|
||||||
|
* it can't be found, report an error.
|
||||||
|
*/
|
||||||
|
if ((s = cmd_current_session(ctx)) == NULL) {
|
||||||
|
ctx->error(ctx, "can't establish current session");
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A NULL argument means the current session and "no window" (-1). */
|
||||||
|
if (arg == NULL) {
|
||||||
|
if (sp != NULL)
|
||||||
|
*sp = s;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Time to look at the argument. If it is empty, that is an error. */
|
||||||
|
if (*arg == '\0')
|
||||||
|
goto not_found;
|
||||||
|
|
||||||
|
/* Find the separating colon. If none, assume the current session. */
|
||||||
|
winptr = strchr(arg, ':');
|
||||||
|
if (winptr == NULL)
|
||||||
|
winptr = xstrdup(arg);
|
||||||
|
else {
|
||||||
|
winptr++; /* skip : */
|
||||||
|
sessptr = xstrdup(arg);
|
||||||
|
*strchr(sessptr, ':') = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("%s: winptr=%s, sessptr=%s", __func__, winptr, sessptr);
|
||||||
|
|
||||||
|
/* Try to lookup the session if present. */
|
||||||
|
if (sessptr != NULL && *sessptr != '\0') {
|
||||||
|
if ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL)
|
||||||
|
goto no_session;
|
||||||
|
}
|
||||||
|
if (sp != NULL)
|
||||||
|
*sp = s;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Then work out the window. No : means "no window" (-1), an empty
|
||||||
|
* string is the current window, otherwise try to look it up in the
|
||||||
|
* session.
|
||||||
|
*/
|
||||||
|
if (winptr == NULL)
|
||||||
|
idx = -1;
|
||||||
|
else if (*winptr == '\0')
|
||||||
|
idx = s->curw->idx;
|
||||||
|
else if ((wl = cmd_lookup_window(s, winptr, &ambiguous)) == NULL) {
|
||||||
|
if (ambiguous)
|
||||||
|
goto not_found;
|
||||||
|
/* Don't care it doesn't exist if this is a valid index. */
|
||||||
|
idx = strtonum(winptr, 0, INT_MAX, &errstr);
|
||||||
|
if (errstr != NULL) {
|
||||||
|
ctx->error(ctx, "index %s: %s", errstr, winptr);
|
||||||
|
idx = -2;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
idx = wl->idx;
|
||||||
|
|
||||||
|
if (sessptr != NULL)
|
||||||
|
xfree(sessptr);
|
||||||
|
return (idx);
|
||||||
|
|
||||||
|
no_session:
|
||||||
|
if (ambiguous)
|
||||||
|
ctx->error(ctx, "multiple sessions: %s", sessptr);
|
||||||
|
else
|
||||||
|
ctx->error(ctx, "session not found: %s", sessptr);
|
||||||
|
if (sessptr != NULL)
|
||||||
|
xfree(sessptr);
|
||||||
|
return (-2);
|
||||||
|
|
||||||
|
not_found:
|
||||||
|
if (ambiguous)
|
||||||
|
ctx->error(ctx, "multiple windows: %s", arg);
|
||||||
|
else
|
||||||
|
ctx->error(ctx, "window not found: %s", arg);
|
||||||
|
if (sessptr != NULL)
|
||||||
|
xfree(sessptr);
|
||||||
|
return (-2);
|
||||||
}
|
}
|
||||||
|
41
tmux.1
41
tmux.1
@ -500,8 +500,14 @@ These specify the client, session or window which a command should affect.
|
|||||||
.Ar target-client
|
.Ar target-client
|
||||||
is the name of the
|
is the name of the
|
||||||
.Xr pty 4
|
.Xr pty 4
|
||||||
file to which the client is connected, for example
|
file to which the client is connected, for example either of
|
||||||
|
.Pa /dev/ttyp1
|
||||||
|
or
|
||||||
|
.Pa ttyp1
|
||||||
|
for the client attached to
|
||||||
.Pa /dev/ttyp1 .
|
.Pa /dev/ttyp1 .
|
||||||
|
If no client is specified, the current client is chosen, if possible, or an
|
||||||
|
error is reported.
|
||||||
Clients may be listed with the
|
Clients may be listed with the
|
||||||
.Ic list-clients
|
.Ic list-clients
|
||||||
command.
|
command.
|
||||||
@ -509,23 +515,32 @@ command.
|
|||||||
.Ar target-session
|
.Ar target-session
|
||||||
is either the name of a session (as listed by the
|
is either the name of a session (as listed by the
|
||||||
.Ic list-sessions
|
.Ic list-sessions
|
||||||
command) or the name of a client,
|
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.
|
||||||
An
|
When looking for the session name,
|
||||||
|
.Nm
|
||||||
|
initially searches for an exact match; if none is found, the session names
|
||||||
|
are checked for any for which
|
||||||
|
.Ar target-session
|
||||||
|
is a prefix or for which it matches as an
|
||||||
.Xr fnmatch 3
|
.Xr fnmatch 3
|
||||||
pattern may be used to match the session name.
|
pattern.
|
||||||
If a session is omitted when required,
|
If a single match is found, it is used as the target session; multiple matches
|
||||||
.Nm tmux
|
produce an error
|
||||||
attempts to use the current session; if no current session is available, the
|
If a session is omitted, the current session is used if available; if no
|
||||||
most recently created is chosen.
|
current session is available, the most recently created is chosen.
|
||||||
If no client is specified, the current client is chosen, if possible, or an
|
|
||||||
error is reported.
|
|
||||||
.Pp
|
.Pp
|
||||||
.Ar target-window
|
.Ar target-window
|
||||||
specifies a window in the form
|
specifies a window in the form
|
||||||
.Em session Ns \&: Ns Em index ,
|
.Em session Ns \&: Ns Em window ,
|
||||||
for example mysession:1.
|
where
|
||||||
|
.Em window
|
||||||
|
is a window index, for example mysession:1, or a window name,
|
||||||
|
.Xr fnmatch 3
|
||||||
|
pattern, or prefix, such as mysession:mywin[0-3].
|
||||||
|
If the latter, the window is looked up in a similar fashion to session name
|
||||||
|
searches described above.
|
||||||
The session is in the same form as for
|
The session is in the same form as for
|
||||||
.Ar target-session .
|
.Ar target-session .
|
||||||
.Em session ,
|
.Em session ,
|
||||||
@ -536,7 +551,7 @@ If
|
|||||||
is omitted, the same rules as for
|
is omitted, the same rules as for
|
||||||
.Ar target-session
|
.Ar target-session
|
||||||
are followed; if
|
are followed; if
|
||||||
.Em index
|
.Em window
|
||||||
is not present, the current window for the given session is used.
|
is not present, the current window for the given session is used.
|
||||||
When the argument does not contain a colon,
|
When the argument does not contain a colon,
|
||||||
.Nm
|
.Nm
|
||||||
|
9
tmux.h
9
tmux.h
@ -1076,11 +1076,6 @@ int paste_replace(struct paste_stack *, u_int, char *);
|
|||||||
/* clock.c */
|
/* clock.c */
|
||||||
void clock_draw(struct screen_write_ctx *, u_int, int);
|
void clock_draw(struct screen_write_ctx *, u_int, int);
|
||||||
|
|
||||||
/* arg.c */
|
|
||||||
struct client *arg_parse_client(const char *);
|
|
||||||
struct session *arg_parse_session(const char *);
|
|
||||||
int arg_parse_window(const char *, struct session **, int *);
|
|
||||||
|
|
||||||
/* cmd.c */
|
/* cmd.c */
|
||||||
struct cmd *cmd_parse(int, char **, char **);
|
struct cmd *cmd_parse(int, char **, char **);
|
||||||
int cmd_exec(struct cmd *, struct cmd_ctx *);
|
int cmd_exec(struct cmd *, struct cmd_ctx *);
|
||||||
@ -1094,7 +1089,9 @@ struct session *cmd_current_session(struct cmd_ctx *);
|
|||||||
struct client *cmd_find_client(struct cmd_ctx *, const char *);
|
struct client *cmd_find_client(struct cmd_ctx *, const char *);
|
||||||
struct session *cmd_find_session(struct cmd_ctx *, const char *);
|
struct session *cmd_find_session(struct cmd_ctx *, const char *);
|
||||||
struct winlink *cmd_find_window(
|
struct winlink *cmd_find_window(
|
||||||
struct cmd_ctx *, const char *, struct session **);
|
struct cmd_ctx *, const char *, struct session **);
|
||||||
|
int cmd_find_index(
|
||||||
|
struct cmd_ctx *, const char *, struct session **);
|
||||||
extern const struct cmd_entry *cmd_table[];
|
extern const struct cmd_entry *cmd_table[];
|
||||||
extern const struct cmd_entry cmd_attach_session_entry;
|
extern const struct cmd_entry cmd_attach_session_entry;
|
||||||
extern const struct cmd_entry cmd_bind_key_entry;
|
extern const struct cmd_entry cmd_bind_key_entry;
|
||||||
|
Loading…
Reference in New Issue
Block a user