mirror of
https://github.com/tmux/tmux.git
synced 2025-01-12 03:08:46 +00:00
Change mouse selection so that after selecting a word, dragging selects
only words and similar for lines. From Anindya Mukherjee.
This commit is contained in:
parent
229be034fb
commit
f65b9c0d36
260
window-copy.c
260
window-copy.c
@ -119,8 +119,12 @@ static void window_copy_cursor_jump_to(struct window_mode_entry *);
|
|||||||
static void window_copy_cursor_jump_to_back(struct window_mode_entry *);
|
static void window_copy_cursor_jump_to_back(struct window_mode_entry *);
|
||||||
static void window_copy_cursor_next_word(struct window_mode_entry *,
|
static void window_copy_cursor_next_word(struct window_mode_entry *,
|
||||||
const char *);
|
const char *);
|
||||||
|
static void window_copy_cursor_next_word_end_pos(struct window_mode_entry *,
|
||||||
|
const char *, u_int *, u_int *);
|
||||||
static void window_copy_cursor_next_word_end(struct window_mode_entry *,
|
static void window_copy_cursor_next_word_end(struct window_mode_entry *,
|
||||||
const char *);
|
const char *);
|
||||||
|
static void window_copy_cursor_previous_word_pos(struct window_mode_entry *,
|
||||||
|
const char *, int, u_int *, u_int *);
|
||||||
static void window_copy_cursor_previous_word(struct window_mode_entry *,
|
static void window_copy_cursor_previous_word(struct window_mode_entry *,
|
||||||
const char *, int);
|
const char *, int);
|
||||||
static void window_copy_scroll_up(struct window_mode_entry *, u_int);
|
static void window_copy_scroll_up(struct window_mode_entry *, u_int);
|
||||||
@ -227,6 +231,22 @@ struct window_copy_mode_data {
|
|||||||
int rectflag; /* in rectangle copy mode? */
|
int rectflag; /* in rectangle copy mode? */
|
||||||
int scroll_exit; /* exit on scroll to end? */
|
int scroll_exit; /* exit on scroll to end? */
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SEL_CHAR, /* select one char at a time */
|
||||||
|
SEL_WORD, /* select one word at a time */
|
||||||
|
SEL_LINE, /* select one line at a time */
|
||||||
|
} selflag;
|
||||||
|
|
||||||
|
const char *ws; /* word separators */
|
||||||
|
|
||||||
|
u_int dx; /* drag start position */
|
||||||
|
u_int dy;
|
||||||
|
|
||||||
|
u_int selrx; /* selection reset positions */
|
||||||
|
u_int selry;
|
||||||
|
u_int endselrx;
|
||||||
|
u_int endselry;
|
||||||
|
|
||||||
u_int cx;
|
u_int cx;
|
||||||
u_int cy;
|
u_int cy;
|
||||||
|
|
||||||
@ -695,6 +715,9 @@ window_copy_cmd_begin_selection(struct window_copy_cmd_state *cs)
|
|||||||
struct client *c = cs->c;
|
struct client *c = cs->c;
|
||||||
struct mouse_event *m = cs->m;
|
struct mouse_event *m = cs->m;
|
||||||
struct window_copy_mode_data *data = wme->data;
|
struct window_copy_mode_data *data = wme->data;
|
||||||
|
struct options *oo = cs->s->options;
|
||||||
|
|
||||||
|
data->ws = options_get_string(oo, "word-separators");
|
||||||
|
|
||||||
if (m != NULL) {
|
if (m != NULL) {
|
||||||
window_copy_start_drag(c, m);
|
window_copy_start_drag(c, m);
|
||||||
@ -1507,12 +1530,19 @@ window_copy_cmd_select_line(struct window_copy_cmd_state *cs)
|
|||||||
|
|
||||||
data->lineflag = LINE_SEL_LEFT_RIGHT;
|
data->lineflag = LINE_SEL_LEFT_RIGHT;
|
||||||
data->rectflag = 0;
|
data->rectflag = 0;
|
||||||
|
data->selflag = SEL_LINE;
|
||||||
|
data->dx = data->cx;
|
||||||
|
data->dy = screen_hsize(data->backing) + data->cy - data->oy;
|
||||||
|
|
||||||
window_copy_cursor_start_of_line(wme);
|
window_copy_cursor_start_of_line(wme);
|
||||||
|
data->selrx = data->cx;
|
||||||
|
data->selry = screen_hsize(data->backing) + data->cy - data->oy;
|
||||||
window_copy_start_selection(wme);
|
window_copy_start_selection(wme);
|
||||||
for (; np > 1; np--)
|
for (; np > 1; np--)
|
||||||
window_copy_cursor_down(wme, 0);
|
window_copy_cursor_down(wme, 0);
|
||||||
window_copy_cursor_end_of_line(wme);
|
window_copy_cursor_end_of_line(wme);
|
||||||
|
data->endselrx = data->cx;
|
||||||
|
data->endselry = screen_hsize(data->backing) + data->cy - data->oy;
|
||||||
|
|
||||||
return (WINDOW_COPY_CMD_REDRAW);
|
return (WINDOW_COPY_CMD_REDRAW);
|
||||||
}
|
}
|
||||||
@ -1524,26 +1554,33 @@ window_copy_cmd_select_word(struct window_copy_cmd_state *cs)
|
|||||||
struct session *s = cs->s;
|
struct session *s = cs->s;
|
||||||
struct window_copy_mode_data *data = wme->data;
|
struct window_copy_mode_data *data = wme->data;
|
||||||
const char *ws;
|
const char *ws;
|
||||||
u_int px, py, xx;
|
u_int px, py;
|
||||||
|
|
||||||
data->lineflag = LINE_SEL_LEFT_RIGHT;
|
data->lineflag = LINE_SEL_LEFT_RIGHT;
|
||||||
data->rectflag = 0;
|
data->rectflag = 0;
|
||||||
|
data->selflag = SEL_WORD;
|
||||||
|
data->dx = data->cx;
|
||||||
|
data->dy = screen_hsize(data->backing) + data->cy - data->oy;
|
||||||
|
|
||||||
px = data->cx;
|
px = data->cx;
|
||||||
py = screen_hsize(data->backing) + data->cy - data->oy;
|
py = screen_hsize(data->backing) + data->cy - data->oy;
|
||||||
xx = window_copy_find_length(wme, py);
|
|
||||||
|
|
||||||
ws = options_get_string(s->options, "word-separators");
|
ws = options_get_string(s->options, "word-separators");
|
||||||
window_copy_cursor_previous_word(wme, ws, 0);
|
window_copy_cursor_previous_word(wme, ws, 0);
|
||||||
|
data->selrx = data->cx;
|
||||||
|
data->selry = screen_hsize(data->backing) + data->cy - data->oy;
|
||||||
window_copy_start_selection(wme);
|
window_copy_start_selection(wme);
|
||||||
|
|
||||||
if (px >= xx || !window_copy_in_set(wme, px + 1, py, ws))
|
if (px >= window_copy_find_length(wme, py) ||
|
||||||
|
!window_copy_in_set(wme, px + 1, py, ws))
|
||||||
window_copy_cursor_next_word_end(wme, ws);
|
window_copy_cursor_next_word_end(wme, ws);
|
||||||
else {
|
else {
|
||||||
window_copy_update_cursor(wme, px, data->cy);
|
window_copy_update_cursor(wme, px, data->cy);
|
||||||
if (window_copy_update_selection(wme, 1))
|
if (window_copy_update_selection(wme, 1))
|
||||||
window_copy_redraw_lines(wme, data->cy, 1);
|
window_copy_redraw_lines(wme, data->cy, 1);
|
||||||
}
|
}
|
||||||
|
data->endselrx = data->cx;
|
||||||
|
data->endselry = screen_hsize(data->backing) + data->cy - data->oy;
|
||||||
|
|
||||||
return (WINDOW_COPY_CMD_REDRAW);
|
return (WINDOW_COPY_CMD_REDRAW);
|
||||||
}
|
}
|
||||||
@ -2788,6 +2825,7 @@ static void
|
|||||||
window_copy_redraw_selection(struct window_mode_entry *wme, u_int old_y)
|
window_copy_redraw_selection(struct window_mode_entry *wme, u_int old_y)
|
||||||
{
|
{
|
||||||
struct window_copy_mode_data *data = wme->data;
|
struct window_copy_mode_data *data = wme->data;
|
||||||
|
struct grid *gd = data->backing->grid;
|
||||||
u_int new_y, start, end;
|
u_int new_y, start, end;
|
||||||
|
|
||||||
new_y = data->cy;
|
new_y = data->cy;
|
||||||
@ -2798,6 +2836,16 @@ window_copy_redraw_selection(struct window_mode_entry *wme, u_int old_y)
|
|||||||
start = new_y;
|
start = new_y;
|
||||||
end = old_y;
|
end = old_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In word selection mode the first word on the line below the cursor
|
||||||
|
* might be selected, so add this line to the redraw area.
|
||||||
|
*/
|
||||||
|
if (data->selflag == SEL_WORD) {
|
||||||
|
/* Last grid line in data coordinates. */
|
||||||
|
if (end < gd->sy + data->oy - 1)
|
||||||
|
end++;
|
||||||
|
}
|
||||||
window_copy_redraw_lines(wme, start, end - start + 1);
|
window_copy_redraw_lines(wme, start, end - start + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2825,22 +2873,82 @@ window_copy_redraw_screen(struct window_mode_entry *wme)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
window_copy_synchronize_cursor(struct window_mode_entry *wme)
|
window_copy_synchronize_cursor_end(struct window_mode_entry *wme)
|
||||||
{
|
{
|
||||||
struct window_copy_mode_data *data = wme->data;
|
struct window_copy_mode_data *data = wme->data;
|
||||||
u_int xx, yy;
|
u_int xx, yy;
|
||||||
|
int begin = 0;
|
||||||
|
|
||||||
xx = data->cx;
|
|
||||||
yy = screen_hsize(data->backing) + data->cy - data->oy;
|
yy = screen_hsize(data->backing) + data->cy - data->oy;
|
||||||
|
switch (data->selflag) {
|
||||||
|
case SEL_WORD:
|
||||||
|
xx = data->cx;
|
||||||
|
if (data->ws == NULL)
|
||||||
|
break;
|
||||||
|
if (data->dy > yy || (data->dy == yy && data->dx > xx)) {
|
||||||
|
/* Right to left selection. */
|
||||||
|
window_copy_cursor_previous_word_pos(wme, data->ws, 0,
|
||||||
|
&xx, &yy);
|
||||||
|
begin = 1;
|
||||||
|
|
||||||
|
/* Reset the end. */
|
||||||
|
data->endselx = data->endselrx;
|
||||||
|
data->endsely = data->endselry;
|
||||||
|
} else {
|
||||||
|
/* Left to right selection. */
|
||||||
|
if (xx >= window_copy_find_length(wme, yy) ||
|
||||||
|
!window_copy_in_set(wme, xx + 1, yy, data->ws))
|
||||||
|
window_copy_cursor_next_word_end_pos(wme,
|
||||||
|
data->ws, &xx, &yy);
|
||||||
|
|
||||||
|
/* Reset the start. */
|
||||||
|
data->selx = data->selrx;
|
||||||
|
data->sely = data->selry;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SEL_LINE:
|
||||||
|
if (data->dy > yy) {
|
||||||
|
/* Right to left selection. */
|
||||||
|
xx = 0;
|
||||||
|
begin = 1;
|
||||||
|
|
||||||
|
/* Reset the end. */
|
||||||
|
data->endselx = data->endselrx;
|
||||||
|
data->endsely = data->endselry;
|
||||||
|
} else {
|
||||||
|
/* Left to right selection. */
|
||||||
|
xx = window_copy_find_length(wme, yy);
|
||||||
|
|
||||||
|
/* Reset the start. */
|
||||||
|
data->selx = data->selrx;
|
||||||
|
data->sely = data->selry;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SEL_CHAR:
|
||||||
|
xx = data->cx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (begin) {
|
||||||
|
data->selx = xx;
|
||||||
|
data->sely = yy;
|
||||||
|
} else {
|
||||||
|
data->endselx = xx;
|
||||||
|
data->endsely = yy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
window_copy_synchronize_cursor(struct window_mode_entry *wme)
|
||||||
|
{
|
||||||
|
struct window_copy_mode_data *data = wme->data;
|
||||||
|
|
||||||
switch (data->cursordrag) {
|
switch (data->cursordrag) {
|
||||||
case CURSORDRAG_ENDSEL:
|
case CURSORDRAG_ENDSEL:
|
||||||
data->endselx = xx;
|
window_copy_synchronize_cursor_end(wme);
|
||||||
data->endsely = yy;
|
|
||||||
break;
|
break;
|
||||||
case CURSORDRAG_SEL:
|
case CURSORDRAG_SEL:
|
||||||
data->selx = xx;
|
data->selx = data->cx;
|
||||||
data->sely = yy;
|
data->sely = screen_hsize(data->backing) + data->cy - data->oy;
|
||||||
break;
|
break;
|
||||||
case CURSORDRAG_NONE:
|
case CURSORDRAG_NONE:
|
||||||
break;
|
break;
|
||||||
@ -3709,6 +3817,55 @@ window_copy_cursor_next_word(struct window_mode_entry *wme,
|
|||||||
window_copy_redraw_lines(wme, data->cy, 1);
|
window_copy_redraw_lines(wme, data->cy, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
window_copy_cursor_next_word_end_pos(struct window_mode_entry *wme,
|
||||||
|
const char *separators, u_int *ppx, u_int *ppy)
|
||||||
|
{
|
||||||
|
struct window_pane *wp = wme->wp;
|
||||||
|
struct window_copy_mode_data *data = wme->data;
|
||||||
|
struct options *oo = wp->window->options;
|
||||||
|
struct screen *back_s = data->backing;
|
||||||
|
u_int px, py, xx, yy;
|
||||||
|
int keys, expected = 1;
|
||||||
|
|
||||||
|
px = data->cx;
|
||||||
|
py = screen_hsize(back_s) + data->cy - data->oy;
|
||||||
|
xx = window_copy_find_length(wme, py);
|
||||||
|
yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
|
||||||
|
|
||||||
|
keys = options_get_number(oo, "mode-keys");
|
||||||
|
if (keys == MODEKEY_VI && !window_copy_in_set(wme, px, py, separators))
|
||||||
|
px++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First skip past any word characters, then any non-word characters.
|
||||||
|
*
|
||||||
|
* expected is initially set to 1 for the former and then 0 for the
|
||||||
|
* latter.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
while (px > xx ||
|
||||||
|
window_copy_in_set(wme, px, py, separators) == expected) {
|
||||||
|
/* Move down if we're past the end of the line. */
|
||||||
|
if (px > xx) {
|
||||||
|
if (py == yy)
|
||||||
|
return;
|
||||||
|
py++;
|
||||||
|
px = 0;
|
||||||
|
xx = window_copy_find_length(wme, py);
|
||||||
|
} else
|
||||||
|
px++;
|
||||||
|
}
|
||||||
|
expected = !expected;
|
||||||
|
} while (expected == 0);
|
||||||
|
|
||||||
|
if (keys == MODEKEY_VI && px != 0)
|
||||||
|
px--;
|
||||||
|
|
||||||
|
*ppx = px;
|
||||||
|
*ppy = py;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
window_copy_cursor_next_word_end(struct window_mode_entry *wme,
|
window_copy_cursor_next_word_end(struct window_mode_entry *wme,
|
||||||
const char *separators)
|
const char *separators)
|
||||||
@ -3761,6 +3918,54 @@ window_copy_cursor_next_word_end(struct window_mode_entry *wme,
|
|||||||
window_copy_redraw_lines(wme, data->cy, 1);
|
window_copy_redraw_lines(wme, data->cy, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compute the previous place where a word begins. */
|
||||||
|
static void
|
||||||
|
window_copy_cursor_previous_word_pos(struct window_mode_entry *wme,
|
||||||
|
const char *separators, int already, u_int *ppx, u_int *ppy)
|
||||||
|
{
|
||||||
|
struct window_copy_mode_data *data = wme->data;
|
||||||
|
u_int px, py;
|
||||||
|
|
||||||
|
px = data->cx;
|
||||||
|
py = screen_hsize(data->backing) + data->cy - data->oy;
|
||||||
|
|
||||||
|
/* Move back to the previous word character. */
|
||||||
|
if (already || window_copy_in_set(wme, px, py, separators)) {
|
||||||
|
for (;;) {
|
||||||
|
if (px > 0) {
|
||||||
|
px--;
|
||||||
|
if (!window_copy_in_set(wme, px, py,
|
||||||
|
separators))
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (data->cy == 0 &&
|
||||||
|
(screen_hsize(data->backing) == 0 ||
|
||||||
|
data->oy >=
|
||||||
|
screen_hsize(data->backing) - 1))
|
||||||
|
goto out;
|
||||||
|
py--;
|
||||||
|
|
||||||
|
py = screen_hsize(data->backing) + data->cy -
|
||||||
|
data->oy;
|
||||||
|
px = window_copy_find_length(wme, py);
|
||||||
|
|
||||||
|
/* Stop if separator at EOL. */
|
||||||
|
if (px > 0 && window_copy_in_set(wme, px - 1,
|
||||||
|
py, separators))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move back to the beginning of this word. */
|
||||||
|
while (px > 0 && !window_copy_in_set(wme, px - 1, py, separators))
|
||||||
|
px--;
|
||||||
|
|
||||||
|
out:
|
||||||
|
*ppx = px;
|
||||||
|
*ppy = py;
|
||||||
|
}
|
||||||
|
|
||||||
/* Move to the previous place where a word begins. */
|
/* Move to the previous place where a word begins. */
|
||||||
static void
|
static void
|
||||||
window_copy_cursor_previous_word(struct window_mode_entry *wme,
|
window_copy_cursor_previous_word(struct window_mode_entry *wme,
|
||||||
@ -3777,21 +3982,24 @@ window_copy_cursor_previous_word(struct window_mode_entry *wme,
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
if (px > 0) {
|
if (px > 0) {
|
||||||
px--;
|
px--;
|
||||||
if (!window_copy_in_set(wme, px, py, separators))
|
if (!window_copy_in_set(wme, px, py,
|
||||||
|
separators))
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
if (data->cy == 0 &&
|
if (data->cy == 0 &&
|
||||||
(screen_hsize(data->backing) == 0 ||
|
(screen_hsize(data->backing) == 0 ||
|
||||||
data->oy >= screen_hsize(data->backing) - 1))
|
data->oy >=
|
||||||
|
screen_hsize(data->backing) - 1))
|
||||||
goto out;
|
goto out;
|
||||||
window_copy_cursor_up(wme, 0);
|
window_copy_cursor_up(wme, 0);
|
||||||
|
|
||||||
py = screen_hsize(data->backing) + data->cy - data->oy;
|
py = screen_hsize(data->backing) + data->cy -
|
||||||
|
data->oy;
|
||||||
px = window_copy_find_length(wme, py);
|
px = window_copy_find_length(wme, py);
|
||||||
|
|
||||||
/* Stop if separator at EOL. */
|
/* Stop if separator at EOL. */
|
||||||
if (px > 0 &&
|
if (px > 0 && window_copy_in_set(wme, px - 1,
|
||||||
window_copy_in_set(wme, px - 1, py, separators))
|
py, separators))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3913,6 +4121,7 @@ window_copy_start_drag(struct client *c, struct mouse_event *m)
|
|||||||
{
|
{
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
struct window_mode_entry *wme;
|
struct window_mode_entry *wme;
|
||||||
|
struct window_copy_mode_data *data;
|
||||||
u_int x, y;
|
u_int x, y;
|
||||||
|
|
||||||
if (c == NULL)
|
if (c == NULL)
|
||||||
@ -3933,10 +4142,27 @@ window_copy_start_drag(struct client *c, struct mouse_event *m)
|
|||||||
c->tty.mouse_drag_update = window_copy_drag_update;
|
c->tty.mouse_drag_update = window_copy_drag_update;
|
||||||
c->tty.mouse_drag_release = window_copy_drag_release;
|
c->tty.mouse_drag_release = window_copy_drag_release;
|
||||||
|
|
||||||
window_copy_update_cursor(wme, x, y);
|
data = wme->data;
|
||||||
window_copy_start_selection(wme);
|
switch (data->selflag) {
|
||||||
window_copy_redraw_screen(wme);
|
case SEL_WORD:
|
||||||
|
if (data->ws) {
|
||||||
|
window_copy_update_cursor(wme, x, y);
|
||||||
|
window_copy_cursor_previous_word_pos(wme,
|
||||||
|
data->ws, 0, &x, &y);
|
||||||
|
y -= screen_hsize(data->backing) - data->oy;
|
||||||
|
}
|
||||||
|
window_copy_update_cursor(wme, x, y);
|
||||||
|
break;
|
||||||
|
case SEL_LINE:
|
||||||
|
window_copy_update_cursor(wme, 0, y);
|
||||||
|
break;
|
||||||
|
case SEL_CHAR:
|
||||||
|
window_copy_update_cursor(wme, x, y);
|
||||||
|
window_copy_start_selection(wme);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
window_copy_redraw_screen(wme);
|
||||||
window_copy_drag_update(c, m);
|
window_copy_drag_update(c, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user