From 74d8f0bf1dda71efe96e8702e3313bbcd879abfb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 19 Jun 2008 20:45:21 +0000 Subject: [PATCH] Command prompt for interactive commands. --- CHANGES | 4 +- GNUmakefile | 7 +- Makefile | 7 +- cmd-command-prompt.c | 94 ++++++++++++++++++++++++ cmd-string.c | 171 +++++++++++++++++++++++++++++++++++++++++++ cmd.c | 3 +- key-bindings.c | 11 +-- server-fn.c | 17 +---- tmux.h | 10 ++- 9 files changed, 291 insertions(+), 33 deletions(-) create mode 100644 cmd-command-prompt.c create mode 100644 cmd-string.c diff --git a/CHANGES b/CHANGES index 069e913d..a0a62270 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,7 @@ 19 June 2008 +* Allow commands to be entered at a prompt. This is triggered with the + command-prompt command, bound to : by default. * Show status messages properly, without blocking the server. 18 June 2008 @@ -507,4 +509,4 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.126 2008-06-19 19:37:39 nicm Exp $ +$Id: CHANGES,v 1.127 2008-06-19 20:45:15 nicm Exp $ diff --git a/GNUmakefile b/GNUmakefile index 5316126b..e1ab3e09 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,4 +1,4 @@ -# $Id: GNUmakefile,v 1.27 2008-06-18 20:58:03 nicm Exp $ +# $Id: GNUmakefile,v 1.28 2008-06-19 20:45:20 nicm Exp $ .PHONY: clean @@ -14,7 +14,8 @@ 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 arg.c cmd.c cmd-generic.c \ + key-string.c key-bindings.c resize.c arg.c \ + cmd.c cmd-generic.c cmd-string.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 \ @@ -25,7 +26,7 @@ SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ cmd-switch-client.c cmd-has-session.c cmd-scroll-mode.c cmd-copy-mode.c \ cmd-paste-buffer.c cmd-new-session.c cmd-start-server.c \ cmd-kill-server.c cmd-set-window-option.c cmd-show-options.c \ - cmd-show-window-options.c \ + cmd-show-window-options.c cmd-command-prompt.c \ window-scroll.c window-more.c window-copy.c options.c \ tty.c tty-keys.c tty-write.c screen-write.c screen-redraw.c diff --git a/Makefile b/Makefile index d8c25a8e..2b672e18 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.62 2008-06-18 16:34:48 nicm Exp $ +# $Id: Makefile,v 1.63 2008-06-19 20:45:20 nicm Exp $ .SUFFIXES: .c .o .y .h .PHONY: clean update-index.html upload-index.html @@ -18,7 +18,8 @@ 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 arg.c cmd.c cmd-generic.c \ + key-string.c key-bindings.c resize.c arg.c \ + cmd.c cmd-generic.c cmd-string.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 \ @@ -29,7 +30,7 @@ SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ cmd-switch-client.c cmd-has-session.c cmd-scroll-mode.c cmd-copy-mode.c \ cmd-paste-buffer.c cmd-new-session.c cmd-start-server.c \ cmd-kill-server.c cmd-set-window-option.c cmd-show-options.c \ - cmd-show-window-options.c \ + cmd-show-window-options.c cmd-command-prompt.c \ window-scroll.c window-more.c window-copy.c options.c \ tty.c tty-keys.c tty-write.c screen-write.c screen-redraw.c diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c new file mode 100644 index 00000000..96ca7199 --- /dev/null +++ b/cmd-command-prompt.c @@ -0,0 +1,94 @@ +/* $Id: cmd-command-prompt.c,v 1.1 2008-06-19 20:45:20 nicm Exp $ */ + +/* + * Copyright (c) 2007 Nicholas Marriott + * + * 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 + +#include + +#include "tmux.h" + +/* + * Prompt for command in client. + */ + +void cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *); + +void cmd_command_prompt_callback(void *, char *); + +const struct cmd_entry cmd_command_prompt_entry = { + "command-prompt", NULL, + CMD_TARGET_CLIENT_USAGE, + 0, + cmd_target_init, + cmd_target_parse, + cmd_command_prompt_exec, + cmd_target_send, + cmd_target_recv, + cmd_target_free, + cmd_target_print +}; + +void +cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct client *c; + + if ((c = cmd_find_client(ctx, data->target)) == NULL) + return; + + if (c->prompt_string != NULL) + return; + + server_set_client_prompt(c, ":", cmd_command_prompt_callback, c); + + if (ctx->cmdclient != NULL) + server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); +} + +void +cmd_command_prompt_callback(void *data, char *s) +{ + struct client *c = data; + struct cmd *cmd; + struct cmd_ctx ctx; + char *cause; + + if (s == NULL) + return; + + if ((cmd = cmd_string_parse(s, &cause)) == NULL) { + *cause = toupper((u_char) *cause); + server_set_client_message(c, cause); + xfree(cause); + return; + } + + ctx.msgdata = NULL; + ctx.cursession = c->session; + ctx.curclient = c; + + ctx.error = key_bindings_error; + ctx.print = key_bindings_print; + ctx.info = key_bindings_info; + + ctx.cmdclient = NULL; + ctx.flags = CMD_KEY; + + cmd_exec(cmd, &ctx); +} diff --git a/cmd-string.c b/cmd-string.c new file mode 100644 index 00000000..7674a0fb --- /dev/null +++ b/cmd-string.c @@ -0,0 +1,171 @@ +/* $Id: cmd-string.c,v 1.1 2008-06-19 20:45:20 nicm Exp $ */ + +/* + * Copyright (c) 2008 Nicholas Marriott + * + * 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 + +#include +#include +#include + +#include "tmux.h" + +/* + * Parse a command from a string. + */ + +int cmd_string_getc(const char *, size_t *); +char *cmd_string_string(const char *, size_t *, char, int); + +int +cmd_string_getc(const char *s, size_t *p) +{ + if (s[*p] == '\0') + return (EOF); + return (s[(*p)++]); +} + +struct cmd * +cmd_string_parse(const char *s, char **cause) +{ + size_t p; + int ch, argc; + char **argv, *buf, *t; + size_t len; + struct cmd *cmd; + + argv = NULL; + argc = 0; + + buf = NULL; + len = 0; + + cmd = NULL; + + p = 0; + for (;;) { + ch = cmd_string_getc(s, &p); + switch (ch) { + case '\'': + if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL) + goto error; + argv = xrealloc(argv, argc + 1, sizeof *argv); + argv[argc++] = t; + break; + case '"': + if ((t = cmd_string_string(s, &p, '"', 1)) == NULL) + goto error; + argv = xrealloc(argv, argc + 1, sizeof *argv); + argv[argc++] = t; + break; + case '#': + /* Comment: discard rest of line. */ + while ((ch = cmd_string_getc(s, &p)) != EOF) + ; + /* FALLTHROUGH */ + case EOF: + case ' ': + case '\t': + if (len != 0) { + buf = xrealloc(buf, 1, len + 1); + buf[len] = '\0'; + + argv = xrealloc(argv, argc + 1, sizeof *argv); + argv[argc++] = buf; + + buf = NULL; + len = 0; + } + + if (ch != EOF) + break; + + cmd = cmd_parse(argc, argv, cause); + goto out; + default: + if (len >= SIZE_MAX - 2) + goto error; + + buf = xrealloc(buf, 1, len + 1); + buf[len++] = ch; + break; + } + } + +error: + xasprintf(cause, "bad command: %s", s); + +out: + if (buf != NULL) + xfree(buf); + + while (--argc >= 0) + xfree(argv[argc]); + if (argv != NULL) + xfree(argv); + + return (cmd); +} + +char * +cmd_string_string(const char *s, size_t *p, char endch, int esc) +{ + int ch; + char *buf; + size_t len; + + buf = NULL; + len = 0; + + while ((ch = cmd_string_getc(s, p)) != endch) { + switch (ch) { + case EOF: + goto error; + case '\\': + if (!esc) + break; + switch (ch = cmd_string_getc(s, p)) { + case EOF: + goto error; + case 'r': + ch = '\r'; + break; + case 'n': + ch = '\n'; + break; + case 't': + ch = '\t'; + break; + } + break; + } + + if (len >= SIZE_MAX - 2) + goto error; + buf = xrealloc(buf, 1, len + 1); + buf[len++] = ch; + } + + buf = xrealloc(buf, 1, len + 1); + buf[len] = '\0'; + return (buf); + +error: + if (buf != NULL) + xfree(buf); + return (NULL); +} diff --git a/cmd.c b/cmd.c index 26fc5ce8..03cac5b7 100644 --- a/cmd.c +++ b/cmd.c @@ -1,4 +1,4 @@ -/* $Id: cmd.c,v 1.49 2008-06-18 22:21:51 nicm Exp $ */ +/* $Id: cmd.c,v 1.50 2008-06-19 20:45:20 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -29,6 +29,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_attach_session_entry, &cmd_bind_key_entry, + &cmd_command_prompt_entry, &cmd_copy_mode_entry, &cmd_detach_client_entry, &cmd_has_session_entry, diff --git a/key-bindings.c b/key-bindings.c index f9413190..8df7791a 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -1,4 +1,4 @@ -/* $Id: key-bindings.c,v 1.31 2008-06-16 17:35:40 nicm Exp $ */ +/* $Id: key-bindings.c,v 1.32 2008-06-19 20:45:20 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -26,10 +26,6 @@ struct bindings key_bindings; -void printflike2 key_bindings_error(struct cmd_ctx *, const char *, ...); -void printflike2 key_bindings_print(struct cmd_ctx *, const char *, ...); -void printflike2 key_bindings_info(struct cmd_ctx *, const char *, ...); - void key_bindings_add(int key, struct cmd *cmd) { @@ -112,6 +108,7 @@ key_bindings_init(void) { '=', &cmd_scroll_mode_entry }, { '[', &cmd_copy_mode_entry }, { ']', &cmd_paste_buffer_entry }, + { ':', &cmd_command_prompt_entry }, { META, &cmd_send_prefix_entry }, }; u_int i; @@ -156,7 +153,7 @@ key_bindings_error(struct cmd_ctx *ctx, const char *fmt, ...) va_end(ap); *msg = toupper((u_char) *msg); - server_write_message(ctx->curclient, "%s", msg); + server_set_client_message(ctx->curclient, msg); xfree(msg); } @@ -187,7 +184,7 @@ key_bindings_info(struct cmd_ctx *ctx, const char *fmt, ...) va_end(ap); *msg = toupper((u_char) *msg); - server_write_message(ctx->curclient, "%s", msg); + server_set_client_message(ctx->curclient, msg); xfree(msg); } diff --git a/server-fn.c b/server-fn.c index 526a859d..61524947 100644 --- a/server-fn.c +++ b/server-fn.c @@ -1,4 +1,4 @@ -/* $Id: server-fn.c,v 1.44 2008-06-19 19:40:34 nicm Exp $ */ +/* $Id: server-fn.c,v 1.45 2008-06-19 20:45:20 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -200,18 +200,3 @@ server_status_window(struct window *w) server_status_session(s); } } - -void printflike2 -server_write_message(struct client *c, const char *fmt, ...) -{ - va_list ap; - char *msg; - - va_start(ap, fmt); - xvasprintf(&msg, fmt, ap); - va_end(ap); - - server_set_client_message(c, msg); - - xfree(msg); -} diff --git a/tmux.h b/tmux.h index 620b02e9..2d066f03 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.153 2008-06-19 19:40:35 nicm Exp $ */ +/* $Id: tmux.h,v 1.154 2008-06-19 20:45:21 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -867,6 +867,7 @@ struct winlink *cmd_find_window( struct cmd_ctx *, const char *, struct session **); extern const struct cmd_entry cmd_attach_session_entry; extern const struct cmd_entry cmd_bind_key_entry; +extern const struct cmd_entry cmd_command_prompt_entry; extern const struct cmd_entry cmd_copy_mode_entry; extern const struct cmd_entry cmd_detach_client_entry; extern const struct cmd_entry cmd_has_session_entry; @@ -901,6 +902,9 @@ extern const struct cmd_entry cmd_switch_client_entry; extern const struct cmd_entry cmd_unbind_key_entry; extern const struct cmd_entry cmd_unlink_window_entry; +/* cmd-string.c */ +struct cmd *cmd_string_parse(const char *, char **); + /* cmd-generic.c */ #define CMD_TARGET_WINDOW_USAGE "[-t target-window]" #define CMD_TARGET_SESSION_USAGE "[-t target-session]" @@ -944,6 +948,9 @@ void key_bindings_remove(int); void key_bindings_init(void); void key_bindings_free(void); void key_bindings_dispatch(int, struct client *); +void printflike2 key_bindings_error(struct cmd_ctx *, const char *, ...); +void printflike2 key_bindings_print(struct cmd_ctx *, const char *, ...); +void printflike2 key_bindings_info(struct cmd_ctx *, const char *, ...); /* key-string.c */ int key_string_lookup_string(const char *); @@ -976,7 +983,6 @@ void server_redraw_session(struct session *); void server_status_session(struct session *); void server_redraw_window(struct window *); void server_status_window(struct window *); -void printflike2 server_write_message(struct client *, const char *, ...); /* status.c */ void status_redraw(struct client *);