summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2010-02-06 17:35:02 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2010-02-06 17:35:02 +0000
commitd4cdb3a4db77c952208f555c9c00068f1fba9bd0 (patch)
tree2124a62e9a047a425491eb6842c02844695e78b1
parent21895563586a7f5a6cf11c3b97d2c4a61555c122 (diff)
Rectangle copy support, from Robin Lee Powell.
-rw-r--r--usr.bin/tmux/mode-key.c9
-rw-r--r--usr.bin/tmux/screen.c115
-rw-r--r--usr.bin/tmux/tmux.15
-rw-r--r--usr.bin/tmux/tmux.h8
-rw-r--r--usr.bin/tmux/window-copy.c114
5 files changed, 187 insertions, 64 deletions
diff --git a/usr.bin/tmux/mode-key.c b/usr.bin/tmux/mode-key.c
index 0ce58eaca96..2f2538c83f5 100644
--- a/usr.bin/tmux/mode-key.c
+++ b/usr.bin/tmux/mode-key.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mode-key.c,v 1.31 2010/02/04 20:00:26 nicm Exp $ */
+/* $OpenBSD: mode-key.c,v 1.32 2010/02/06 17:35:01 nicm Exp $ */
/*
* 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_HISTORYTOP, "history-top" },
{ MODEKEYCOPY_LEFT, "cursor-left" },
+ { MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" },
{ MODEKEYCOPY_MIDDLELINE, "middle-line" },
{ MODEKEYCOPY_NEXTPAGE, "page-down" },
{ MODEKEYCOPY_NEXTSPACE, "next-space" },
@@ -207,6 +208,7 @@ const struct mode_key_entry mode_key_vi_copy[] = {
{ 'l', 0, MODEKEYCOPY_RIGHT },
{ 'n', 0, MODEKEYCOPY_SEARCHAGAIN },
{ 'q', 0, MODEKEYCOPY_CANCEL },
+ { 'v', 0, MODEKEYCOPY_RECTANGLETOGGLE },
{ 'w', 0, MODEKEYCOPY_NEXTWORD },
{ KEYC_BSPACE, 0, MODEKEYCOPY_LEFT },
{ KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN },
@@ -276,9 +278,10 @@ struct mode_key_tree mode_key_tree_emacs_choice;
/* emacs copy mode keys. */
const struct mode_key_entry mode_key_emacs_copy[] = {
{ ' ', 0, MODEKEYCOPY_NEXTPAGE },
- { '<' | KEYC_ESCAPE,0, MODEKEYCOPY_HISTORYTOP },
- { '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM },
+ { '<' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYTOP },
+ { '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM },
{ 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE },
+ { 'R', 0, MODEKEYCOPY_RECTANGLETOGGLE },
{ '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION },
{ '\001' /* C-a */, 0, MODEKEYCOPY_STARTOFLINE },
{ '\002' /* C-b */, 0, MODEKEYCOPY_LEFT },
diff --git a/usr.bin/tmux/screen.c b/usr.bin/tmux/screen.c
index 239d2d70858..cf9f50a6a57 100644
--- a/usr.bin/tmux/screen.c
+++ b/usr.bin/tmux/screen.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: screen.c,v 1.13 2010/01/03 17:12:04 nicm Exp $ */
+/* $OpenBSD: screen.c,v 1.14 2010/02/06 17:35:01 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -228,41 +228,17 @@ screen_resize_y(struct screen *s, u_int sy)
/* Set selection. */
void
-screen_set_selection(struct screen *s,
- u_int sx, u_int sy, u_int ex, u_int ey, struct grid_cell *gc)
+screen_set_selection(struct screen *s, u_int sx, u_int sy,
+ u_int ex, u_int ey, u_int rectflag, struct grid_cell *gc)
{
struct screen_sel *sel = &s->sel;
memcpy(&sel->cell, gc, sizeof sel->cell);
sel->flag = 1;
+ sel->rectflag = rectflag;
- /* starting line < ending line -- downward selection. */
- if (sy < 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;
- }
+ sel->sx = sx; sel->sy = sy;
+ sel->ex = ex; sel->ey = ey;
}
/* Clear selection. */
@@ -280,16 +256,81 @@ screen_check_selection(struct screen *s, u_int px, u_int py)
{
struct screen_sel *sel = &s->sel;
- if (!sel->flag || py < sel->sy || py > sel->ey)
+ if (!sel->flag)
return (0);
- if (py == sel->sy && py == sel->ey) {
- if (px < sel->sx || px > sel->ex)
- return (0);
- return (1);
+ if (sel->rectflag) {
+ if (sel->sy < sel->ey) {
+ /* start line < end line -- downward selection. */
+ 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);
}
diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1
index a978a56471b..a5da4297f16 100644
--- a/usr.bin/tmux/tmux.1
+++ b/usr.bin/tmux/tmux.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.146 2010/02/04 20:00:26 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.147 2010/02/06 17:35:01 nicm Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\"
@@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" 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
.Os
.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 space" Ta "B" Ta ""
.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 up" Ta "C-Up or C-y" Ta "C-Up"
.It Li "Search again" Ta "n" Ta "n"
diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h
index f2ff1aa4789..b7a5ad027ec 100644
--- a/usr.bin/tmux/tmux.h
+++ b/usr.bin/tmux/tmux.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.203 2010/02/06 17:15:33 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.204 2010/02/06 17:35:01 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -469,6 +469,7 @@ enum mode_key_cmd {
MODEKEYCOPY_PREVIOUSPAGE,
MODEKEYCOPY_PREVIOUSSPACE,
MODEKEYCOPY_PREVIOUSWORD,
+ MODEKEYCOPY_RECTANGLETOGGLE,
MODEKEYCOPY_RIGHT,
MODEKEYCOPY_SCROLLDOWN,
MODEKEYCOPY_SCROLLUP,
@@ -674,6 +675,7 @@ SLIST_HEAD(joblist, job);
/* Screen selection. */
struct screen_sel {
int flag;
+ int rectflag;
u_int sx;
u_int sy;
@@ -1774,8 +1776,8 @@ void screen_free(struct screen *);
void screen_reset_tabs(struct screen *);
void screen_set_title(struct screen *, const char *);
void screen_resize(struct screen *, u_int, u_int);
-void screen_set_selection(
- struct screen *, u_int, u_int, u_int, u_int, struct grid_cell *);
+void screen_set_selection(struct screen *,
+ u_int, u_int, u_int, u_int, u_int, struct grid_cell *);
void screen_clear_selection(struct screen *);
int screen_check_selection(struct screen *, u_int, u_int);
diff --git a/usr.bin/tmux/window-copy.c b/usr.bin/tmux/window-copy.c
index 9f17a0de50a..f0dd8eb3596 100644
--- a/usr.bin/tmux/window-copy.c
+++ b/usr.bin/tmux/window-copy.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: window-copy.c,v 1.41 2010/02/04 20:00:26 nicm Exp $ */
+/* $OpenBSD: window-copy.c,v 1.42 2010/02/06 17:35:01 nicm Exp $ */
/*
* 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_scroll_up(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 = {
window_copy_init,
@@ -95,6 +96,8 @@ struct window_copy_mode_data {
u_int selx;
u_int sely;
+ u_int rectflag; /* are we in rectangle copy mode? */
+
u_int cx;
u_int cy;
@@ -126,6 +129,8 @@ window_copy_init(struct window_pane *wp)
data->lastcx = 0;
data->lastsx = 0;
+ data->rectflag = 0;
+
data->inputtype = WINDOW_COPY_OFF;
data->inputprompt = NULL;
data->inputstr = xstrdup("");
@@ -379,6 +384,9 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
data->inputprompt = "Goto Line";
*data->inputstr = '\0';
goto input_on;
+ case MODEKEYCOPY_RECTANGLETOGGLE:
+ window_copy_rectangle_toggle(wp);
+ return;
default:
break;
}
@@ -823,7 +831,7 @@ window_copy_update_selection(struct window_pane *wp)
struct screen *s = &data->screen;
struct options *oo = &wp->window->options;
struct grid_cell gc;
- u_int sx, sy, ty;
+ u_int sx, sy, ty, cy;
if (!s->sel.flag)
return (0);
@@ -841,17 +849,33 @@ window_copy_update_selection(struct window_pane *wp)
sx = data->selx;
sy = data->sely;
if (sy < ty) { /* above screen */
- sx = 0;
+ if (!data->rectflag)
+ sx = 0;
sy = 0;
} 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;
} else
sy -= ty;
sy = screen_hsize(s) + sy;
- screen_set_selection(
- s, sx, sy, data->cx, screen_hsize(s) + data->cy, &gc);
+ screen_set_selection(s,
+ 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);
}
@@ -861,8 +885,9 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c)
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
char *buf;
- size_t off;
- u_int i, xx, yy, sx, sy, ex, ey, limit;
+ size_t off;
+ u_int i, xx, yy, sx, sy, ex, ey, limit;
+ u_int firstsx, lastex, restex, restsx;
if (!s->sel.flag)
return;
@@ -893,17 +918,53 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c)
if (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. */
if (sy == ey)
- window_copy_copy_line(wp, &buf, &off, sy, sx, ex);
+ window_copy_copy_line(wp, &buf, &off, sy, firstsx, lastex);
else {
- xx = screen_size_x(s);
- window_copy_copy_line(wp, &buf, &off, sy, sx, xx);
+ window_copy_copy_line(wp, &buf, &off, sy, firstsx, restex);
if (ey - sy > 1) {
- for (i = sy + 1; i < ey; i++)
- window_copy_copy_line(wp, &buf, &off, i, 0, xx);
+ for (i = sy + 1; i < ey; i++) {
+ 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. */
@@ -1288,7 +1349,6 @@ window_copy_scroll_up(struct window_pane *wp, u_int ny)
if (ny == 0)
return;
data->oy -= ny;
- window_copy_update_selection(wp);
screen_write_start(&ctx, wp, NULL);
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);
if (screen_size_y(s) > 3)
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);
+ }
screen_write_cursormove(&ctx, data->cx, data->cy);
+ window_copy_update_selection(wp);
screen_write_stop(&ctx);
}
@@ -1320,16 +1383,29 @@ window_copy_scroll_down(struct window_pane *wp, u_int ny)
if (ny == 0)
return;
data->oy += ny;
- window_copy_update_selection(wp);
screen_write_start(&ctx, wp, NULL);
screen_write_cursormove(&ctx, 0, 0);
screen_write_insertline(&ctx, 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);
- else if (ny == 1) /* nuke position */
+ } else if (ny == 1) /* nuke position */
window_copy_write_line(wp, &ctx, 1);
screen_write_cursormove(&ctx, data->cx, data->cy);
+ window_copy_update_selection(wp);
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);
+}
+