1
0
mirror of https://github.com/tmux/tmux.git synced 2025-04-22 12:28:48 +00:00

Sync OpenBSD patchset 636:

Rectangle copy support, from Robin Lee Powell.
This commit is contained in:
Tiago Cunha 2010-02-08 18:13:17 +00:00
parent a32d095c97
commit 3c37b09272
5 changed files with 187 additions and 64 deletions

View File

@ -1,4 +1,4 @@
/* $Id: mode-key.c,v 1.42 2010-02-05 01:34:08 tcunha Exp $ */ /* $Id: mode-key.c,v 1.43 2010-02-08 18:13:17 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -89,6 +89,7 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
{ MODEKEYCOPY_HISTORYBOTTOM, "history-bottom" }, { MODEKEYCOPY_HISTORYBOTTOM, "history-bottom" },
{ MODEKEYCOPY_HISTORYTOP, "history-top" }, { MODEKEYCOPY_HISTORYTOP, "history-top" },
{ MODEKEYCOPY_LEFT, "cursor-left" }, { MODEKEYCOPY_LEFT, "cursor-left" },
{ MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" },
{ MODEKEYCOPY_MIDDLELINE, "middle-line" }, { MODEKEYCOPY_MIDDLELINE, "middle-line" },
{ MODEKEYCOPY_NEXTPAGE, "page-down" }, { MODEKEYCOPY_NEXTPAGE, "page-down" },
{ MODEKEYCOPY_NEXTSPACE, "next-space" }, { MODEKEYCOPY_NEXTSPACE, "next-space" },
@ -207,6 +208,7 @@ const struct mode_key_entry mode_key_vi_copy[] = {
{ 'l', 0, MODEKEYCOPY_RIGHT }, { 'l', 0, MODEKEYCOPY_RIGHT },
{ 'n', 0, MODEKEYCOPY_SEARCHAGAIN }, { 'n', 0, MODEKEYCOPY_SEARCHAGAIN },
{ 'q', 0, MODEKEYCOPY_CANCEL }, { 'q', 0, MODEKEYCOPY_CANCEL },
{ 'v', 0, MODEKEYCOPY_RECTANGLETOGGLE },
{ 'w', 0, MODEKEYCOPY_NEXTWORD }, { 'w', 0, MODEKEYCOPY_NEXTWORD },
{ KEYC_BSPACE, 0, MODEKEYCOPY_LEFT }, { KEYC_BSPACE, 0, MODEKEYCOPY_LEFT },
{ KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN }, { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN },
@ -276,9 +278,10 @@ struct mode_key_tree mode_key_tree_emacs_choice;
/* emacs copy mode keys. */ /* emacs copy mode keys. */
const struct mode_key_entry mode_key_emacs_copy[] = { const struct mode_key_entry mode_key_emacs_copy[] = {
{ ' ', 0, MODEKEYCOPY_NEXTPAGE }, { ' ', 0, MODEKEYCOPY_NEXTPAGE },
{ '<' | KEYC_ESCAPE,0, MODEKEYCOPY_HISTORYTOP }, { '<' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYTOP },
{ '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM }, { '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM },
{ 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE }, { 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE },
{ 'R', 0, MODEKEYCOPY_RECTANGLETOGGLE },
{ '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION }, { '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION },
{ '\001' /* C-a */, 0, MODEKEYCOPY_STARTOFLINE }, { '\001' /* C-a */, 0, MODEKEYCOPY_STARTOFLINE },
{ '\002' /* C-b */, 0, MODEKEYCOPY_LEFT }, { '\002' /* C-b */, 0, MODEKEYCOPY_LEFT },

115
screen.c
View File

@ -1,4 +1,4 @@
/* $Id: screen.c,v 1.98 2010-01-05 23:54:53 tcunha Exp $ */ /* $Id: screen.c,v 1.99 2010-02-08 18:13:17 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -227,41 +227,17 @@ screen_resize_y(struct screen *s, u_int sy)
/* Set selection. */ /* Set selection. */
void void
screen_set_selection(struct screen *s, screen_set_selection(struct screen *s, u_int sx, u_int sy,
u_int sx, u_int sy, u_int ex, u_int ey, struct grid_cell *gc) u_int ex, u_int ey, u_int rectflag, struct grid_cell *gc)
{ {
struct screen_sel *sel = &s->sel; struct screen_sel *sel = &s->sel;
memcpy(&sel->cell, gc, sizeof sel->cell); memcpy(&sel->cell, gc, sizeof sel->cell);
sel->flag = 1; sel->flag = 1;
sel->rectflag = rectflag;
/* starting line < ending line -- downward selection. */ sel->sx = sx; sel->sy = sy;
if (sy < ey) { sel->ex = ex; sel->ey = ey;
sel->sx = sx; sel->sy = sy;
sel->ex = ex; sel->ey = ey;
return;
}
/* starting line > ending line -- upward selection. */
if (sy > ey) {
if (sx > 0) {
sel->sx = ex; sel->sy = ey;
sel->ex = sx - 1; sel->ey = sy;
} else {
sel->sx = ex; sel->sy = ey;
sel->ex = -1; sel->ey = sy - 1;
}
return;
}
/* starting line == ending line. */
if (ex < sx) {
sel->sx = ex; sel->sy = ey;
sel->ex = sx - 1; sel->ey = sy;
} else {
sel->sx = sx; sel->sy = sy;
sel->ex = ex; sel->ey = ey;
}
} }
/* Clear selection. */ /* Clear selection. */
@ -279,16 +255,81 @@ screen_check_selection(struct screen *s, u_int px, u_int py)
{ {
struct screen_sel *sel = &s->sel; struct screen_sel *sel = &s->sel;
if (!sel->flag || py < sel->sy || py > sel->ey) if (!sel->flag)
return (0); return (0);
if (py == sel->sy && py == sel->ey) { if (sel->rectflag) {
if (px < sel->sx || px > sel->ex) if (sel->sy < sel->ey) {
return (0); /* start line < end line -- downward selection. */
return (1); if (py < sel->sy || py > sel->ey)
return (0);
} else if (sel->sy > sel->ey) {
/* start line > end line -- upward selection. */
if (py > sel->sy || py < sel->ey)
return (0);
} else {
/* starting line == ending line. */
if (py != sel->sy)
return (0);
}
/*
* Need to include the selection start row, but not the cursor
* row, which means the selection changes depending on which
* one is on the left.
*/
if (sel->ex < sel->sx) {
/* Cursor (ex) is on the left. */
if (px <= sel->ex)
return (0);
if (px > sel->sx)
return (0);
} else {
/* Selection start (sx) is on the left. */
if (px < sel->sx)
return (0);
if (px >= sel->ex)
return (0);
}
} else {
/*
* Like emacs, keep the top-left-most character, and drop the
* bottom-right-most, regardless of copy direction.
*/
if (sel->sy < sel->ey) {
/* starting line < ending line -- downward selection. */
if (py < sel->sy || py > sel->ey)
return (0);
if ((py == sel->sy && px < sel->sx)
|| (py == sel->ey && px > sel->ex))
return (0);
} else if (sel->sy > sel->ey) {
/* starting line > ending line -- upward selection. */
if (py > sel->sy || py < sel->ey)
return (0);
if ((py == sel->sy && px >= sel->sx)
|| (py == sel->ey && px < sel->ex))
return (0);
} else {
/* starting line == ending line. */
if (py != sel->sy)
return (0);
if (sel->ex < sel->sx) {
/* cursor (ex) is on the left */
if (px > sel->sx || px < sel->ex)
return (0);
} else {
/* selection start (sx) is on the left */
if (px < sel->sx || px > sel->ex)
return (0);
}
}
} }
if ((py == sel->sy && px < sel->sx) || (py == sel->ey && px > sel->ex))
return (0);
return (1); return (1);
} }

5
tmux.1
View File

@ -1,4 +1,4 @@
.\" $Id: tmux.1,v 1.228 2010-02-05 01:34:08 tcunha Exp $ .\" $Id: tmux.1,v 1.229 2010-02-08 18:13:17 tcunha Exp $
.\" .\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> .\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\" .\"
@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: February 4 2010 $ .Dd $Mdocdate: February 6 2010 $
.Dt TMUX 1 .Dt TMUX 1
.Os .Os
.Sh NAME .Sh NAME
@ -564,6 +564,7 @@ The following keys are supported as appropriate for the mode:
.It Li "Previous word" Ta "b" Ta "M-b" .It Li "Previous word" Ta "b" Ta "M-b"
.It Li "Previous space" Ta "B" Ta "" .It Li "Previous space" Ta "B" Ta ""
.It Li "Quit mode" Ta "q" Ta "Escape" .It Li "Quit mode" Ta "q" Ta "Escape"
.It Li "Rectangle toggle" Ta "v" Ta "R"
.It Li "Scroll down" Ta "C-Down or C-e" Ta "C-Down" .It Li "Scroll down" Ta "C-Down or C-e" Ta "C-Down"
.It Li "Scroll up" Ta "C-Up or C-y" Ta "C-Up" .It Li "Scroll up" Ta "C-Up or C-y" Ta "C-Up"
.It Li "Search again" Ta "n" Ta "n" .It Li "Search again" Ta "n" Ta "n"

8
tmux.h
View File

@ -1,4 +1,4 @@
/* $Id: tmux.h,v 1.541 2010-02-08 18:10:07 tcunha Exp $ */ /* $Id: tmux.h,v 1.542 2010-02-08 18:13:17 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -468,6 +468,7 @@ enum mode_key_cmd {
MODEKEYCOPY_PREVIOUSPAGE, MODEKEYCOPY_PREVIOUSPAGE,
MODEKEYCOPY_PREVIOUSSPACE, MODEKEYCOPY_PREVIOUSSPACE,
MODEKEYCOPY_PREVIOUSWORD, MODEKEYCOPY_PREVIOUSWORD,
MODEKEYCOPY_RECTANGLETOGGLE,
MODEKEYCOPY_RIGHT, MODEKEYCOPY_RIGHT,
MODEKEYCOPY_SCROLLDOWN, MODEKEYCOPY_SCROLLDOWN,
MODEKEYCOPY_SCROLLUP, MODEKEYCOPY_SCROLLUP,
@ -673,6 +674,7 @@ SLIST_HEAD(joblist, job);
/* Screen selection. */ /* Screen selection. */
struct screen_sel { struct screen_sel {
int flag; int flag;
int rectflag;
u_int sx; u_int sx;
u_int sy; u_int sy;
@ -1773,8 +1775,8 @@ void screen_free(struct screen *);
void screen_reset_tabs(struct screen *); void screen_reset_tabs(struct screen *);
void screen_set_title(struct screen *, const char *); void screen_set_title(struct screen *, const char *);
void screen_resize(struct screen *, u_int, u_int); void screen_resize(struct screen *, u_int, u_int);
void screen_set_selection( void screen_set_selection(struct screen *,
struct screen *, u_int, u_int, u_int, u_int, struct grid_cell *); u_int, u_int, u_int, u_int, u_int, struct grid_cell *);
void screen_clear_selection(struct screen *); void screen_clear_selection(struct screen *);
int screen_check_selection(struct screen *, u_int, u_int); int screen_check_selection(struct screen *, u_int, u_int);

View File

@ -1,4 +1,4 @@
/* $Id: window-copy.c,v 1.100 2010-02-05 01:34:08 tcunha Exp $ */ /* $Id: window-copy.c,v 1.101 2010-02-08 18:13:17 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -68,6 +68,7 @@ void window_copy_cursor_next_word_end(struct window_pane *, const char *);
void window_copy_cursor_previous_word(struct window_pane *, const char *); void window_copy_cursor_previous_word(struct window_pane *, const char *);
void window_copy_scroll_up(struct window_pane *, u_int); void window_copy_scroll_up(struct window_pane *, u_int);
void window_copy_scroll_down(struct window_pane *, u_int); void window_copy_scroll_down(struct window_pane *, u_int);
void window_copy_rectangle_toggle(struct window_pane *);
const struct window_mode window_copy_mode = { const struct window_mode window_copy_mode = {
window_copy_init, window_copy_init,
@ -95,6 +96,8 @@ struct window_copy_mode_data {
u_int selx; u_int selx;
u_int sely; u_int sely;
u_int rectflag; /* are we in rectangle copy mode? */
u_int cx; u_int cx;
u_int cy; u_int cy;
@ -126,6 +129,8 @@ window_copy_init(struct window_pane *wp)
data->lastcx = 0; data->lastcx = 0;
data->lastsx = 0; data->lastsx = 0;
data->rectflag = 0;
data->inputtype = WINDOW_COPY_OFF; data->inputtype = WINDOW_COPY_OFF;
data->inputprompt = NULL; data->inputprompt = NULL;
data->inputstr = xstrdup(""); data->inputstr = xstrdup("");
@ -379,6 +384,9 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
data->inputprompt = "Goto Line"; data->inputprompt = "Goto Line";
*data->inputstr = '\0'; *data->inputstr = '\0';
goto input_on; goto input_on;
case MODEKEYCOPY_RECTANGLETOGGLE:
window_copy_rectangle_toggle(wp);
return;
default: default:
break; break;
} }
@ -823,7 +831,7 @@ window_copy_update_selection(struct window_pane *wp)
struct screen *s = &data->screen; struct screen *s = &data->screen;
struct options *oo = &wp->window->options; struct options *oo = &wp->window->options;
struct grid_cell gc; struct grid_cell gc;
u_int sx, sy, ty; u_int sx, sy, ty, cy;
if (!s->sel.flag) if (!s->sel.flag)
return (0); return (0);
@ -841,17 +849,33 @@ window_copy_update_selection(struct window_pane *wp)
sx = data->selx; sx = data->selx;
sy = data->sely; sy = data->sely;
if (sy < ty) { /* above screen */ if (sy < ty) { /* above screen */
sx = 0; if (!data->rectflag)
sx = 0;
sy = 0; sy = 0;
} else if (sy > ty + screen_size_y(s) - 1) { /* below screen */ } else if (sy > ty + screen_size_y(s) - 1) { /* below screen */
sx = screen_size_x(s) - 1; if (!data->rectflag)
sx = screen_size_x(s) - 1;
sy = screen_size_y(s) - 1; sy = screen_size_y(s) - 1;
} else } else
sy -= ty; sy -= ty;
sy = screen_hsize(s) + sy; sy = screen_hsize(s) + sy;
screen_set_selection( screen_set_selection(s,
s, sx, sy, data->cx, screen_hsize(s) + data->cy, &gc); sx, sy, data->cx, screen_hsize(s) + data->cy, data->rectflag, &gc);
if (data->rectflag) {
/*
* Can't rely on the caller to redraw the right lines for
* rectangle selection - find the highest line and the number
* of lines, and redraw just past that in both directions
*/
cy = data->cy;
if (sy < cy)
window_copy_redraw_lines(wp, sy, cy - sy + 1);
else
window_copy_redraw_lines(wp, cy, sy - cy + 1);
}
return (1); return (1);
} }
@ -861,8 +885,9 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c)
struct window_copy_mode_data *data = wp->modedata; struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen; struct screen *s = &data->screen;
char *buf; char *buf;
size_t off; size_t off;
u_int i, xx, yy, sx, sy, ex, ey, limit; u_int i, xx, yy, sx, sy, ex, ey, limit;
u_int firstsx, lastex, restex, restsx;
if (!s->sel.flag) if (!s->sel.flag)
return; return;
@ -893,17 +918,53 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c)
if (ex > xx) if (ex > xx)
ex = xx; ex = xx;
/*
* Deal with rectangle-copy if necessary; four situations: start of
* first line (firstsx), end of last line (lastex), start (restsx) and
* end (restex) of all other lines.
*/
xx = screen_size_x(s);
if (data->rectflag) {
/*
* Need to ignore the column with the cursor in it, which for
* rectangular copy means knowing which side the cursor is on.
*/
if (data->selx < data->cx) {
/* Selection start is on the left. */
lastex = data->cx;
restex = data->cx;
firstsx = data->selx;
restsx = data->selx;
} else {
/* Cursor is on the left. */
lastex = data->selx + 1;
restex = data->selx + 1;
firstsx = data->cx + 1;
restsx = data->cx + 1;
}
} else {
/*
* Like emacs, keep the top-left-most character, and drop the
* bottom-right-most, regardless of copy direction.
*/
lastex = ex;
restex = xx;
firstsx = sx;
restsx = 0;
}
/* Copy the lines. */ /* Copy the lines. */
if (sy == ey) if (sy == ey)
window_copy_copy_line(wp, &buf, &off, sy, sx, ex); window_copy_copy_line(wp, &buf, &off, sy, firstsx, lastex);
else { else {
xx = screen_size_x(s); window_copy_copy_line(wp, &buf, &off, sy, firstsx, restex);
window_copy_copy_line(wp, &buf, &off, sy, sx, xx);
if (ey - sy > 1) { if (ey - sy > 1) {
for (i = sy + 1; i < ey; i++) for (i = sy + 1; i < ey; i++) {
window_copy_copy_line(wp, &buf, &off, i, 0, xx); window_copy_copy_line(
wp, &buf, &off, i, restsx, restex);
}
} }
window_copy_copy_line(wp, &buf, &off, ey, 0, ex); window_copy_copy_line(wp, &buf, &off, ey, restsx, lastex);
} }
/* Don't bother if no data. */ /* Don't bother if no data. */
@ -1288,7 +1349,6 @@ window_copy_scroll_up(struct window_pane *wp, u_int ny)
if (ny == 0) if (ny == 0)
return; return;
data->oy -= ny; data->oy -= ny;
window_copy_update_selection(wp);
screen_write_start(&ctx, wp, NULL); screen_write_start(&ctx, wp, NULL);
screen_write_cursormove(&ctx, 0, 0); screen_write_cursormove(&ctx, 0, 0);
@ -1299,9 +1359,12 @@ window_copy_scroll_up(struct window_pane *wp, u_int ny)
window_copy_write_line(wp, &ctx, 1); window_copy_write_line(wp, &ctx, 1);
if (screen_size_y(s) > 3) if (screen_size_y(s) > 3)
window_copy_write_line(wp, &ctx, screen_size_y(s) - 2); window_copy_write_line(wp, &ctx, screen_size_y(s) - 2);
if (s->sel.flag && screen_size_y(s) > ny) if (s->sel.flag && screen_size_y(s) > ny) {
window_copy_update_selection(wp);
window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1); window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1);
}
screen_write_cursormove(&ctx, data->cx, data->cy); screen_write_cursormove(&ctx, data->cx, data->cy);
window_copy_update_selection(wp);
screen_write_stop(&ctx); screen_write_stop(&ctx);
} }
@ -1320,16 +1383,29 @@ window_copy_scroll_down(struct window_pane *wp, u_int ny)
if (ny == 0) if (ny == 0)
return; return;
data->oy += ny; data->oy += ny;
window_copy_update_selection(wp);
screen_write_start(&ctx, wp, NULL); screen_write_start(&ctx, wp, NULL);
screen_write_cursormove(&ctx, 0, 0); screen_write_cursormove(&ctx, 0, 0);
screen_write_insertline(&ctx, ny); screen_write_insertline(&ctx, ny);
window_copy_write_lines(wp, &ctx, 0, ny); window_copy_write_lines(wp, &ctx, 0, ny);
if (s->sel.flag && screen_size_y(s) > ny) if (s->sel.flag && screen_size_y(s) > ny) {
window_copy_update_selection(wp);
window_copy_write_line(wp, &ctx, ny); window_copy_write_line(wp, &ctx, ny);
else if (ny == 1) /* nuke position */ } else if (ny == 1) /* nuke position */
window_copy_write_line(wp, &ctx, 1); window_copy_write_line(wp, &ctx, 1);
screen_write_cursormove(&ctx, data->cx, data->cy); screen_write_cursormove(&ctx, data->cx, data->cy);
window_copy_update_selection(wp);
screen_write_stop(&ctx); screen_write_stop(&ctx);
} }
void
window_copy_rectangle_toggle(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
data->rectflag = !data->rectflag;
window_copy_update_selection(wp);
window_copy_redraw_screen(wp);
}