diff options
author | Nicholas Marriott <nicm@cvs.openbsd.org> | 2010-02-06 17:35:02 +0000 |
---|---|---|
committer | Nicholas Marriott <nicm@cvs.openbsd.org> | 2010-02-06 17:35:02 +0000 |
commit | d4cdb3a4db77c952208f555c9c00068f1fba9bd0 (patch) | |
tree | 2124a62e9a047a425491eb6842c02844695e78b1 | |
parent | 21895563586a7f5a6cf11c3b97d2c4a61555c122 (diff) |
Rectangle copy support, from Robin Lee Powell.
-rw-r--r-- | usr.bin/tmux/mode-key.c | 9 | ||||
-rw-r--r-- | usr.bin/tmux/screen.c | 115 | ||||
-rw-r--r-- | usr.bin/tmux/tmux.1 | 5 | ||||
-rw-r--r-- | usr.bin/tmux/tmux.h | 8 | ||||
-rw-r--r-- | usr.bin/tmux/window-copy.c | 114 |
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); +} + |