From 8216f7b3d9cb1465898ac888407b179ad6ddb733 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 2 Apr 2009 23:28:16 +0000 Subject: [PATCH] swap-pane command. --- GNUmakefile | 4 +- Makefile | 4 +- TODO | 3 +- cmd-server-info.c | 8 +- cmd-swap-pane.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++ cmd.c | 3 +- key-bindings.c | 6 +- tmux.h | 3 +- 8 files changed, 300 insertions(+), 13 deletions(-) create mode 100644 cmd-swap-pane.c diff --git a/GNUmakefile b/GNUmakefile index 687817f4..d4b213e9 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,4 +1,4 @@ -# $Id: GNUmakefile,v 1.79 2009-04-01 18:21:22 nicm Exp $ +# $Id: GNUmakefile,v 1.80 2009-04-02 23:28:15 nicm Exp $ .PHONY: clean @@ -37,7 +37,7 @@ SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ cmd-resize-pane-up.c cmd-resize-pane-down.c cmd-kill-pane.c \ cmd-up-pane.c cmd-down-pane.c cmd-choose-window.c cmd-choose-session.c \ cmd-suspend-client.c cmd-find-window.c cmd-load-buffer.c \ - cmd-copy-buffer.c cmd-break-pane.c cmd-next-layout.c \ + cmd-copy-buffer.c cmd-break-pane.c cmd-swap-pane.c cmd-next-layout.c \ window-clock.c window-scroll.c window-more.c window-copy.c \ window-choose.c \ options.c options-cmd.c paste.c colour.c utf8.c clock.c \ diff --git a/Makefile b/Makefile index 22dcefd2..6b5627db 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.118 2009-04-02 22:12:28 nicm Exp $ +# $Id: Makefile,v 1.119 2009-04-02 23:28:16 nicm Exp $ .SUFFIXES: .c .o .y .h .PHONY: clean update-index.html upload-index.html @@ -40,7 +40,7 @@ SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ cmd-resize-pane-up.c cmd-resize-pane-down.c cmd-kill-pane.c \ cmd-up-pane.c cmd-down-pane.c cmd-choose-window.c cmd-choose-session.c \ cmd-suspend-client.c cmd-find-window.c cmd-load-buffer.c \ - cmd-copy-buffer.c cmd-break-pane.c cmd-next-layout.c \ + cmd-copy-buffer.c cmd-break-pane.c cmd-swap-pane.c cmd-next-layout.c \ window-clock.c window-scroll.c window-more.c window-copy.c \ window-choose.c \ options.c options-cmd.c paste.c colour.c utf8.c clock.c \ diff --git a/TODO b/TODO index e70f25d6..ab660c6e 100644 --- a/TODO +++ b/TODO @@ -85,7 +85,7 @@ - test bug sshing from freebsd console - layout/split stuff: horiz split command, and similar resizing commands as for vert split - swap-pane command + rotate-window (-pane?) to rotate panes so first becomes last display the layout in a readable format somewhere previous-layout command select-layout command @@ -97,6 +97,7 @@ speed improvements? hardcoded 81 for left-vertical is nasty - document new layout stuff: next-layout +- document swap-pane - document repeat behaviour and -r on bind-key - document status-keys - document break-pane diff --git a/cmd-server-info.c b/cmd-server-info.c index ce680485..4cbd59aa 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -1,4 +1,4 @@ -/* $Id: cmd-server-info.c,v 1.13 2009-04-01 18:21:28 nicm Exp $ */ +/* $Id: cmd-server-info.c,v 1.14 2009-04-02 23:28:16 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -133,9 +133,9 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) sizeof (**gd->udata); } } - ctx->print(ctx, "%6u: %s %lu %d %u/%u, %zu " - "bytes; UTF-8 %u/%u, %zu bytes", j, wp->tty, - (u_long) wp->pid, wp->fd, lines, + ctx->print(ctx, "%6u: %p %s %lu %d %u/%u, %zu " + "bytes; UTF-8 %u/%u, %zu bytes", j, wp, + wp->tty, (u_long) wp->pid, wp->fd, lines, gd->hsize + gd->sy, size, ulines, gd->hsize + gd->sy, usize); j++; diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c new file mode 100644 index 00000000..c68e0634 --- /dev/null +++ b/cmd-swap-pane.c @@ -0,0 +1,282 @@ +/* $Id: cmd-swap-pane.c,v 1.1 2009-04-02 23:28:16 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" + +/* + * Swap two panes. + */ + +int cmd_swap_pane_parse(struct cmd *, int, char **, char **); +int cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *); +void cmd_swap_pane_send(struct cmd *, struct buffer *); +void cmd_swap_pane_recv(struct cmd *, struct buffer *); +void cmd_swap_pane_free(struct cmd *); +void cmd_swap_pane_init(struct cmd *, int); +size_t cmd_swap_pane_print(struct cmd *, char *, size_t); + +struct cmd_swap_pane_data { + char *target; + int src; + int dst; + int flag_detached; + int flag_next; + int flag_previous; +}; + +const struct cmd_entry cmd_swap_pane_entry = { + "swap-pane", "swapp", + "[-dn] [-t target-window] [-p src-index] [-q dst-index]", + 0, + cmd_swap_pane_init, + cmd_swap_pane_parse, + cmd_swap_pane_exec, + cmd_swap_pane_send, + cmd_swap_pane_recv, + cmd_swap_pane_free, + cmd_swap_pane_print +}; + +void +cmd_swap_pane_init(struct cmd *self, int key) +{ + struct cmd_swap_pane_data *data; + + self->data = data = xmalloc(sizeof *data); + data->target = NULL; + data->src = -1; + data->dst = -1; + data->flag_detached = 0; + data->flag_next = 0; + data->flag_previous = 0; + + switch (key) { + case '}': + data->flag_next = 1; + break; + case '{': + data->flag_previous = 1; + break; + } +} + +int +cmd_swap_pane_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_swap_pane_data *data; + int opt, n; + const char *errstr; + + self->entry->init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, "dt:np:q:r")) != -1) { + switch (opt) { + case 'd': + data->flag_detached = 1; + break; + case 'n': + data->flag_next = 1; + data->flag_previous = 0; + data->dst = -1; + break; + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); + break; + case 'p': + if (data->src == -1) { + n = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "src %s", errstr); + goto error; + } + data->src = n; + } + break; + case 'q': + if (data->dst == -1) { + n = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "dst %s", errstr); + goto error; + } + data->dst = n; + } + data->flag_next = 0; + data->flag_previous = 0; + break; + case 'r': + data->flag_next = 0; + data->flag_previous = 1; + data->dst = -1; + 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); + +error: + self->entry->free(self); + return (-1); +} + +int +cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_swap_pane_data *data = self->data; + struct winlink *wl; + struct window *w; + struct window_pane *tmp_wp, *src_wp, *dst_wp; + u_int xx, yy; + + if (data == NULL) + return (0); + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + w = wl->window; + + if (data->src == -1) + src_wp = w->active; + else { + src_wp = window_pane_at_index(w, data->src); + if (src_wp == NULL) { + ctx->error(ctx, "no pane: %d", data->src); + return (-1); + } + } + if (data->dst == -1) + dst_wp = w->active; + else { + dst_wp = window_pane_at_index(w, data->dst); + if (dst_wp == NULL) { + ctx->error(ctx, "no pane: %d", data->dst); + return (-1); + } + } + + if (data->dst == -1 && data->flag_next) { + if ((dst_wp = TAILQ_NEXT(src_wp, entry)) == NULL) + dst_wp = TAILQ_FIRST(&w->panes); + } + if (data->dst == -1 && data->flag_previous) { + if ((dst_wp = TAILQ_PREV(src_wp, window_panes, entry)) == NULL) + dst_wp = TAILQ_LAST(&w->panes, window_panes); + } + + if (src_wp == dst_wp) + return (0); + + tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry); + TAILQ_REMOVE(&w->panes, dst_wp, entry); + TAILQ_REPLACE(&w->panes, src_wp, dst_wp, entry); + if (tmp_wp == src_wp) + tmp_wp = dst_wp; + if (tmp_wp == NULL) + TAILQ_INSERT_HEAD(&w->panes, src_wp, entry); + else + TAILQ_INSERT_AFTER(&w->panes, tmp_wp, src_wp, entry); + + xx = src_wp->xoff; + yy = src_wp->yoff; + src_wp->xoff = dst_wp->xoff; + src_wp->yoff = dst_wp->yoff; + dst_wp->xoff = xx; + dst_wp->yoff = yy; + + xx = src_wp->sx; + yy = src_wp->sy; + window_pane_resize(src_wp, dst_wp->sx, dst_wp->sy); + window_pane_resize(dst_wp, xx, yy); + + if (!data->flag_detached) { + window_set_active_pane(w, dst_wp); + layout_refresh(w, 0); + } + + return (0); +} + +void +cmd_swap_pane_send(struct cmd *self, struct buffer *b) +{ + struct cmd_swap_pane_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->target); +} + +void +cmd_swap_pane_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_swap_pane_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->target = cmd_recv_string(b); +} + +void +cmd_swap_pane_free(struct cmd *self) +{ + struct cmd_swap_pane_data *data = self->data; + + if (data->target != NULL) + xfree(data->target); + xfree(data); +} + +size_t +cmd_swap_pane_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_swap_pane_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && (data->flag_next || data->flag_detached)) { + off += xsnprintf(buf + off, len - off, " -"); + if (off < len && data->flag_next) + off += xsnprintf(buf + off, len - off, "d"); + if (off < len && data->flag_detached) + off += xsnprintf(buf + off, len - off, "n"); + } + if (off < len && data->target != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->target); + if (off < len && data->src != -1) + off += xsnprintf(buf + off, len - off, " -p %d", data->src); + if (off < len && data->dst != -1) + off += xsnprintf(buf + off, len - off, " -q %d", data->dst); + return (off); +} diff --git a/cmd.c b/cmd.c index eade9e1b..07e7665e 100644 --- a/cmd.c +++ b/cmd.c @@ -1,4 +1,4 @@ -/* $Id: cmd.c,v 1.87 2009-04-01 18:21:29 nicm Exp $ */ +/* $Id: cmd.c,v 1.88 2009-04-02 23:28:16 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -86,6 +86,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_split_window_entry, &cmd_start_server_entry, &cmd_suspend_client_entry, + &cmd_swap_pane_entry, &cmd_swap_window_entry, &cmd_switch_client_entry, &cmd_unbind_key_entry, diff --git a/key-bindings.c b/key-bindings.c index 02afc1c6..558a60e4 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -1,4 +1,4 @@ -/* $Id: key-bindings.c,v 1.64 2009-04-01 18:21:30 nicm Exp $ */ +/* $Id: key-bindings.c,v 1.65 2009-04-02 23:28:16 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -102,6 +102,7 @@ key_bindings_init(void) { '?', 0, &cmd_list_keys_entry }, { '[', 0, &cmd_copy_mode_entry }, { '\'', 0, &cmd_select_prompt_entry }, + { '\032', /* C-z */ 0, &cmd_suspend_client_entry }, { ']', 0, &cmd_paste_buffer_entry }, { 'c', 0, &cmd_new_window_entry }, { 'd', 0, &cmd_detach_client_entry }, @@ -115,7 +116,8 @@ key_bindings_init(void) { 't', 0, &cmd_clock_mode_entry }, { 'w', 0, &cmd_choose_window_entry }, { 'x', 0, &cmd_kill_pane_entry, }, - { '\032', 0, &cmd_suspend_client_entry }, + { '{', 0, &cmd_swap_pane_entry }, + { '}', 0, &cmd_swap_pane_entry }, { META, 0, &cmd_send_prefix_entry }, { KEYC_PPAGE, 0, &cmd_scroll_mode_entry }, { KEYC_ADDESC('n'), 0, &cmd_next_window_entry }, diff --git a/tmux.h b/tmux.h index b6f3d087..70cf2c34 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.297 2009-04-02 21:08:14 nicm Exp $ */ +/* $Id: tmux.h,v 1.298 2009-04-02 23:28:16 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -1230,6 +1230,7 @@ extern const struct cmd_entry cmd_source_file_entry; extern const struct cmd_entry cmd_split_window_entry; extern const struct cmd_entry cmd_start_server_entry; extern const struct cmd_entry cmd_suspend_client_entry; +extern const struct cmd_entry cmd_swap_pane_entry; extern const struct cmd_entry cmd_swap_window_entry; extern const struct cmd_entry cmd_switch_client_entry; extern const struct cmd_entry cmd_unbind_key_entry;