diff options
42 files changed, 911 insertions, 1522 deletions
@@ -1,5 +1,26 @@ 05 June 2008 +* Completely reorganise command parsing. Much more common code in cmd-generic.c + and a new way of specifying windows, clients or sessions. Now, most commands + take a -t argument, which specifies a client, a session, or a window target. + Clients and sessions are given alone (sessions are fnmatch(3)d and + clients currently not), windows are give by (client|session):index. For + example, if a user is in session "1" window 0 on /dev/ttypi, these should all + be equivalent: + + tmux renamew newname (current session and window) + tmux renamew -t: newname (current session and window) + tmux renamew -t:0 newname (current session, window 0) + tmux renamew -t0 newname (current session, window 0) + tmux renamew -t1:0 newname (session 1, window 0) + tmux renamew -t1: newname (session 1, current window) + tmux renamew -t/dev/ttypi newname (client /dev/ttypi's current + session and window) + tmux renamew -t/dev/ttypi: newname (client /dev/ttypi's current + session and window) + tmux renamew -t/dev/ttypi:0 newname (client /dev/ttypi's current + session, window 0) + * Infrastructure for printing arguments in list-keys output. Easy ones only for now. @@ -408,4 +429,4 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.110 2008-06-05 16:35:31 nicm Exp $ +$Id: CHANGES,v 1.111 2008-06-05 21:24:59 nicm Exp $ diff --git a/GNUmakefile b/GNUmakefile index 6740ecd0..533350b4 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,4 +1,4 @@ -# $Id: GNUmakefile,v 1.15 2008-06-05 05:04:47 nicm Exp $ +# $Id: GNUmakefile,v 1.16 2008-06-05 21:25:00 nicm Exp $ .PHONY: clean @@ -14,7 +14,7 @@ META?= \002 SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ xmalloc.c xmalloc-debug.c input.c input-keys.c screen.c screen-display.c \ window.c session.c log.c client.c client-msg.c client-fn.c cfg.c \ - key-string.c key-bindings.c resize.c cmd.c cmd-generic.c \ + key-string.c key-bindings.c resize.c arg.c cmd.c cmd-generic.c \ cmd-detach-client.c cmd-list-sessions.c cmd-new-window.c cmd-bind-key.c \ cmd-unbind-key.c cmd-previous-window.c cmd-last-window.c cmd-list-keys.c \ cmd-set-option.c cmd-rename-window.c cmd-select-window.c \ @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.58 2008-06-04 17:54:26 nicm Exp $ +# $Id: Makefile,v 1.59 2008-06-05 21:25:00 nicm Exp $ .SUFFIXES: .c .o .y .h .PHONY: clean update-index.html upload-index.html @@ -18,7 +18,7 @@ META?= \002 # C-b SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ xmalloc.c xmalloc-debug.c input.c input-keys.c screen.c screen-display.c \ window.c session.c log.c client.c client-msg.c client-fn.c cfg.c \ - key-string.c key-bindings.c resize.c cmd.c cmd-generic.c \ + key-string.c key-bindings.c resize.c arg.c cmd.c cmd-generic.c \ cmd-detach-client.c cmd-list-sessions.c cmd-new-window.c cmd-bind-key.c \ cmd-unbind-key.c cmd-previous-window.c cmd-last-window.c cmd-list-keys.c \ cmd-set-option.c cmd-rename-window.c cmd-select-window.c \ @@ -83,11 +83,3 @@ - each command should have a print op as well for list keys - fix occasion start server problems - test and fix wsvt25 -- look again at stuff that doesn't use flags - swap-window - switch-client -audit for lookup window - link-window - look for dstidx - also lookup dstsess with find_session ---- @@ -0,0 +1,192 @@ +/* $Id: arg.c,v 1.1 2008-06-05 21:25:00 nicm Exp $ */ + +/* + * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include <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 timespec *ts; + u_int i; + + ts = 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 (ts == NULL || timespeccmp(&s->ts, ts, >)) { + newest = s; + ts = &s->ts; + } + } + + 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 (arg2[n - 1] == ':') + arg2[n - 1] = '\0'; + + /* Try and lookup 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 (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); + } + } + + 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 lookup 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); +} diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 820584b7..27e965bb 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -1,4 +1,4 @@ -/* $Id: cmd-attach-session.c,v 1.17 2008-06-05 17:12:10 nicm Exp $ */ +/* $Id: cmd-attach-session.c,v 1.18 2008-06-05 21:25:00 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -26,89 +26,32 @@ * Attach existing session to the current terminal. */ -int cmd_attach_session_parse(struct cmd *, int, char **, char **); void cmd_attach_session_exec(struct cmd *, struct cmd_ctx *); -void cmd_attach_session_send(struct cmd *, struct buffer *); -void cmd_attach_session_recv(struct cmd *, struct buffer *); -void cmd_attach_session_free(struct cmd *); -void cmd_attach_session_print(struct cmd *, char *, size_t); - -struct cmd_attach_session_data { - char *cname; - char *sname; - int flag_detach; -}; const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", - "[-d] [-c client-tty|-s session-name]", - CMD_CANTNEST, - cmd_attach_session_parse, + "[-d] " CMD_TARGET_SESSION_USAGE, + CMD_DFLAG|CMD_CANTNEST, + cmd_target_init, + cmd_target_parse, cmd_attach_session_exec, - cmd_attach_session_send, - cmd_attach_session_recv, - cmd_attach_session_free, - NULL, - cmd_attach_session_print + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print }; -int -cmd_attach_session_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_attach_session_data *data; - int opt; - - self->data = data = xmalloc(sizeof *data); - data->cname = NULL; - data->sname = NULL; - data->flag_detach = 0; - - while ((opt = getopt(argc, argv, "c:ds:")) != EOF) { - switch (opt) { - case 'c': - if (data->sname != NULL) - goto usage; - if (data->cname == NULL) - data->cname = xstrdup(optarg); - break; - case 'd': - data->flag_detach = 1; - break; - case 's': - if (data->cname != NULL) - goto usage; - if (data->sname == NULL) - data->sname = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 0) - goto usage; - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} - void cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_attach_session_data *data = self->data; - struct session *s; - char *cause; + struct cmd_target_data *data = self->data; + struct session *s; + char *cause; if (ctx->flags & CMD_KEY) return; - - if ((s = cmd_find_session(ctx, data->cname, data->sname)) == NULL) + + if ((s = cmd_find_session(ctx, data->target)) == NULL) return; if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) { @@ -122,7 +65,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) return; } - if (data->flag_detach) + if (data->flags & CMD_DFLAG) server_write_session(s, MSG_DETACH, NULL, 0); ctx->cmdclient->session = s; @@ -131,52 +74,3 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) server_redraw_client(ctx->cmdclient); } -void -cmd_attach_session_send(struct cmd *self, struct buffer *b) -{ - struct cmd_attach_session_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->cname); - cmd_send_string(b, data->sname); -} - -void -cmd_attach_session_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_attach_session_data *data; - - self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->cname = cmd_recv_string(b); - data->sname = cmd_recv_string(b); -} - -void -cmd_attach_session_free(struct cmd *self) -{ - struct cmd_attach_session_data *data = self->data; - - if (data->cname != NULL) - xfree(data->cname); - if (data->sname != NULL) - xfree(data->sname); - xfree(data); -} - -void -cmd_attach_session_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_attach_session_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return; - if (off < len && data->flag_detach) - off += xsnprintf(buf + off, len - off, " -d"); - if (off < len && data->cname != NULL) - off += xsnprintf(buf + off, len - off, " -c %s", data->cname); - if (off < len && data->sname != NULL) - off += xsnprintf(buf + off, len - off, " -s %s", data->sname); -} diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 03d38744..d8dcf310 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -1,4 +1,4 @@ -/* $Id: cmd-bind-key.c,v 1.13 2008-06-05 16:35:31 nicm Exp $ */ +/* $Id: cmd-bind-key.c,v 1.14 2008-06-05 21:25:00 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -41,13 +41,13 @@ const struct cmd_entry cmd_bind_key_entry = { "bind-key", "bind", "key command [arguments]", 0, + NULL, cmd_bind_key_parse, cmd_bind_key_exec, cmd_bind_key_send, cmd_bind_key_recv, cmd_bind_key_free, - NULL, - NULL + NULL /* XXX */ }; int diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index 37bb4a2f..530ee947 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -1,4 +1,4 @@ -/* $Id: cmd-copy-mode.c,v 1.9 2008-06-05 16:35:31 nicm Exp $ */ +/* $Id: cmd-copy-mode.c,v 1.10 2008-06-05 21:25:00 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -28,23 +28,24 @@ void cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_copy_mode_entry = { "copy-mode", NULL, - CMD_WINDOWONLY_USAGE, + CMD_TARGET_WINDOW_USAGE, 0, - cmd_windowonly_parse, + cmd_target_init, + cmd_target_parse, cmd_copy_mode_exec, - cmd_windowonly_send, - cmd_windowonly_recv, - cmd_windowonly_free, - NULL, + cmd_target_send, + cmd_target_recv, + cmd_target_free, NULL }; void cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct winlink *wl; + struct cmd_target_data *data = self->data; + struct winlink *wl; - if ((wl = cmd_windowonly_get(self, ctx, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) return; window_set_mode(wl->window, &window_copy_mode); diff --git a/cmd-detach-client.c b/cmd-detach-client.c index 04ee1831..1697adcd 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -1,4 +1,4 @@ -/* $Id: cmd-detach-client.c,v 1.5 2008-06-05 16:35:31 nicm Exp $ */ +/* $Id: cmd-detach-client.c,v 1.6 2008-06-05 21:25:00 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -28,23 +28,24 @@ void cmd_detach_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_detach_client_entry = { "detach-client", "detach", - CMD_CLIENTONLY_USAGE, + CMD_TARGET_CLIENT_USAGE, 0, - cmd_clientonly_parse, + cmd_target_init, + cmd_target_parse, cmd_detach_client_exec, - cmd_clientonly_send, - cmd_clientonly_recv, - cmd_clientonly_free, - NULL, - cmd_clientonly_print + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print }; void cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct client *c; + struct cmd_target_data *data = self->data; + struct client *c; - if ((c = cmd_clientonly_get(self, ctx)) == NULL) + if ((c = cmd_find_client(ctx, data->target)) == NULL) return; server_write_client(c, MSG_DETACH, NULL, 0); diff --git a/cmd-generic.c b/cmd-generic.c index 8eece27b..debc051a 100644 --- a/cmd-generic.c +++ b/cmd-generic.c @@ -1,4 +1,4 @@ -/* $Id: cmd-generic.c,v 1.7 2008-06-05 17:12:10 nicm Exp $ */ +/* $Id: cmd-generic.c,v 1.8 2008-06-05 21:25:00 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> @@ -23,114 +23,43 @@ #include "tmux.h" -int -cmd_clientonly_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_clientonly_data *data; - int opt; - - self->data = data = xmalloc(sizeof *data); - data->cname = NULL; - - while ((opt = getopt(argc, argv, "c:")) != EOF) { - switch (opt) { - case 'c': - if (data->cname == NULL) - data->cname = xstrdup(optarg); - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 0) - goto usage; - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} - void -cmd_clientonly_send(struct cmd *self, struct buffer *b) +cmd_target_init(struct cmd *self, unused int key) { - struct cmd_clientonly_data *data = self->data; - - buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->cname); -} - -void -cmd_clientonly_recv(struct cmd *self, struct buffer *b) -{ - struct cmd_clientonly_data *data; + struct cmd_target_data *data; self->data = data = xmalloc(sizeof *data); - buffer_read(b, data, sizeof *data); - data->cname = cmd_recv_string(b); -} - -void -cmd_clientonly_free(struct cmd *self) -{ - struct cmd_clientonly_data *data = self->data; - - if (data->cname != NULL) - xfree(data->cname); - xfree(data); -} - -struct client * -cmd_clientonly_get(struct cmd *self, struct cmd_ctx *ctx) -{ - struct cmd_clientonly_data *data = self->data; - - if (data != NULL) - return (cmd_find_client(ctx, data->cname)); - return (cmd_find_client(ctx, NULL)); -} - -void -cmd_clientonly_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_clientonly_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return; - if (off < len && data->cname != NULL) - off += xsnprintf(buf + off, len - off, " -c %s", data->cname); + data->flags = 0; + data->target = NULL; + data->arg = NULL; } int -cmd_sessiononly_parse(struct cmd *self, int argc, char **argv, char **cause) +cmd_target_parse(struct cmd *self, int argc, char **argv, char **cause) { - struct cmd_sessiononly_data *data; - int opt; - - self->data = data = xmalloc(sizeof *data); - data->cname = NULL; - data->sname = NULL; + struct cmd_target_data *data; + int opt; - while ((opt = getopt(argc, argv, "c:s:")) != EOF) { + self->entry->init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, "dkt:")) != EOF) { switch (opt) { - case 'c': - if (data->sname != NULL) - goto usage; - if (data->cname == NULL) - data->cname = xstrdup(optarg); - break; - case 's': - if (data->cname != NULL) - goto usage; - if (data->sname == NULL) - data->sname = xstrdup(optarg); + case 'd': + if (self->entry->flags & CMD_DFLAG) { + data->flags |= CMD_DFLAG; + break; + } + goto usage; + case 'k': + if (self->entry->flags & CMD_KFLAG) { + data->flags |= CMD_KFLAG; + break; + } + goto usage; + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); break; default: goto usage; @@ -138,9 +67,15 @@ cmd_sessiononly_parse(struct cmd *self, int argc, char **argv, char **cause) } argc -= optind; argv += optind; - if (argc != 0) - goto usage; + if (self->entry->flags & CMD_ONEARG) { + if (argc != 1) + goto usage; + data->arg = xstrdup(argv[0]); + } else { + if (argc != 0) + goto usage; + } return (0); usage: @@ -151,95 +86,99 @@ usage: } void -cmd_sessiononly_send(struct cmd *self, struct buffer *b) +cmd_target_send(struct cmd *self, struct buffer *b) { - struct cmd_sessiononly_data *data = self->data; + struct cmd_target_data *data = self->data; buffer_write(b, data, sizeof *data); - cmd_send_string(b, data->cname); - cmd_send_string(b, data->sname); + cmd_send_string(b, data->target); + cmd_send_string(b, data->arg); } void -cmd_sessiononly_recv(struct cmd *self, struct buffer *b) +cmd_target_recv(struct cmd *self, struct buffer *b) { - struct cmd_sessiononly_data *data; + struct cmd_target_data *data; self->data = data = xmalloc(sizeof *data); buffer_read(b, data, sizeof *data); - data->cname = cmd_recv_string(b); - data->sname = cmd_recv_string(b); + data->target = cmd_recv_string(b); + data->arg = cmd_recv_string(b); } void -cmd_sessiononly_free(struct cmd *self) +cmd_target_free(struct cmd *self) { - struct cmd_sessiononly_data *data = self->data; + struct cmd_target_data *data = self->data; - if (data->cname != NULL) - xfree(data->cname); - if (data->sname != NULL) - xfree(data->sname); + if (data->target != NULL) + xfree(data->target); + if (data->arg != NULL) + xfree(data->arg); xfree(data); } -struct session * -cmd_sessiononly_get(struct cmd *self, struct cmd_ctx *ctx) -{ - struct cmd_sessiononly_data *data = self->data; - - if (data != NULL) - return (cmd_find_session(ctx, data->cname, data->sname)); - return (cmd_find_session(ctx, NULL, NULL)); -} - void -cmd_sessiononly_print(struct cmd *self, char *buf, size_t len) +cmd_target_print(struct cmd *self, char *buf, size_t len) { - struct cmd_sessiononly_data *data = self->data; - size_t off = 0; + struct cmd_target_data *data = self->data; + size_t off = 0; off += xsnprintf(buf, len, "%s", self->entry->name); if (data == NULL) return; - if (off < len && data->cname != NULL) - off += xsnprintf(buf + off, len - off, " -c %s", data->cname); - if (off < len && data->sname != NULL) - off += xsnprintf(buf + off, len - off, " -s %s", data->sname); + if (off < len && data->flags & CMD_DFLAG) + off += xsnprintf(buf + off, len - off, " -d"); + if (off < len && data->flags & CMD_KFLAG) |