On 2014-06-20 14:11 +0100, Nicholas Marriott wrote:
> Can you do these separately? Ie the double/triple click bit separate
> from the right drag bit.

OK, I've managed to cut the patch into 5 pieces.

Note: In order this to look correctly in vi mode, it needs my changes
from [1]. Can you look into that as well?

Thanks!

[1] http://sourceforge.net/p/tmux/mailman/message/32431246/

-- 
Balazs
>From c54fd2dad49eae576cc4c274086f9560474addaf Mon Sep 17 00:00:00 2001
From: Balazs Kezes <rlblas...@gmail.com>
Date: Sat, 21 Jun 2014 12:37:06 +0100
Subject: [PATCH 1/5] Fix mouse click counting

At this point this isn't used anywhere so this results in no functionality
change.
---
 tty-keys.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/tty-keys.c b/tty-keys.c
index 97b49a2..72eeb16 100644
--- a/tty-keys.c
+++ b/tty-keys.c
@@ -786,25 +786,25 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
 
 		m->button = 3;
 	} else if ((b & MOUSE_MASK_BUTTONS) == 3) {
-		if (~m->event & MOUSE_EVENT_DRAG && x == m->x && y == m->y)
+		if (~m->event & MOUSE_EVENT_DRAG && x == m->sx && y == m->sy) {
 			m->event = MOUSE_EVENT_CLICK;
-		else
+			m->clicks = (m->clicks + 1) % 3;
+		} else {
 			m->event = MOUSE_EVENT_DRAG;
+		}
 		m->event |= MOUSE_EVENT_UP;
 	} else {
 		if (b & MOUSE_MASK_DRAG)
 			m->event = MOUSE_EVENT_DRAG;
 		else {
-			if (m->event & MOUSE_EVENT_UP && x == m->x && y == m->y)
-				m->clicks = (m->clicks + 1) % 3;
-			else
-				m->clicks = 0;
-			m->sx = x;
-			m->sy = y;
 			m->event = MOUSE_EVENT_DOWN;
+			if (x != m->sx || y != m->sy)
+				m->clicks = 0;
 		}
 		m->button = (b & MOUSE_MASK_BUTTONS);
 	}
+	m->sx = x;
+	m->sy = y;
 
 	return (0);
 }
-- 
2.0.0.526.g5318336

>From 9d161e63f44910fbd0294310bd03bcf39f147726 Mon Sep 17 00:00:00 2001
From: Balazs Kezes <rlblas...@gmail.com>
Date: Sat, 21 Jun 2014 13:13:16 +0100
Subject: [PATCH 2/5] Refactor input_mouse()

Move "options_get_number(...)" out of the two conditions so that there's only
one call to it. Also add some cosmetic changes.
---
 input-keys.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/input-keys.c b/input-keys.c
index 7531f22..840104f 100644
--- a/input-keys.c
+++ b/input-keys.c
@@ -205,6 +205,7 @@ input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m)
 	size_t			 len;
 	struct paste_buffer	*pb;
 	u_int			 i;
