From 0cd55eb1e7823a75810b7f43f53b6266cb8b0bc0 Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Fri, 10 Apr 2015 16:00:08 +0000
Subject: [PATCH] Add a -x flag to copy-selection, append-selection and
 start-named-buffer to prevent it exiting copy mode after copying. From J
 Raynor with a few tweaks by me.

---
 cmd-bind-key.c | 28 ++++++++++++++++++++++------
 tmux.1         | 18 +++++++++++++++---
 window-copy.c  | 27 +++++++++++++++++++++------
 3 files changed, 58 insertions(+), 15 deletions(-)

diff --git a/cmd-bind-key.c b/cmd-bind-key.c
index 5d68d486..47c58e51 100644
--- a/cmd-bind-key.c
+++ b/cmd-bind-key.c
@@ -104,18 +104,34 @@ cmd_bind_key_mode_table(struct cmd *self, struct cmd_q *cmdq, int key)
 		return (CMD_RETURN_ERROR);
 	}
 
-	if (cmd != MODEKEYCOPY_COPYPIPE) {
-		if (args->argc != 2) {
-			cmdq_error(cmdq, "no argument allowed");
-			return (CMD_RETURN_ERROR);
+	switch (cmd) {
+	case MODEKEYCOPY_APPENDSELECTION:
+	case MODEKEYCOPY_COPYSELECTION:
+	case MODEKEYCOPY_STARTNAMEDBUFFER:
+		if (args->argc == 2)
+			arg = NULL;
+		else {
+			arg = args->argv[2];
+			if (strcmp(arg, "-x") != 0) {
+				cmdq_error(cmdq, "unknown argument");
+				return (CMD_RETURN_ERROR);
+			}
 		}
-		arg = NULL;
-	} else {
+		break;
+	case MODEKEYCOPY_COPYPIPE:
 		if (args->argc != 3) {
 			cmdq_error(cmdq, "no argument given");
 			return (CMD_RETURN_ERROR);
 		}
 		arg = args->argv[2];
+		break;
+	default:
+		if (args->argc != 2) {
+			cmdq_error(cmdq, "no argument allowed");
+			return (CMD_RETURN_ERROR);
+		}
+		arg = NULL;
+		break;
 	}
 
 	mtmp.key = key;
diff --git a/tmux.1 b/tmux.1
index 2764626e..abdeba54 100644
--- a/tmux.1
+++ b/tmux.1
@@ -987,15 +987,27 @@ command and keys modified or removed with
 .Ic bind-key
 and
 .Ic unbind-key .
-One command accepts an argument,
-.Ic copy-pipe ,
-which copies the selection and pipes it to a command.
+If
+.Ic append-selection ,
+.Ic copy-selection ,
+or
+.Ic start-named-buffer
+are given the
+.Fl x
+flag,
+.Nm
+will not exit copy mode after copying.
+.Ic copy-pipe
+copies the selection and pipes it to a command.
 For example the following will bind
+.Ql C-w
+not to exit after copying and
 .Ql C-q
 to copy the selection into
 .Pa /tmp
 as well as the paste buffer:
 .Bd -literal -offset indent
+bind-key -temacs-copy C-w copy-selection -x
 bind-key -temacs-copy C-q copy-pipe "cat >/tmp/out"
 .Ed
 .Pp
diff --git a/window-copy.c b/window-copy.c
index 074e7310..feb8c481 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -147,6 +147,7 @@ struct window_copy_mode_data {
 	enum window_copy_input_type inputtype;
 	const char     *inputprompt;
 	char	       *inputstr;
+	int		inputexit;
 
 	int		numprefix;
 
@@ -424,8 +425,12 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
 	case MODEKEYCOPY_APPENDSELECTION:
 		if (sess != NULL) {
 			window_copy_append_selection(wp, NULL);
-			window_pane_reset_mode(wp);
-			return;
+			if (arg == NULL) {
+				window_pane_reset_mode(wp);
+				return;
+			}
+			window_copy_clear_selection(wp);
+			window_copy_redraw_screen(wp);
 		}
 		break;
 	case MODEKEYCOPY_CANCEL:
@@ -572,8 +577,12 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
 	case MODEKEYCOPY_COPYSELECTION:
 		if (sess != NULL) {
 			window_copy_copy_selection(wp, NULL);
-			window_pane_reset_mode(wp);
-			return;
+			if (arg == NULL) {
+				window_pane_reset_mode(wp);
+				return;
+			}
+			window_copy_clear_selection(wp);
+			window_copy_redraw_screen(wp);
 		}
 		break;
 	case MODEKEYCOPY_STARTOFLINE:
@@ -718,6 +727,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
 		goto input_on;
 	case MODEKEYCOPY_STARTNAMEDBUFFER:
 		data->inputtype = WINDOW_COPY_NAMEDBUFFER;
+		data->inputexit = (arg == NULL);
 		data->inputprompt = "Buffer";
 		*data->inputstr = '\0';
 		goto input_on;
@@ -828,8 +838,13 @@ window_copy_key_input(struct window_pane *wp, int key)
 		case WINDOW_COPY_NAMEDBUFFER:
 			window_copy_copy_selection(wp, data->inputstr);
 			*data->inputstr = '\0';
-			window_pane_reset_mode(wp);
-			return (0);
+			if (data->inputexit) {
+				window_pane_reset_mode(wp);
+				return (0);
+			}
+			window_copy_clear_selection(wp);
+			window_copy_redraw_screen(wp);
+			break;
 		case WINDOW_COPY_GOTOLINE:
 			window_copy_goto_line(wp, data->inputstr);
 			*data->inputstr = '\0';