diff --git a/Makefile b/Makefile index 2b672e18..efa0ca0d 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.63 2008-06-19 20:45:20 nicm Exp $ +# $Id: Makefile,v 1.64 2008-06-20 08:36:20 nicm Exp $ .SUFFIXES: .c .o .y .h .PHONY: clean update-index.html upload-index.html @@ -30,8 +30,9 @@ 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-command-prompt.c \ - window-scroll.c window-more.c window-copy.c options.c \ + cmd-show-window-options.c cmd-command-prompt.c cmd-set-buffer.c \ + cmd-show-buffer.c \ + window-scroll.c window-more.c window-copy.c options.c paste.c \ tty.c tty-keys.c tty-write.c screen-write.c screen-redraw.c CC?= cc diff --git a/TODO b/TODO index 82530944..8138cf62 100644 --- a/TODO +++ b/TODO @@ -75,3 +75,15 @@ - support \033_string\033\\ for window title too - fix bell-action in show-options - list-keys should be sorted +--- +buffer stack. buffer numbered 0 is top and ascending + +where -b number == top if missing: +paste-buffer -b number +delete-buffer -b number +set-buffer -b number string +save-buffer -b number filename +load-buffer -b number filename +copy-buffer (from other session) +show-buffers +--- diff --git a/array.h b/array.h index 42ac2258..c9d6512b 100644 --- a/array.h +++ b/array.h @@ -1,4 +1,4 @@ -/* $Id: array.h,v 1.4 2008-06-18 16:35:26 nicm Exp $ */ +/* $Id: array.h,v 1.5 2008-06-20 08:36:20 nicm Exp $ */ /* * Copyright (c) 2006 Nicholas Marriott @@ -54,6 +54,15 @@ (a)->list[(a)->num] = s; \ (a)->num++; \ } while (0) +#define ARRAY_INSERT(a, i, s) do { \ + ENSURE_SIZE2((a)->list, (a)->space, (a)->num + 1, ARRAY_ITEMSIZE(a)); \ + if ((i) < (a)->num) { \ + memmove((a)->list + (i) + 1, (a)->list + (i), \ + ARRAY_ITEMSIZE(a) * ((a)->num - (i))); \ + } \ + (a)->list[i] = s; \ + (a)->num++; \ +} while (0) #define ARRAY_REMOVE(a, i) do { \ if ((i) < (a)->num - 1) { \ memmove((a)->list + (i), (a)->list + (i) + 1, \ diff --git a/cmd-generic.c b/cmd-generic.c index 68805d62..3ede0cf6 100644 --- a/cmd-generic.c +++ b/cmd-generic.c @@ -1,4 +1,4 @@ -/* $Id: cmd-generic.c,v 1.10 2008-06-18 22:21:51 nicm Exp $ */ +/* $Id: cmd-generic.c,v 1.11 2008-06-20 08:36:20 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -262,3 +262,133 @@ cmd_srcdst_print(struct cmd *self, char *buf, size_t len) if (off < len && data->arg != NULL) off += xsnprintf(buf + off, len - off, " %s", data->arg); } + +void +cmd_buffer_init(struct cmd *self, unused int key) +{ + struct cmd_buffer_data *data; + + self->data = data = xmalloc(sizeof *data); + data->flags = 0; + data->target = NULL; + data->buffer = -1; + data->arg = NULL; +} + +int +cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_buffer_data *data; + int opt, n; + const char *errstr; + + cmd_buffer_init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, "b:dkt:")) != EOF) { + switch (opt) { + case 'b': + if (data->buffer == -1) { + n = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf( + cause, "buffer index %s", errstr); + goto error; + } + data->buffer = n; + } + break; + 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; + } + } + argc -= optind; + argv += optind; + + 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: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + +error: + self->entry->free(self); + return (-1); +} + +void +cmd_buffer_send(struct cmd *self, struct buffer *b) +{ + struct cmd_buffer_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->target); + cmd_send_string(b, data->arg); +} + +void +cmd_buffer_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_buffer_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->target = cmd_recv_string(b); + data->arg = cmd_recv_string(b); +} + +void +cmd_buffer_free(struct cmd *self) +{ + struct cmd_buffer_data *data = self->data; + + if (data->target != NULL) + xfree(data->target); + if (data->arg != NULL) + xfree(data->arg); + xfree(data); +} + +void +cmd_buffer_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_buffer_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return; + if (off < len && data->flags & CMD_DFLAG) + off += xsnprintf(buf + off, len - off, " -d"); + if (off < len && data->flags & CMD_KFLAG) + off += xsnprintf(buf + off, len - off, " -k"); + if (off < len && data->buffer != -1) + off += xsnprintf(buf + off, len - off, " -b %d", data->buffer); + if (off < len && data->target != NULL) + off += xsnprintf(buf + off, len - off, " -t %s", data->target); + if (off < len && data->arg != NULL) + off += xsnprintf(buf + off, len - off, " %s", data->arg); +} diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c new file mode 100644 index 00000000..150cbcc9 --- /dev/null +++ b/cmd-set-buffer.c @@ -0,0 +1,63 @@ +/* $Id: cmd-set-buffer.c,v 1.1 2008-06-20 08:36: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 + +#include "tmux.h" + +/* + * Add or set a session paste buffer. + */ + +void cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_set_buffer_entry = { + "set-buffer", "setb", + CMD_BUFFER_SESSION_USAGE " data", + CMD_ONEARG, + cmd_buffer_init, + cmd_buffer_parse, + cmd_set_buffer_exec, + cmd_buffer_send, + cmd_buffer_recv, + cmd_buffer_free, + cmd_buffer_print +}; + +void +cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_buffer_data *data = self->data; + struct session *s; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return; + + if (data->buffer == -1) + paste_add(&s->buffers, data->arg); + else { + if (paste_replace(&s->buffers, data->buffer, data->arg) != 0) + ctx->error(ctx, "no buffer %d", data->buffer); + } + + if (ctx->cmdclient != NULL) + server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); +} diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c new file mode 100644 index 00000000..a964bc06 --- /dev/null +++ b/cmd-show-buffer.c @@ -0,0 +1,89 @@ +/* $Id: cmd-show-buffer.c,v 1.1 2008-06-20 08:36: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 + +#include "tmux.h" + +/* + * Show a session paste buffer. + */ + +void cmd_show_buffer_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_show_buffer_entry = { + "show-buffer", "showb", + CMD_BUFFER_SESSION_USAGE, + 0, + cmd_buffer_init, + cmd_buffer_parse, + cmd_show_buffer_exec, + cmd_buffer_send, + cmd_buffer_recv, + cmd_buffer_free, + cmd_buffer_print +}; + +void +cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_buffer_data *data = self->data; + struct session *s; + struct paste_buffer *pb; + u_int size; + char *buf, *ptr; + size_t len; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return; + + if (data->buffer == -1) { + if ((pb = paste_get_top(&s->buffers)) == NULL) + ctx->error(ctx, "no buffers"); + } else { + if ((pb = paste_get_index(&s->buffers, data->buffer)) == NULL) + ctx->error(ctx, "no buffer %d", data->buffer); + } + + if (pb != NULL) { + size = s->sx; + + buf = xmalloc(size + 1); + len = 0; + + ptr = pb->data; + do { + buf[len++] = *ptr++; + + if (len == size) { + buf[len] = '\0'; + ctx->print(ctx, buf); + + len = 0; + } + } while (*ptr != '\0'); + buf[len] = '\0'; + ctx->print(ctx, buf); + } + + if (ctx->cmdclient != NULL) + server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); +} diff --git a/cmd.c b/cmd.c index 03cac5b7..4755edaf 100644 --- a/cmd.c +++ b/cmd.c @@ -1,4 +1,4 @@ -/* $Id: cmd.c,v 1.50 2008-06-19 20:45:20 nicm Exp $ */ +/* $Id: cmd.c,v 1.51 2008-06-20 08:36:20 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -54,8 +54,10 @@ const struct cmd_entry *cmd_table[] = { &cmd_select_window_entry, &cmd_send_keys_entry, &cmd_send_prefix_entry, + &cmd_set_buffer_entry, &cmd_set_option_entry, &cmd_set_window_option_entry, + &cmd_show_buffer_entry, &cmd_show_options_entry, &cmd_show_window_options_entry, &cmd_start_server_entry, diff --git a/paste.c b/paste.c new file mode 100644 index 00000000..1dedd6be --- /dev/null +++ b/paste.c @@ -0,0 +1,128 @@ +/* $Id: paste.c,v 1.1 2008-06-20 08:36: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 + +#include "tmux.h" + +void +paste_init_stack(struct paste_stack *ps) +{ + ARRAY_INIT(ps); +} + +void +paste_free_stack(struct paste_stack *ps) +{ + while (paste_free_top(ps) == 0) + ; +} + +struct paste_buffer * +paste_walk_stack(struct paste_stack *ps, uint *idx) +{ + struct paste_buffer *pb; + + pb = paste_get_index(ps, *idx); + (*idx)++; + return (pb); +} + +struct paste_buffer * +paste_get_top(struct paste_stack *ps) +{ + if (ARRAY_LENGTH(ps) == 0) + return (NULL); + return (ARRAY_FIRST(ps)); +} + +struct paste_buffer * +paste_get_index(struct paste_stack *ps, u_int idx) +{ + if (idx >= ARRAY_LENGTH(ps)) + return (NULL); + return (ARRAY_ITEM(ps, idx)); +} + +int +paste_free_top(struct paste_stack *ps) +{ + struct paste_buffer *pb; + + if (ARRAY_LENGTH(ps) == 0) + return (1); + + pb = ARRAY_FIRST(ps); + ARRAY_REMOVE(ps, 0); + + xfree(pb->data); + xfree(pb); + + return (0); +} + +int +paste_free_index(struct paste_stack *ps, u_int idx) +{ + struct paste_buffer *pb; + + if (idx >= ARRAY_LENGTH(ps)) + return (1); + + pb = ARRAY_ITEM(ps, idx); + ARRAY_REMOVE(ps, idx); + + xfree(pb->data); + xfree(pb); + + return (0); +} + +void +paste_add(struct paste_stack *ps, const char *data) +{ + struct paste_buffer *pb; + + pb = xmalloc(sizeof *pb); + ARRAY_INSERT(ps, 0, pb); + + pb->data = xstrdup(data); + if (clock_gettime(CLOCK_REALTIME, &pb->created) != 0) + fatal("clock_gettime"); +} + +int +paste_replace(struct paste_stack *ps, u_int idx, const char *data) +{ + struct paste_buffer *pb; + + if (idx >= ARRAY_LENGTH(ps)) + return (1); + + pb = ARRAY_ITEM(ps, idx); + xfree(pb->data); + + pb->data = xstrdup(data); + if (clock_gettime(CLOCK_REALTIME, &pb->created) != 0) + fatal("clock_gettime"); + + return (0); +} diff --git a/session.c b/session.c index 75a01c76..67609172 100644 --- a/session.c +++ b/session.c @@ -1,4 +1,4 @@ -/* $Id: session.c,v 1.38 2008-06-18 22:21:51 nicm Exp $ */ +/* $Id: session.c,v 1.39 2008-06-20 08:36:20 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -120,6 +120,7 @@ session_create(const char *name, const char *cmd, u_int sx, u_int sy) s->curw = s->lastw = NULL; RB_INIT(&s->windows); TAILQ_INIT(&s->alerts); + paste_init_stack(&s->buffers); options_init(&s->options, &global_options); s->sx = sx; @@ -165,6 +166,7 @@ session_destroy(struct session *s) session_alert_cancel(s, NULL); options_free(&s->options); + paste_free_stack(&s->buffers); while (!RB_EMPTY(&s->windows)) winlink_remove(&s->windows, RB_ROOT(&s->windows)); diff --git a/tmux.h b/tmux.h index 242b63b2..83587c5e 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.156 2008-06-20 06:36:01 nicm Exp $ */ +/* $Id: tmux.h,v 1.157 2008-06-20 08:36:20 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -590,6 +590,13 @@ struct options { struct options *parent; }; +/* Paste buffer. */ +struct paste_buffer { + char *data; + struct timespec created; +}; +ARRAY_DECL(paste_stack, struct paste_buffer *); + /* Client session. */ struct session_alert { struct winlink *wl; @@ -611,6 +618,8 @@ struct session { struct options options; + struct paste_stack buffers; + TAILQ_HEAD(, session_alert) alerts; #define SESSION_UNATTACHED 0x1 /* not attached to any clients */ @@ -760,6 +769,13 @@ struct cmd_srcdst_data { char *arg; }; +struct cmd_buffer_data { + int flags; + char *target; + int buffer; + char *arg; +}; + /* Key binding. */ struct binding { int key; @@ -851,6 +867,17 @@ void tty_vwrite_window(void *, int, va_list); void tty_write_session(void *, int, ...); void tty_vwrite_session(void *, int, va_list); +/* paste.c */ +void paste_init_stack(struct paste_stack *); +void paste_free_stack(struct paste_stack *); +struct paste_buffer *paste_walk_stack(struct paste_stack *, uint *); +struct paste_buffer *paste_get_top(struct paste_stack *); +struct paste_buffer *paste_get_index(struct paste_stack *, u_int); +int paste_free_top(struct paste_stack *); +int paste_free_index(struct paste_stack *, u_int); +void paste_add(struct paste_stack *, const char *); +int paste_replace(struct paste_stack *, u_int, const char *); + /* arg.c */ struct client *arg_parse_client(const char *); struct session *arg_parse_session(const char *); @@ -896,8 +923,10 @@ extern const struct cmd_entry cmd_scroll_mode_entry; extern const struct cmd_entry cmd_select_window_entry; extern const struct cmd_entry cmd_send_keys_entry; extern const struct cmd_entry cmd_send_prefix_entry; +extern const struct cmd_entry cmd_set_buffer_entry; extern const struct cmd_entry cmd_set_option_entry; extern const struct cmd_entry cmd_set_window_option_entry; +extern const struct cmd_entry cmd_show_buffer_entry; extern const struct cmd_entry cmd_show_options_entry; extern const struct cmd_entry cmd_show_window_options_entry; extern const struct cmd_entry cmd_start_server_entry; @@ -930,6 +959,16 @@ void cmd_srcdst_send(struct cmd *, struct buffer *); void cmd_srcdst_recv(struct cmd *, struct buffer *); void cmd_srcdst_free(struct cmd *); void cmd_srcdst_print(struct cmd *, char *, size_t); +#define CMD_BUFFER_WINDOW_USAGE "[-b index] [-t target-window]" +#define CMD_BUFFER_SESSION_USAGE "[-b index] [-t target-session]" +#define CMD_BUFFER_CLIENT_USAGE "[-b index] [-t target-client]" +void cmd_buffer_init(struct cmd *, int); +int cmd_buffer_parse(struct cmd *, int, char **, char **); +void cmd_buffer_exec(struct cmd *, struct cmd_ctx *); +void cmd_buffer_send(struct cmd *, struct buffer *); +void cmd_buffer_recv(struct cmd *, struct buffer *); +void cmd_buffer_free(struct cmd *); +void cmd_buffer_print(struct cmd *, char *, size_t); /* client.c */ int client_init(const char *, struct client_ctx *, int);