+	int			 wheel;
 
 	/*
 	 * If the alternate screen is active and hasn't enabled the mouse, send
@@ -252,15 +253,20 @@ input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m)
 		return;
 	}
 
-	if (m->button == 1 && (m->event & MOUSE_EVENT_CLICK) &&
-	    options_get_number(&wp->window->options, "mode-mouse") == 1) {
-		pb = paste_get_top();
-		if (pb != NULL) {
-			paste_send_pane(pb, wp, "\r",
-			    wp->screen->mode & MODE_BRACKETPASTE);
+	if (options_get_number(&wp->window->options, "mode-mouse") != 1)
+		return;
+
+	/* We don't care about m->button in case of wheel events. */
+	wheel = (m->event & MOUSE_EVENT_WHEEL);
+	if (wp->mode == NULL && !wheel && m->button == 1) {
+		if (m->event & MOUSE_EVENT_CLICK) {
+			pb = paste_get_top();
+			if (pb != NULL) {
+				paste_send_pane(pb, wp, "\r",
+					wp->screen->mode & MODE_BRACKETPASTE);
+			}
 		}
-	} else if (m->button != 1 &&
-	    options_get_number(&wp->window->options, "mode-mouse") == 1) {
+	} else {
 		if (window_pane_set_mode(wp, &window_copy_mode) == 0) {
 			window_copy_init_from_pane(wp);
 			if (wp->mode->mouse != NULL)
-- 
2.0.0.526.g5318336

>From 18ca63c60b9e0ab404f93a63fd6d1252364ab7e6 Mon Sep 17 00:00:00 2001
From: Balazs Kezes <rlblas...@gmail.com>
Date: Sat, 21 Jun 2014 15:41:42 +0100
Subject: [PATCH 3/5] Extend selection with right click in copy mode

This changes the behavior of the mouse in the copy mode. Previously when you
released the left button you automatically left the copy mode. Not anymore. To
leave the copy mode you need to press the middle mouse button. Right click will
extend the current selection.

But also make sure that when you left click once that won't enter the copy mode
unless you start dragging. A common usecase is to use the left button to select
a pane - we don't want to break this case. Look at the logic around
quit_on_mouse_release for how is this behavior preserved.
---
 cmd-copy-mode.c |  2 +-
 input-keys.c    |  2 +-
 tmux.h          |  2 +-
 window-copy.c   | 66 +++++++++++++++++++++++++++++++++++++++++----------------
 4 files changed, 51 insertions(+), 21 deletions(-)

diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c
index f11c7af..7e1a995 100644
--- a/cmd-copy-mode.c
+++ b/cmd-copy-mode.c
@@ -56,7 +56,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq)
 	if (wp->mode != &window_copy_mode) {
 		if (window_pane_set_mode(wp, &window_copy_mode) != 0)
 			return (CMD_RETURN_NORMAL);
-		window_copy_init_from_pane(wp);
+		window_copy_init_from_pane(wp, 0);
 	}
 	if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
 		window_copy_pageup(wp);
diff --git a/input-keys.c b/input-keys.c
index 840104f..767bbdd 100644
--- a/input-keys.c
+++ b/input-keys.c
@@ -268,7 +268,7 @@ input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m)
 		}
 	} else {
 		if (window_pane_set_mode(wp, &window_copy_mode) == 0) {
-			window_copy_init_from_pane(wp);
+			window_copy_init_from_pane(wp, !wheel);
 			if (wp->mode->mouse != NULL)
 				wp->mode->mouse(wp, s, m);
 		}
diff --git a/tmux.h b/tmux.h
index c4c5236..2c178ad 100644
--- a/tmux.h
+++ b/tmux.h
@@ -2245,7 +2245,7 @@ extern const char window_clock_table[14][5][5];
 
 /* window-copy.c */
 extern const struct window_mode window_copy_mode;
-void		 window_copy_init_from_pane(struct window_pane *);
+void		 window_copy_init_from_pane(struct window_pane *, int);
 void		 window_copy_init_for_output(struct window_pane *);
 void printflike2 window_copy_add(struct window_pane *, const char *, ...);
 void		 window_copy_vadd(struct window_pane *, const char *, va_list);
diff --git a/window-copy.c b/window-copy.c
index 0775bcb..f398771 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -154,6 +154,8 @@ struct window_copy_mode_data {
 
 	enum window_copy_input_type jumptype;
 	char		jumpchar;
+
+	int		quit_on_mouse_release;
 };
 
 struct screen *
@@ -189,6 +191,8 @@ window_copy_init(struct window_pane *wp)
 	data->jumptype = WINDOW_COPY_OFF;
 	data->jumpchar = '\0';
 
+	data->quit_on_mouse_release = 0;
+
 	s = &data->screen;
 	screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
 	if (options_get_number(&wp->window->options, "mode-mouse"))
@@ -206,7 +210,7 @@ window_copy_init(struct window_pane *wp)
 }
 
 void
