aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES6
-rw-r--r--Makefile9
-rw-r--r--TODO5
-rw-r--r--client-msg.c17
-rw-r--r--client.c93
-rw-r--r--cmd-detach-session.c137
-rw-r--r--cmd-list-sessions.c70
-rw-r--r--cmd-new-session.c162
-rw-r--r--cmd.c306
-rw-r--r--key-bindings.c214
-rw-r--r--op-list.c199
-rw-r--r--op.c271
-rw-r--r--server-fn.c17
-rw-r--r--server-msg.c402
-rw-r--r--server.c6
-rw-r--r--session.c10
-rw-r--r--tmux.c148
-rw-r--r--tmux.h190
18 files changed, 1034 insertions, 1228 deletions
diff --git a/CHANGES b/CHANGES
index 2f84a8c9..e50acaff 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,9 @@
03 October 2007
+* (nicm) Rewrite command handling so commands are much more generic and the
+ same commands are used for command line and keys (although most will probably
+ need to check how they are called). Currently incomplete (only new/detach/ls
+ implemented).
* (nicm) String number arguments. So you can do: tmux bind ^Q create "blah".
* (nicm) Key binding. tmux bind key command [argument] and tmux unbind key.
Key names are in a table in key-string.c, plus A is A, ^A is ctrl-A.
@@ -99,5 +103,5 @@
(including mutt, emacs). No status bar yet and no key remapping or other
customisation.
-$Id: CHANGES,v 1.25 2007-10-03 12:34:16 nicm Exp $
+$Id: CHANGES,v 1.26 2007-10-03 21:31:06 nicm Exp $
diff --git a/Makefile b/Makefile
index 5da175b0..b1d68369 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.12 2007-10-03 11:26:34 nicm Exp $
+# $Id: Makefile,v 1.13 2007-10-03 21:31:07 nicm Exp $
.SUFFIXES: .c .o .y .h
.PHONY: clean
@@ -17,9 +17,10 @@ DEBUG=
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 cmd.c input.c input-keys.c screen.c window.c \
- session.c local.c log.c client.c client-msg.c client-fn.c op.c op-list.c \
- key-string.c
+ xmalloc.c xmalloc-debug.c input.c input-keys.c screen.c window.c \
+ session.c local.c log.c client.c client-msg.c client-fn.c key-string.c \
+ key-bindings.c \
+ cmd.c cmd-new-session.c cmd-detach-session.c cmd-list-sessions.c
YACC= yacc -d
diff --git a/TODO b/TODO
index 9ee064ee..2d696923 100644
--- a/TODO
+++ b/TODO
@@ -33,8 +33,11 @@
IPC is arse-about-face: too much overhead. 8-byte header for each
packet... hrm. already scanning output for \e, could add an extra
byte to it for message
-- could use bsearch all over the place
+- could use bsearch all over the place or get rid of smaller tables (clientmsg)
- better errors when creating new windows/sessions (how?)
+- commands should have to care less about CMD_KEY
+- CLIENT_HOLD sucks
+- session with CMD_NOSESSION should be an error
-- For 0.1 --------------------------------------------------------------------
- man page
diff --git a/client-msg.c b/client-msg.c
index 0a17d67e..6bcd8173 100644
--- a/client-msg.c
+++ b/client-msg.c
@@ -1,4 +1,4 @@
-/* $Id: client-msg.c,v 1.5 2007-10-03 10:18:31 nicm Exp $ */
+/* $Id: client-msg.c,v 1.6 2007-10-03 21:31:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -39,7 +39,6 @@ struct client_msg client_msg_table[] = {
{ MSG_DATA, client_msg_fn_data },
{ MSG_DETACH, client_msg_fn_detach },
{ MSG_ERROR, client_msg_fn_error },
- { MSG_OKAY, client_msg_fn_okay },
{ MSG_PAUSE, client_msg_fn_pause },
};
#define NCLIENTMSG (sizeof client_msg_table / sizeof client_msg_table[0])
@@ -73,7 +72,6 @@ client_msg_dispatch(struct client_ctx *cctx, char **error)
}
}
-/* Data message from server. */
int
client_msg_fn_data(
struct hdr *hdr, struct client_ctx *cctx, unused char **error)
@@ -82,7 +80,6 @@ client_msg_fn_data(
return (0);
}
-/* Pause message from server. */
int
client_msg_fn_pause(
struct hdr *hdr, unused struct client_ctx *cctx, unused char **error)
@@ -92,17 +89,6 @@ client_msg_fn_pause(
return (1);
}
-/* Okay message from server. */
-int
-client_msg_fn_okay(
- struct hdr *hdr, unused struct client_ctx *cctx, unused char **error)
-{
- if (hdr->size != 0)
- fatalx("bad MSG_OKAY size");
- return (0);
-}
-
-/* Error message from server. */
int
client_msg_fn_error(struct hdr *hdr, struct client_ctx *cctx, char **error)
{
@@ -116,7 +102,6 @@ client_msg_fn_error(struct hdr *hdr, struct client_ctx *cctx, char **error)
return (-1);
}
-/* Detach message from server. */
int
client_msg_fn_detach(
struct hdr *hdr, unused struct client_ctx *cctx, char **error)
diff --git a/client.c b/client.c
index 77a1fb68..0c60d540 100644
--- a/client.c
+++ b/client.c
@@ -1,4 +1,4 @@
-/* $Id: client.c,v 1.10 2007-10-03 10:18:32 nicm Exp $ */
+/* $Id: client.c,v 1.11 2007-10-03 21:31:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -38,33 +38,19 @@ int client_process_local(struct client_ctx *, char **);
int
client_init(char *path, struct client_ctx *cctx, int start_server)
{
- struct sockaddr_un sa;
- struct stat sb;
- size_t sz;
- int mode;
- u_int retries;
+ struct sockaddr_un sa;
+ struct stat sb;
+ struct msg_identify_data data;
+ struct winsize ws;
+ size_t sz;
+ int mode;
+ u_int retries;
if (path == NULL) {
xasprintf(&path,
"%s/%s-%lu", _PATH_TMP, __progname, (u_long) getuid());
}
- if (start_server) {
- if (!isatty(STDIN_FILENO)) {
- log_warnx("stdin is not a tty");
- return (-1);
- }
- if (!isatty(STDOUT_FILENO)) {
- log_warnx("stdout is not a tty");
- return (-1);
- }
-
- if (ioctl(STDIN_FILENO, TIOCGWINSZ, &cctx->ws) == -1) {
- log_warn("ioctl(TIOCGWINSZ)");
- return (-1);
- }
- }
-
retries = 0;
retry:
if (stat(path, &sb) != 0) {
@@ -121,50 +107,18 @@ retry:
cctx->srv_in = buffer_create(BUFSIZ);
cctx->srv_out = buffer_create(BUFSIZ);
- return (0);
-}
-
-int
-client_flush(struct client_ctx *cctx)
-{
- struct pollfd pfd;
- struct hdr hdr;
-
- for (;;) {
- pfd.fd = cctx->srv_fd;
- pfd.events = POLLIN;
- if (BUFFER_USED(cctx->srv_out) > 0)
- pfd.events |= POLLOUT;
-
- if (poll(&pfd, 1, INFTIM) == -1) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- fatal("poll failed");
- }
-
- if (buffer_poll(&pfd, cctx->srv_in, cctx->srv_out) != 0) {
- log_warnx("lost server");
- return (1);
+ if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) {
+ log_warn("ioctl(TIOCGWINSZ)");
+ return (-1);
}
- if (BUFFER_USED(cctx->srv_in) < sizeof hdr)
- continue;
- memcpy(&hdr, BUFFER_OUT(cctx->srv_in), sizeof hdr);
- if (BUFFER_USED(cctx->srv_in) < (sizeof hdr) + hdr.size)
- continue;
- buffer_remove(cctx->srv_in, sizeof hdr);
-
- if (hdr.type == MSG_OKAY)
- return (0);
- if (hdr.type == MSG_ERROR) {
- if (hdr.size > INT_MAX - 1)
- fatalx("bad MSG_ERROR size");
- log_warnx(
- "%.*s", (int) hdr.size, BUFFER_OUT(cctx->srv_in));
- return (1);
- }
- fatalx("unexpected message");
+ data.sx = ws.ws_col;
+ data.sy = ws.ws_row;
+ client_write_server(cctx, MSG_IDENTIFY, &data, sizeof data);
}
+
+ return (0);
}
int
@@ -244,14 +198,15 @@ local_dead:
void
client_handle_winch(struct client_ctx *cctx)
{
- struct size_data data;
-
- if (ioctl(STDIN_FILENO, TIOCGWINSZ, &cctx->ws) == -1)
+ struct msg_resize_data data;
+ struct winsize ws;
+
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
fatal("ioctl failed");
- data.sx = cctx->ws.ws_col;
- data.sy = cctx->ws.ws_row;
- client_write_server(cctx, MSG_SIZE, &data, sizeof data);
+ data.sx = ws.ws_col;
+ data.sy = ws.ws_row;
+ client_write_server(cctx, MSG_RESIZE, &data, sizeof data);
sigwinch = 0;
}
diff --git a/cmd-detach-session.c b/cmd-detach-session.c
new file mode 100644
index 00000000..bcb858a7
--- /dev/null
+++ b/cmd-detach-session.c
@@ -0,0 +1,137 @@
+/* $Id: cmd-detach-session.c,v 1.1 2007-10-03 21:31:07 nicm Exp $ */
+
+/*
+ * Copyright (c) 2007 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 <getopt.h>
+
+#include "tmux.h"
+
+/*
+ * Detach session. If called with -a detach all clients attached to specified
+ * session, otherwise detach current session on key press only.
+ */
+
+int cmd_detach_session_parse(void **, int, char **, char **);
+const char *cmd_detach_session_usage(void);
+void cmd_detach_session_exec(void *, struct cmd_ctx *);
+void cmd_detach_session_send(void *, struct buffer *);
+void cmd_detach_session_recv(void **, struct buffer *);
+void cmd_detach_session_free(void *);
+
+struct cmd_detach_session_data {
+ int flag_all;
+};
+
+const struct cmd_entry cmd_detach_session_entry = {
+ CMD_DETACHSESSION, "detach-session", "detach", 0,
+ cmd_detach_session_parse,
+ cmd_detach_session_usage,
+ cmd_detach_session_exec,
+ cmd_detach_session_send,
+ cmd_detach_session_recv,
+ cmd_detach_session_free
+};
+
+int
+cmd_detach_session_parse(void **ptr, int argc, char **argv, char **cause)
+{
+ struct cmd_detach_session_data *data;
+ int opt;
+
+ *ptr = data = xmalloc(sizeof *data);
+ data->flag_all = 0;
+
+ while ((opt = getopt(argc, argv, "a")) != EOF) {
+ switch (opt) {
+ case 'a':
+ data->flag_all = 1;
+ break;
+ default:
+ goto usage;
+ }
+ }
+ argc -= optind;
+ argv -= optind;
+ if (argc != 0)
+ goto usage;
+
+ return (0);
+
+usage:
+ usage(cause, "%s", cmd_detach_session_usage());
+
+ xfree(data);
+ return (-1);
+}
+
+const char *
+cmd_detach_session_usage(void)
+{
+ return ("detach-session [-a]");
+}
+
+void
+cmd_detach_session_exec(void *ptr, struct cmd_ctx *ctx)
+{
+ struct cmd_detach_session_data *data = ptr, std = { 0 };
+ struct client *c = ctx->client, *cp;
+ struct session *s = ctx->session;
+ u_int i;
+
+ if (data == NULL)
+ data = &std;
+
+ if (data->flag_all) {
+ for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
+ cp = ARRAY_ITEM(&clients, i);
+ if (cp == NULL || cp->session != s)
+ continue;
+ server_write_client(cp, MSG_DETACH, NULL, 0);
+ }
+ } else if (ctx->flags & CMD_KEY)
+ server_write_client(c, MSG_DETACH, NULL, 0);
+
+ if (!(ctx->flags & CMD_KEY))
+ server_write_client(c, MSG_EXIT, NULL, 0);
+}
+
+void
+cmd_detach_session_send(void *ptr, struct buffer *b)
+{
+ struct cmd_detach_session_data *data = ptr;
+
+ buffer_write(b, data, sizeof *data);
+}
+
+void
+cmd_detach_session_recv(void **ptr, struct buffer *b)
+{
+ struct cmd_detach_session_data *data;
+
+ *ptr = data = xmalloc(sizeof *data);
+ buffer_read(b, data, sizeof *data);
+}
+
+void
+cmd_detach_session_free(void *ptr)
+{
+ struct cmd_detach_session_data *data = ptr;
+
+ xfree(data);
+}
diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c
new file mode 100644
index 00000000..47f3f0a0
--- /dev/null
+++ b/cmd-list-sessions.c
@@ -0,0 +1,70 @@
+/* $Id: cmd-list-sessions.c,v 1.1 2007-10-03 21:31:07 nicm Exp $ */
+
+/*
+ * Copyright (c) 2007 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 <getopt.h>
+#include <string.h>
+
+#include "tmux.h"
+
+/*
+ * List all sessions.
+ */
+
+int cmd_list_sessions_parse(void **, int, char **, char **);
+const char *cmd_list_sessions_usage(void);
+void cmd_list_sessions_exec(void *, struct cmd_ctx *);
+
+const struct cmd_entry cmd_list_sessions_entry = {
+ CMD_LISTSESSIONS, "list-sessions", "ls", CMD_NOSESSION,
+ NULL,
+ NULL,
+ cmd_list_sessions_exec,
+ NULL,
+ NULL,
+ NULL
+};
+
+void
+cmd_list_sessions_exec(unused void *ptr, struct cmd_ctx *ctx)
+{
+ struct client *c = ctx->client;
+ struct session *s = ctx->session;
+ char *tim;
+ u_int i, j, n;
+
+ for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
+ s = ARRAY_ITEM(&sessions, i);
+ if (s == NULL)
+ continue;
+
+ n = 0;
+ for (j = 0; j < ARRAY_LENGTH(&s->windows); j++) {
+ if (ARRAY_ITEM(&s->windows, j) != NULL)
+ n++;
+ }
+ tim = ctime(&s->tim);
+ *strchr(tim, '\n') = '\0';
+
+ ctx->print(ctx, "%s: %u windows (created %s)", s->name, n, tim);
+ }
+
+ if (!(ctx->flags & CMD_KEY))
+ server_write_client(c, MSG_EXIT, NULL, 0);
+}
diff --git a/cmd-new-session.c b/cmd-new-session.c
new file mode 100644
index 00000000..6ed04ed8
--- /dev/null
+++ b/cmd-new-session.c
@@ -0,0 +1,162 @@
+/* $Id: cmd-new-session.c,v 1.1 2007-10-03 21:31:07 nicm Exp $ */
+
+/*
+ * Copyright (c) 2007 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 <getopt.h>
+
+#include "tmux.h"
+
+/*
+ * Create a new session and attach to the current terminal unless -d is given.
+ */
+
+int cmd_new_session_parse(void **, int, char **, char **);
+const char *cmd_new_session_usage(void);
+void cmd_new_session_exec(void *, struct cmd_ctx *);
+void cmd_new_session_send(void *, struct buffer *);
+void cmd_new_session_recv(void **, struct buffer *);
+void cmd_new_session_free(void *);
+
+struct cmd_new_session_data {
+ char *name;
+ int flag_detached;
+};
+
+const struct cmd_entry cmd_new_session_entry = {
+ CMD_NEWSESSION, "new-session", "new", CMD_STARTSERVER|CMD_NOSESSION,
+ cmd_new_session_parse,
+ cmd_new_session_usage,
+ cmd_new_session_exec,
+ cmd_new_session_send,
+ cmd_new_session_recv,
+ cmd_new_session_free
+};
+
+int
+cmd_new_session_parse(void **ptr, int argc, char **argv, char **cause)
+{
+ struct cmd_new_session_data *data;
+ int opt;
+
+ *ptr = data = xmalloc(sizeof *data);
+ data->flag_detached = 0;
+ data->name = NULL;
+
+ while ((opt = getopt(argc, argv, "ds:")) != EOF) {
+ switch (opt) {
+ case 'd':
+ data->flag_detached = 1;
+ break;
+ case 's':
+ data->name = xstrdup(optarg);
+ break;
+ default:
+ goto usage;
+ }
+ }
+ argc -= optind;
+ argv -= optind;
+ if (argc != 0)
+ goto usage;
+
+ return (0);
+
+usage:
+ usage(cause, "%s", cmd_new_session_usage());
+
+ if (data->name != NULL)
+ xfree(data->name);
+ xfree(data);
+ return (-1);
+}
+
+const char *
+cmd_new_session_usage(void)
+{
+ return ("new-session [-d] [-n session name]");
+}
+
+void
+cmd_new_session_exec(void *ptr, struct cmd_ctx *ctx)
+{
+ struct cmd_new_session_data *data = ptr, std = { NULL, 0 };
+ struct client *c = ctx->client;
+ u_int sy;
+
+ if (data == NULL)
+ data = &std;
+
+ if (ctx->flags & CMD_KEY)
+ return;
+
+ if (!data->flag_detached && !(c->flags & CLIENT_TERMINAL)) {
+ ctx->error(ctx, "not a terminal");
+ return;
+ }
+
+ if (data->name != NULL && session_find(data->name) != NULL) {
+ ctx->error(ctx, "duplicate session: %s", data->name);
+ return;
+ }
+
+ sy = c->sy;
+ if (sy < status_lines)
+ sy = status_lines + 1;
+ sy -= status_lines;
+
+ c->session = session_create(data->name, default_command, c->sx, sy);
+ if (c->session == NULL)
+ fatalx("session_create failed");
+
+ if (data->flag_detached)
+ server_write_client(c, MSG_EXIT, NULL, 0);
+ else {
+ server_write_client(c, MSG_READY, NULL, 0);
+ server_draw_client(c);
+ }
+}
+
+void
+cmd_new_session_send(void *ptr, struct buffer *b)
+{
+ struct cmd_new_session_data *data = ptr;
+
+ buffer_write(b, data, sizeof *data);
+ cmd_send_string(b, data->name);
+}
+
+void
+cmd_new_session_recv(void **ptr, struct buffer *b)
+{
+ struct cmd_new_session_data *data;
+
+ *ptr = data = xmalloc(sizeof *data);
+ buffer_read(b, data, sizeof *data);
+ data->name = cmd_recv_string(b);
+}
+
+void
+cmd_new_session_free(void *ptr)
+{
+ struct cmd_new_session_data *data = ptr;
+
+ if (data->name != NULL)
+ xfree(data->name);
+ xfree(data);
+}
diff --git a/cmd.c b/cmd.c
index c5823f3b..cf171de4 100644
--- a/cmd.c
+++ b/cmd.c
@@ -1,4 +1,4 @@
-/* $Id: cmd.c,v 1.4 2007-10-03 12:43:47 nicm Exp $ */
+/* $Id: cmd.c,v 1.5 2007-10-03 21:31:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,243 +18,163 @@
#include <sys/types.h>
-#include <stdlib.h>
+#include <getopt.h>
#include <string.h>
#include "tmux.h"
-int cmd_prefix = META;
-
-void cmd_fn_detach(struct client *, struct cmd *);
-void cmd_fn_last(struct client *, struct cmd *);
-void cmd_fn_meta(struct client *, struct cmd *);
-void cmd_fn_new(struct client *, struct cmd *);
-void cmd_fn_next(struct client *, struct cmd *);
-void cmd_fn_previous(struct client *, struct cmd *);
-void cmd_fn_refresh(struct client *, struct cmd *);
-void cmd_fn_select(struct client *, struct cmd *);
-void cmd_fn_info(struct client *, struct cmd *);
-
-const struct cmd cmd_default[] = {
- { '0', cmd_fn_select, 0, NULL },
- { '1', cmd_fn_select, 1, NULL },
- { '2', cmd_fn_select, 2, NULL },
- { '3', cmd_fn_select, 3, NULL },
- { '4', cmd_fn_select, 4, NULL },
- { '5', cmd_fn_select, 5, NULL },
- { '6', cmd_fn_select, 6, NULL },
- { '7', cmd_fn_select, 7, NULL },
- { '8', cmd_fn_select, 8, NULL },
- { '9', cmd_fn_select, 9, NULL },
- { 'C', cmd_fn_new, 0, NULL },
- { 'c', cmd_fn_new, 0, NULL },
- { 'D', cmd_fn_detach, 0, NULL },
- { 'd', cmd_fn_detach, 0, NULL },
- { 'N', cmd_fn_next, 0, NULL },
- { 'n', cmd_fn_next, 0, NULL },
- { 'P', cmd_fn_previous, 0, NULL },
- { 'p', cmd_fn_previous, 0, NULL },
- { 'R', cmd_fn_refresh, 0, NULL },
- { 'r', cmd_fn_refresh, 0, NULL },
- { 'L', cmd_fn_last, 0, NULL },
- { 'l', cmd_fn_last, 0, NULL },
- { 'I', cmd_fn_info, 0, NULL },
- { 'i', cmd_fn_info, 0, NULL },
- { META, cmd_fn_meta, 0, NULL },
-};
-u_int cmd_count = (sizeof cmd_default / sizeof cmd_default[0]);
-struct cmd *cmd_table;
-
-const struct bind cmd_bind_table[] = {
- { "detach", cmd_fn_detach, 0 },
- { "info", cmd_fn_info, 0 },
- { "last", cmd_fn_last, 0 },
- { "meta", cmd_fn_meta, 0 },
- { "new", cmd_fn_new, BIND_STRING|BIND_USER },
- { "next", cmd_fn_next, 0 },
- { "previous", cmd_fn_previous, 0 },
- { "refresh", cmd_fn_refresh, 0 },
- { "select", cmd_fn_select, BIND_NUMBER|BIND_USER },
+const struct cmd_entry *cmd_table[] = {
+ &cmd_detach_session_entry,
+ &cmd_list_sessions_entry,
+ &cmd_new_session_entry,
+ NULL
};
-#define NCMDBIND (sizeof cmd_bind_table / sizeof cmd_bind_table[0])
-
-const struct bind *
-cmd_lookup_bind(const char *name)
-{
- const struct bind *bind;
- u_int i;
-
- for (i = 0; i < NCMDBIND; i++) {
- bind = cmd_bind_table + i;
- if (strcmp(bind->name, name) == 0)
- return (bind);
- }
- return (NULL);
-}
-void
-cmd_add_bind(int key, u_int num, char *str, const struct bind *bind)
+struct cmd *
+cmd_parse(int argc, char **argv, char **cause)
{
- struct cmd *cmd = NULL;
- u_int i;
-
- for (i = 0; i < cmd_count; i++) {
- cmd = cmd_table + i;
- if (cmd->key == key)
+ const struct cmd_entry **this, *entry;
+ struct cmd *cmd;
+ int opt;
+
+ *cause = NULL;
+ if (argc == 0)
+ return (NULL);
+
+ entry = NULL;
+ for (this = cmd_table; *this != NULL; this++) {
+ if (strcmp((*this)->alias, argv[0]) == 0) {
+ entry = *this;
break;
- }
- if (i == cmd_count) {
- for (i = 0; i < cmd_count; i++) {
- cmd = cmd_table + i;
- if (cmd->key == KEYC_NONE)
- break;
}
- if (i == cmd_count) {
- cmd_count++;
- cmd_table = xrealloc(cmd_table,
- cmd_count, sizeof cmd_table[0]);
- cmd = cmd_table + cmd_count - 1;
+
+ if (strncmp((*this)->name, argv[0], strlen(argv[0])) != 0)
+ continue;
+ if (entry != NULL) {
+ xasprintf(cause, "ambiguous command: %s", argv[0]);
+ return (NULL);
}
+ entry = *this;
}
-
- cmd->key = key;
- cmd->fn = bind->fn;
- if (bind->flags & BIND_USER) {
- if (bind->flags & BIND_STRING)
- cmd->str = xstrdup(str);
- if (bind->flags & BIND_NUMBER)
- cmd->num = num;
+ if (entry == NULL) {
+ xasprintf(cause, "unknown command: %s", argv[0]);
+ return (NULL);
}
-}
-void
-cmd_remove_bind(int key)
-{
- struct cmd *cmd;
- u_int i;
-
- for (i = 0; i < cmd_count; i++) {
- cmd = cmd_table + i;
- if (cmd->key == key) {
- cmd->key = KEYC_NONE;
- break;
+ optind = 1;
+ if (entry->parse == NULL) {
+ while ((opt = getopt(argc, argv, "")) != EOF) {
+ switch (opt) {
+ default:
+ goto usage;
+ }
}
+ argc -= optind;
+ argv += optind;
+ if (argc != 0)
+ goto usage;
}
-}
-void
-cmd_init(void)
-{
- cmd_table = xmalloc(sizeof cmd_default);
- memcpy(cmd_table, cmd_default, sizeof cmd_default);
-}
+ cmd = xmalloc(sizeof *cmd);
+ cmd->entry = entry;
+ if (entry->parse != NULL) {
+ if (entry->parse(&cmd->data, argc, argv, cause) != 0) {
+ xfree(cmd);
+ return (NULL);
+ }
+ }
+ return (cmd);
-void
-cmd_free(void)
-{
- /* XXX free strings */
- xfree(cmd_table);
+usage:
+ if (entry->usage == NULL)
+ usage(cause, "%s", entry->name);
+ else
+ usage(cause, "%s", entry->usage());
+ return (NULL);
}
void
-cmd_dispatch(struct client *c, int key)
+cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx)
{
- struct cmd *cmd;
- u_int i;
-
- for (i = 0; i < cmd_count; i++) {
- cmd = cmd_table + i;
- if (cmd->key != KEYC_NONE && cmd->key == key)
- cmd->fn(c, cmd);
- }
+ return (cmd->entry->exec(cmd->data, ctx));
}
void
-cmd_fn_new(struct client *c, struct cmd *cmd)
+cmd_send(struct cmd *cmd, struct buffer *b)
{
- char *s;
+ buffer_write(b, &cmd->entry->type, sizeof cmd->entry->type);
- s = cmd->str;
- if (s == NULL)
- s = default_command;
- if (session_new(c->session, s, c->sx, c->sy) != 0)
- server_write_message(c, "%s failed", s); /* XXX */
- else
- server_draw_client(c, 0, c->sy - 1);
+ if (cmd->entry->send == NULL)
+ return;
+ return (cmd->entry->send(cmd->data, b));
}
-void
-cmd_fn_detach(struct client *c, unused struct cmd *cmd)
+struct cmd *
+cmd_recv(struct buffer *b)
{
- server_write_client(c, MSG_DETACH, NULL, 0);
-}
+ const struct cmd_entry **this, *entry;
+ struct cmd *cmd;
+ enum cmd_type type;
+
+ buffer_read(b, &type, sizeof type);
+
+ entry = NULL;
+ for (this = cmd_table; *this != NULL; this++) {
+ if ((*this)->type == type) {
+ entry = *this;
+ break;
+ }
+ }
+ if (*this == NULL)
+ return (NULL);
-void
-cmd_fn_last(struct client *c, unused struct cmd *cmd)
-{
- if (session_last(c->session) == 0)
- server_window_changed(c);
- else
- server_write_message(c, "No last window");
-}
+ cmd = xmalloc(sizeof *cmd);
+ cmd->entry = entry;
-void
-cmd_fn_meta(struct client *c, unused struct cmd *cmd)
-{
- window_key(c->session->window, cmd_prefix);
+ if (cmd->entry->recv != NULL)
+ cmd->entry->recv(&cmd->data, b);
+ return (cmd);
}
void
-cmd_fn_next(struct client *c, unused struct cmd *cmd)
+cmd_free(struct cmd *cmd)
{
- if (session_next(c->session) == 0)
- server_window_changed(c);
- else
- server_write_message(c, "No next window");
+ if (cmd->entry->free != NULL)
+ cmd->entry->free(cmd->data);
+ xfree(cmd);
}
void
-cmd_fn_previous(struct client *c, unused struct cmd *cmd)
+cmd_send_string(struct buffer *b, const char *s)
{
- if (session_previous(c->session) == 0)
- server_window_changed(c);
- else
- server_write_message(c, "No previous window");
-}
+ size_t n;
+
+ if (s == NULL) {
+ n = 0;
+ buffer_write(b, &n, sizeof n);
+ return;
+ }
-void
-cmd_fn_refresh(struct client *c, unused struct cmd *cmd)
-{
- server_draw_client(c, 0, c->sy - 1);
-}
+ n = strlen(s) + 1;
+ buffer_write(b, &n, sizeof n);
-void
-cmd_fn_select(struct client *c, struct cmd *cmd)
-{
- if (session_select(c->session, cmd->num) == 0)
- server_window_changed(c);
- else
- server_write_message(c, "Window %u not present", cmd->num);
+ buffer_write(b, s, n);
}
-void
-cmd_fn_info(struct client *c, unused struct cmd *cmd)
+char *
+cmd_recv_string(struct buffer *b)
{
- struct window *w;
- char *buf;
- size_t len;
- u_int i;
+ char *s;
+ size_t n;
- len = c->sx + 1;
- buf = xmalloc(len);
+ buffer_read(b, &n, sizeof n);
- w = c->session->window;
- window_index(&c->session->windows, w, &i);
- xsnprintf(buf, len, "%u:%s \"%s\" (size %u,%u) (cursor %u,%u) "
- "(region %u,%u)", i, w->name, w->screen.title, w->screen.sx,
- w->screen.sy, w->screen.cx, w->screen.cy, w->screen.ry_upper,
- w->screen.ry_lower);
+ if (n == 0)
+ return (NULL);
+
+ s = xmalloc(n);
+ buffer_read(b, s, n);
+ s[n - 1] = '\0';
- server_write_message(c, "%s", buf);
- xfree(buf);
+ return (s);
}
diff --git a/key-bindings.c b/key-bindings.c
new file mode 100644
index 00000000..7cbd556b
--- /dev/null
+++ b/key-bindings.c
@@ -0,0 +1,214 @@
+/* $Id: key-bindings.c,v 1.1 2007-10-03 21:31:07 nicm Exp $ */
+
+/*
+ * Copyright (c) 2007 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 <stdlib.h>
+#include <string.h>
+
+#include "tmux.h"
+
+ARRAY_DECL(, struct binding *) key_bindings;
+
+void key_bindings_error(struct cmd_ctx *, const char *, ...);
+void key_bindings_print(struct cmd_ctx *, const char *, ...);
+
+void
+key_bindings_add(int key, struct cmd *cmd)
+{
+ struct binding *bd;
+ u_int i;
+
+ bd = NULL;
+ for (i = 0; i < ARRAY_LENGTH(&key_bindings); i++) {
+ bd = ARRAY_ITEM(&key_bindings, i);
+ if (bd->key == key)
+ break;
+ }
+ if (i == ARRAY_LENGTH(&key_bindings)) {
+ bd = xmalloc(sizeof *bd);
+ ARRAY_ADD(&key_bindings, bd);
+ }
+
+ bd->key = key;
+ bd->cmd = cmd;
+}
+
+void
+key_bindings_remove(int key)
+{
+ struct binding *bd;
+ u_int i;
+
+ bd = NULL;
+ for (i = 0; i < ARRAY_LENGTH(&key_bindings); i++) {
+ bd = ARRAY_ITEM(&key_bindings, i);
+ if (bd->key == key)
+ break;
+ }
+ if (i == ARRAY_LENGTH(&key_bindings))
+ return;
+
+ cmd_free(bd->cmd);
+ xfree(bd);
+}
+
+void
+key_bindings_init(void)
+{
+ struct {
+ int key;
+ const struct cmd_entry *entry;
+ } table[] = {
+ { 'D', &cmd_detach_session_entry },
+ { 'd', &cmd_detach_session_entry },
+ { 'S', &cmd_list_sessions_entry },
+ { 's', &cmd_list_sessions_entry },
+/* { 'C', &cmd_new_window },
+ { 'c', &cmd_new_window },
+ { 'N', &cmd_next_window },
+ { 'n', &cmd_next_window },
+ { 'P', &cmd_previous_window },
+ { 'p', &cmd_previous_window },
+ { 'R', &cmd_refresh_client },
+ { 'r', &cmd_refresh_client },
+ { 'L', &cmd_last_window },
+ { 'l', &cmd_last_window },
+ { 'I', &cmd_windo_info },
+ { 'i', &cmd_window_info },
+ { META, &cmd_meta_entry },
+*//* { '0', cmdx_fn_select, 0, NULL },
+ { '1', cmdx_fn_select, 1, NULL },
+ { '2', cmdx_fn_select, 2, NULL },
+ { '3',