diff options
| -rw-r--r-- | CHANGES | 6 | ||||
| -rw-r--r-- | Makefile | 9 | ||||
| -rw-r--r-- | TODO | 5 | ||||
| -rw-r--r-- | client-msg.c | 17 | ||||
| -rw-r--r-- | client.c | 93 | ||||
| -rw-r--r-- | cmd-detach-session.c | 137 | ||||
| -rw-r--r-- | cmd-list-sessions.c | 70 | ||||
| -rw-r--r-- | cmd-new-session.c | 162 | ||||
| -rw-r--r-- | cmd.c | 306 | ||||
| -rw-r--r-- | key-bindings.c | 214 | ||||
| -rw-r--r-- | op-list.c | 199 | ||||
| -rw-r--r-- | op.c | 271 | ||||
| -rw-r--r-- | server-fn.c | 17 | ||||
| -rw-r--r-- | server-msg.c | 402 | ||||
| -rw-r--r-- | server.c | 6 | ||||
| -rw-r--r-- | session.c | 10 | ||||
| -rw-r--r-- | tmux.c | 148 | ||||
| -rw-r--r-- | tmux.h | 190 |
18 files changed, 1034 insertions, 1228 deletions
@@ -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 $ @@ -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 @@ -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) @@ -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); +} @@ -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', |