-window_copy_init_from_pane(struct window_pane *wp)
+window_copy_init_from_pane(struct window_pane *wp, int quit_on_mouse_release)
 {
 	struct window_copy_mode_data	*data = wp->modedata;
 	struct screen			*s = &data->screen;
@@ -219,6 +223,7 @@ window_copy_init_from_pane(struct window_pane *wp)
 	data->backing = &wp->base;
 	data->cx = data->backing->cx;
 	data->cy = data->backing->cy;
+	data->quit_on_mouse_release = quit_on_mouse_release;
 
 	s->cx = data->cx;
 	s->cy = data->cy;
@@ -869,6 +874,14 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key)
 	return (0);
 }
 
+static void
+window_copy_select_via_mouse(struct window_pane *wp, struct mouse_event *m)
+{
+	window_copy_update_cursor(wp, m->x, m->y);
+	if (window_copy_update_selection(wp, 1))
+		window_copy_redraw_screen(wp);
+}
+
 void
 window_copy_mouse(
     struct window_pane *wp, struct session *sess, struct mouse_event *m)
@@ -876,6 +889,7 @@ window_copy_mouse(
 	struct window_copy_mode_data	*data = wp->modedata;
 	struct screen			*s = &data->screen;
 	u_int				 i;
+	int				 pressed, released, dragged;
 
 	if (m->x >= screen_size_x(s))
 		return;
@@ -901,35 +915,51 @@ window_copy_mouse(
 		return;
 	}
 
-	/*
-	 * If already reading motion, move the cursor while buttons are still
-	 * pressed, or stop the selection on their release.
-	 */
-	if (s->mode & MODE_MOUSE_BUTTON) {
-		if (~m->event & MOUSE_EVENT_UP) {
-			window_copy_update_cursor(wp, m->x, m->y);
-			if (window_copy_update_selection(wp, 1))
-				window_copy_redraw_screen(wp);
-			return;
-		}
-		goto reset_mode;
-	}
+	pressed = (m->event & MOUSE_EVENT_DOWN);
+	released = (m->event & MOUSE_EVENT_UP);
+	dragged = (m->event & MOUSE_EVENT_DRAG);
 
-	/* Otherwise if other buttons pressed, start selection and motion. */
-	if (~m->event & MOUSE_EVENT_UP) {
+	if (!(s->mode & MODE_MOUSE_BUTTON) && pressed) {
 		s->mode &= ~MODE_MOUSE_STANDARD;
 		s->mode |= MODE_MOUSE_BUTTON;
+	} else if ((s->mode & MODE_MOUSE_BUTTON) && released) {
+		s->mode &= ~MODE_MOUSE_BUTTON;
+		s->mode |= MODE_MOUSE_STANDARD;
+	}
 
+	if (data->quit_on_mouse_release && m->clicks == 1 && released) {
+		if (sess != NULL)
+			window_pane_reset_mode(wp);
+		return;
+	} else if (!pressed) {
+		/* Let's reset this on release, dragged or wheel events. */
+		data->quit_on_mouse_release = 0;
+	}
+
+	if (m->button == 1) {
+		if (released)
+			goto reset_mode;
+		else
+			return;
+	}
+
+	if (pressed && m->button == 0 && !s->sel.flag) {
 		window_copy_update_cursor(wp, m->x, m->y);
 		window_copy_start_selection(wp);
 		window_copy_redraw_screen(wp);
 	}
 
+	if (dragged || (pressed && m->button == 2)) {
+		window_copy_select_via_mouse(wp, m);
+	} else if (pressed && m->button == 0) {
+		window_copy_update_cursor(wp, m->x, m->y);
+		window_copy_start_selection(wp);
+		window_copy_select_via_mouse(wp, m);
+	}
+
 	return;
 
 reset_mode:
-	s->mode &= ~MODE_MOUSE_BUTTON;
-	s->mode |= MODE_MOUSE_STANDARD;
 	if (sess != NULL) {
 		window_copy_copy_selection(wp, NULL);
 		window_pane_reset_mode(wp);
-- 
2.0.0.526.g5318336

>From e6aeaac3a96b44fcc5e713d89c8ab8ce7cfd385b Mon Sep 17 00:00:00 2001
From: Balazs Kezes <rlblas...@gmail.com>
Date: Sat, 21 Jun 2014 16:05:04 +0100
Subject: [PATCH 4/5] Select words/lines on double/triple clicks in copy mode

This also affects right clicks.
---
 window-copy.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 83 insertions(+), 5 deletions(-)

diff --git a/window-copy.c b/window-copy.c
index f398771..29fa1ab 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -156,6 +156,8 @@ struct window_copy_mode_data {
 	char		jumpchar;
 
 	int		quit_on_mouse_release;
+	u_int		mouse_sx, mouse_sy; /* the starting point of dragging */
+	u_int		mouse_x0, mouse_x1; /* possible starting points */
 };
 
 struct screen *
@@ -875,9 +877,51 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key)
 }
 
 static void
-window_copy_select_via_mouse(struct window_pane *wp, struct mouse_event *m)
+window_copy_select_via_mouse(
+	struct window_pane *wp, struct mouse_event *m, const char *sep)
 {
+	struct window_copy_mode_data	*data = wp->modedata;
+	int				 dir;
+	u_int				 my, by;
+
+	/*
+	 * Based on where the user pressed when they started the selection and
+	 * where is the current mouse position, extend the selection. Care needs
+	 * to be taken to ensure character/word/line modes are respected.
+	 */
+
+	/* Make sure the starting place is correct. */
 	window_copy_update_cursor(wp, m->x, m->y);
+	my = data->mouse_sy;
+	by = screen_hsize(data->backing) + data->cy - data->oy;
+	if (by < my || (by == my && data->cx < data->mouse_sx)) {
+		dir = -1;
+		data->selx = data->mouse_x1;
+	} else {
+		dir = +1;
+		data->selx = data->mouse_x0;
+	}
+
+	if (m->clicks == 0) {
+		window_copy_update_cursor(wp, m->x, m->y);
+		if (window_copy_update_selection(wp, 1))
+			window_copy_redraw_screen(wp);
+	} else if (m->clicks == 1) {
+		if (dir < 0) {
+			data->cx += 1; /* Handle first letter clicks. */
+			window_copy_cursor_previous_word(wp, sep);
+		} else {
+			if (data->cx > 0)
+				data->cx -= 1; /* Handle last letter clicks. */
+			window_copy_cursor_next_word_end(wp, sep);
+		}
+	} else if (m->clicks == 2) {
+		if (dir < 0)
+			window_copy_cursor_start_of_line(wp);
+		else
+			window_copy_cursor_end_of_line(wp);
+	}
+
 	if (window_copy_update_selection(wp, 1))
 		window_copy_redraw_screen(wp);
 }
@@ -888,8 +932,9 @@ window_copy_mouse(
 {
 	struct window_copy_mode_data	*data = wp->modedata;
 	struct screen			*s = &data->screen;
-	u_int				 i;
+	u_int				 i, mouse_backing_y;
 	int				 pressed, released, dragged;
+	const char			*sep;
 
 	if (m->x >= screen_size_x(s))
 		return;
@@ -918,6 +963,8 @@ window_copy_mouse(
 	pressed = (m->event & MOUSE_EVENT_DOWN);
 	released = (m->event & MOUSE_EVENT_UP);
 	dragged = (m->event & MOUSE_EVENT_DRAG);
+	mouse_backing_y = screen_hsize(data->backing) + m->y - data->oy;
+	sep = options_get_string(&sess->options, "word-separators");
 
 	if (!(s->mode & MODE_MOUSE_BUTTON) && pressed) {
 		s->mode &= ~MODE_MOUSE_STANDARD;
@@ -945,16 +992,47 @@ window_copy_mouse(
 
 	if (pressed && m->button == 0 && !s->sel.flag) {
 		window_copy_update_cursor(wp, m->x, m->y);
+		data->mouse_sx = m->x;
+		data->mouse_sy = mouse_backing_y;
+		data->mouse_x0 = m->x;
+		data->mouse_x1 = m->x;
 		window_copy_start_selection(wp);
 		window_copy_redraw_screen(wp);
 	}
 
 	if (dragged || (pressed && m->button == 2)) {
-		window_copy_select_via_mouse(wp, m);
+		window_copy_select_via_mouse(wp, m, sep);
 	} else if (pressed && m->button == 0) {
+		/*
+		 * Single click: normal selection.
+		 * Double click: word selection.
+		 * Triple click: line selection.
+		 */
+
 		window_copy_update_cursor(wp, m->x, m->y);
-		window_copy_start_selection(wp);
-		window_copy_select_via_mouse(wp, m);
+		data->mouse_sx = m->x;
+		data->mouse_sy = mouse_backing_y;
+		if (m->clicks == 0) {
+			window_copy_start_selection(wp);
+			data->mouse_x0 = m->x;
+			data->mouse_x1 = m->x;
+		} else if (m->clicks == 1) {
+			if (data->cx > 0)
+				data->cx -= 1; /* Handle last letter clicks. */
+			window_copy_cursor_next_word_end(wp, sep);
+			data->mouse_x1 = data->cx;
+			data->cx += 1; /* Handle single letter words. */
+			window_copy_cursor_previous_word(wp, sep);
+			data->mouse_x0 = data->cx;
+			window_copy_start_selection(wp);
+		} else if (m->clicks == 2) {
+			window_copy_cursor_end_of_line(wp);
+			data->mouse_x1 = data->cx;
+			window_copy_cursor_start_of_line(wp);
+			data->mouse_x0 = data->cx;
+			window_copy_start_selection(wp);
+		}
+		window_copy_select_via_mouse(wp, m, sep);
 	}
 
 	return;
-- 
2.0.0.526.g5318336

>From 98b144375ce2af1cee4b54253362bd96907ff573 Mon Sep 17 00:00:00 2001
From: Balazs Kezes <rlblas...@gmail.com>
Date: Sat, 21 Jun 2014 16:15:09 +0100
Subject: [PATCH 5/5] Update documentation about the new mouse behavior

---
 CHANGES | 12 ++++++++++++
 tmux.1  |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/CHANGES b/CHANGES
index abd1ac0..67fe5a5 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,15 @@
+CHANGES FROM 1.9a to 1.10 TBD
+
+Incompatible Changes
+====================
+
+* New mouse selection mechanism when mouse mode is enabled: Left button starts
+  the selection. You can double/triple click in order to select full
+  words/lines. Right button will extend the selection from the original starting
+  point to the mouse position. You can quit the copy mode via the middle button
+  which will copy the current selection. Note that the word separating
+  characters are coming from the "word-separators" option.
+
 CHANGES FROM 1.9 to 1.9a 22 February 2014
 
 NOTE:  This is a bug-fix release to address some important bugs which just
diff --git a/tmux.1 b/tmux.1
index 924157d..7682dde 100644
--- a/tmux.1
+++ b/tmux.1
@@ -2827,6 +2827,13 @@ If set to
 .Em copy-mode ,
 the mouse behaves as set to on, but cannot be used to enter copy
 mode.
+
+When enabled then in copy mode left button starts the selection. You can
+double/triple click in order to select full words/lines. Right button will
+extend the selection from the original starting point to the mouse position. You
+can quit the copy mode via the middle button which will copy the current
+selection. Note that the word separating characters are coming from the
+"word-separators" option.
 .Pp
 .It Ic mode-style Ar style
 Set window modes style.
-- 
2.0.0.526.g5318336

------------------------------------------------------------------------------
HPCC Systems Open Source Big Data Platform from LexisNexis Risk Solutions
Find What Matters Most in Your Big Data with HPCC Systems
Open Source. Fast. Scalable. Simple. Ideal for Dirty Data.
Leverages Graph Analysis for Fast Processing & Easy Data Exploration
http://p.sf.net/sfu/hpccsystems
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to