=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/window-copy.c,v retrieving revision 1.160 retrieving revision 1.161 diff -c -r1.160 -r1.161 *** src/usr.bin/tmux/window-copy.c 2016/11/15 09:53:23 1.160 --- src/usr.bin/tmux/window-copy.c 2016/11/24 13:38:44 1.161 *************** *** 1,4 **** ! /* $OpenBSD: window-copy.c,v 1.160 2016/11/15 09:53:23 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott --- 1,4 ---- ! /* $OpenBSD: window-copy.c,v 1.161 2016/11/24 13:38:44 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott *************** *** 62,68 **** --- 62,71 ---- static void window_copy_goto_line(struct window_pane *, const char *); static void window_copy_update_cursor(struct window_pane *, u_int, u_int); static void window_copy_start_selection(struct window_pane *); + static int window_copy_adjust_selection(struct window_pane *, u_int *, + u_int *); static int window_copy_update_selection(struct window_pane *, int); + static void window_copy_synchronize_cursor(struct window_pane *wp); static void *window_copy_get_selection(struct window_pane *, size_t *); static void window_copy_copy_buffer(struct window_pane *, const char *, void *, size_t); *************** *** 119,139 **** WINDOW_COPY_JUMPTOBACKWARD, }; /* ! * Copy-mode's visible screen (the "screen" field) is filled from one of ! * two sources: the original contents of the pane (used when we ! * actually enter via the "copy-mode" command, to copy the contents of ! * the current pane), or else a series of lines containing the output ! * from an output-writing tmux command (such as any of the "show-*" or ! * "list-*" commands). * ! * In either case, the full content of the copy-mode grid is pointed at ! * by the "backing" field, and is copied into "screen" as needed (that ! * is, when scrolling occurs). When copy-mode is backed by a pane, ! * backing points directly at that pane's screen structure (&wp->base); ! * when backed by a list of output-lines from a command, it points at ! * a newly-allocated screen structure (which is deallocated when the ! * mode ends). */ struct window_copy_mode_data { struct screen screen; --- 122,146 ---- WINDOW_COPY_JUMPTOBACKWARD, }; + enum { + WINDOW_COPY_REL_POS_ABOVE, + WINDOW_COPY_REL_POS_ON_SCREEN, + WINDOW_COPY_REL_POS_BELOW, + }; + /* ! * Copy mode's visible screen (the "screen" field) is filled from one of two ! * sources: the original contents of the pane (used when we actually enter via ! * the "copy-mode" command, to copy the contents of the current pane), or else ! * a series of lines containing the output from an output-writing tmux command ! * (such as any of the "show-*" or "list-*" commands). * ! * In either case, the full content of the copy-mode grid is pointed at by the ! * "backing" field, and is copied into "screen" as needed (that is, when ! * scrolling occurs). When copy-mode is backed by a pane, backing points ! * directly at that pane's screen structure (&wp->base); when backed by a list ! * of output-lines from a command, it points at a newly-allocated screen ! * structure (which is deallocated when the mode ends). */ struct window_copy_mode_data { struct screen screen; *************** *** 141,151 **** struct screen *backing; int backing_written; /* backing display started */ ! u_int oy; ! u_int selx; u_int sely; int rectflag; /* in rectangle copy mode? */ int scroll_exit; /* exit on scroll to end? */ --- 148,167 ---- struct screen *backing; int backing_written; /* backing display started */ ! u_int oy; /* number of lines scrolled up */ ! u_int selx; /* beginning of selection */ u_int sely; + u_int endselx; /* end of selection */ + u_int endsely; + + enum { + CURSORDRAG_NONE, /* selection is independent of cursor */ + CURSORDRAG_ENDSEL, /* end is synchronized with cursor */ + CURSORDRAG_SEL, /* start is synchronized with cursor */ + } cursordrag; + int rectflag; /* in rectangle copy mode? */ int scroll_exit; /* exit on scroll to end? */ *************** *** 173,178 **** --- 189,196 ---- data->cx = 0; data->cy = 0; + data->cursordrag = CURSORDRAG_NONE; + data->lastcx = 0; data->lastsx = 0; *************** *** 358,364 **** { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; ! u_int n, ox, oy; oy = screen_hsize(data->backing) + data->cy - data->oy; ox = window_copy_find_length(wp, oy); --- 376,382 ---- { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; ! u_int n, ox, oy, px, py; oy = screen_hsize(data->backing) + data->cy - data->oy; ox = window_copy_find_length(wp, oy); *************** *** 386,394 **** data->oy -= n; if (!data->screen.sel.flag || !data->rectflag) { ! u_int py = screen_hsize(data->backing) + data->cy - data->oy; ! u_int px = window_copy_find_length(wp, py); ! if ((data->cx >= data->lastsx && data->cx != px) || data->cx > px) window_copy_cursor_end_of_line(wp); } --- 404,413 ---- data->oy -= n; if (!data->screen.sel.flag || !data->rectflag) { ! py = screen_hsize(data->backing) + data->cy - data->oy; ! px = window_copy_find_length(wp, py); ! if ((data->cx >= data->lastsx && data->cx != px) || ! data->cx > px) window_copy_cursor_end_of_line(wp); } *************** *** 514,519 **** --- 533,540 ---- window_copy_redraw_screen(wp); } } + if (strcmp(command, "stop-selection") == 0) + data->cursordrag = CURSORDRAG_NONE; if (strcmp(command, "bottom-line") == 0) { data->cx = 0; data->cy = screen_size_y(sn) - 1; *************** *** 1151,1156 **** --- 1172,1200 ---- } static void + window_copy_synchronize_cursor(struct window_pane *wp) + { + struct window_copy_mode_data *data = wp->modedata; + u_int xx, yy; + + xx = data->cx; + yy = screen_hsize(data->backing) + data->cy - data->oy; + + switch (data->cursordrag) { + case CURSORDRAG_ENDSEL: + data->endselx = xx; + data->endsely = yy; + break; + case CURSORDRAG_SEL: + data->selx = xx; + data->sely = yy; + break; + case CURSORDRAG_NONE: + break; + } + } + + static void window_copy_update_cursor(struct window_pane *wp, u_int cx, u_int cy) { struct window_copy_mode_data *data = wp->modedata; *************** *** 1180,1225 **** data->selx = data->cx; data->sely = screen_hsize(data->backing) + data->cy - data->oy; s->sel.flag = 1; window_copy_update_selection(wp, 1); } static int window_copy_update_selection(struct window_pane *wp, int may_redraw) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; struct options *oo = wp->window->options; struct grid_cell gc; ! u_int sx, sy, ty, cy; if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE) return (0); ! /* Set colours. */ ! style_apply(&gc, oo, "mode-style"); - /* Find top of screen. */ - ty = screen_hsize(data->backing) - data->oy; - /* Adjust the selection. */ sx = data->selx; sy = data->sely; ! if (sy < ty) { /* above screen */ ! if (!data->rectflag) ! sx = 0; ! sy = 0; ! } else if (sy > ty + screen_size_y(s) - 1) { /* below screen */ ! 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, data->rectflag, &gc); if (data->rectflag && may_redraw) { /* * Can't rely on the caller to redraw the right lines for --- 1224,1306 ---- data->selx = data->cx; data->sely = screen_hsize(data->backing) + data->cy - data->oy; + data->endselx = data->selx; + data->endsely = data->sely; + + data->cursordrag = CURSORDRAG_ENDSEL; + s->sel.flag = 1; window_copy_update_selection(wp, 1); } static int + window_copy_adjust_selection(struct window_pane *wp, u_int *selx, u_int *sely) + { + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + u_int sx, sy, ty; + int relpos; + + sx = *selx; + sy = *sely; + + ty = screen_hsize(data->backing) - data->oy; + if (sy < ty) { + relpos = WINDOW_COPY_REL_POS_ABOVE; + if (!data->rectflag) + sx = 0; + sy = 0; + } else if (sy > ty + screen_size_y(s) - 1) { + relpos = WINDOW_COPY_REL_POS_BELOW; + if (!data->rectflag) + sx = screen_size_x(s) - 1; + sy = screen_size_y(s) - 1; + } else { + relpos = WINDOW_COPY_REL_POS_ON_SCREEN; + sy -= ty; + } + + *selx = sx; + *sely = screen_hsize(s) + sy; + return (relpos); + } + + static int window_copy_update_selection(struct window_pane *wp, int may_redraw) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; struct options *oo = wp->window->options; struct grid_cell gc; ! u_int sx, sy, cy, endsx, endsy; ! int startrelpos, endrelpos; if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE) return (0); ! window_copy_synchronize_cursor(wp); /* Adjust the selection. */ sx = data->selx; sy = data->sely; ! startrelpos = window_copy_adjust_selection(wp, &sx, &sy); ! /* Adjust the end of selection. */ ! endsx = data->endselx; ! endsy = data->endsely; ! endrelpos = window_copy_adjust_selection(wp, &endsx, &endsy); + /* Selection is outside of the current screen */ + if (startrelpos == endrelpos && + startrelpos != WINDOW_COPY_REL_POS_ON_SCREEN) { + screen_hide_selection(s); + return (0); + } + + /* Set colours and selection. */ + style_apply(&gc, oo, "mode-style"); + screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag, &gc); + if (data->rectflag && may_redraw) { /* * Can't rely on the caller to redraw the right lines for *************** *** 1261,1268 **** */ /* Find start and end. */ ! xx = data->cx; ! yy = screen_hsize(data->backing) + data->cy - data->oy; if (yy < data->sely || (yy == data->sely && xx < data->selx)) { sx = xx; sy = yy; ex = data->selx; ey = data->sely; --- 1342,1349 ---- */ /* Find start and end. */ ! xx = data->endselx; ! yy = data->endsely; if (yy < data->sely || (yy == data->sely && xx < data->selx)) { sx = xx; sy = yy; ex = data->selx; ey = data->sely; *************** *** 1500,1505 **** --- 1581,1588 ---- screen_clear_selection(&data->screen); + data->cursordrag = CURSORDRAG_NONE; + py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wp, py); if (data->cx > px) *************** *** 1630,1636 **** { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; ! u_int selx, sely, cx, cy, yy, hsize; if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE) return; --- 1713,1719 ---- { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; ! u_int selx, sely, cy, yy, hsize; if (!s->sel.flag && s->sel.lineflag == LINE_SEL_NONE) return; *************** *** 1640,1665 **** else if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT) s->sel.lineflag = LINE_SEL_LEFT_RIGHT; ! selx = data->selx; ! sely = data->sely; ! cx = data->cx; cy = data->cy; yy = screen_hsize(data->backing) + data->cy - data->oy; - data->selx = cx; - data->sely = yy; data->cx = selx; hsize = screen_hsize(data->backing); ! if (sely < hsize - data->oy) { data->oy = hsize - sely; data->cy = 0; ! } else if (sely > hsize - data->oy + screen_size_y(s)) { data->oy = hsize - sely + screen_size_y(s) - 1; data->cy = screen_size_y(s) - 1; } else data->cy = cy + sely - yy; window_copy_redraw_screen(wp); } --- 1723,1761 ---- else if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT) s->sel.lineflag = LINE_SEL_LEFT_RIGHT; ! switch (data->cursordrag) { ! case CURSORDRAG_NONE: ! case CURSORDRAG_SEL: ! data->cursordrag = CURSORDRAG_ENDSEL; ! break; ! case CURSORDRAG_ENDSEL: ! data->cursordrag = CURSORDRAG_SEL; ! break; ! } ! ! selx = data->endselx; ! sely = data->endsely; ! if (data->cursordrag == CURSORDRAG_SEL) { ! selx = data->selx; ! sely = data->sely; ! } ! cy = data->cy; yy = screen_hsize(data->backing) + data->cy - data->oy; data->cx = selx; hsize = screen_hsize(data->backing); ! if (sely < hsize - data->oy) { /* above */ data->oy = hsize - sely; data->cy = 0; ! } else if (sely > hsize - data->oy + screen_size_y(s)) { /* below */ data->oy = hsize - sely + screen_size_y(s) - 1; data->cy = screen_size_y(s) - 1; } else data->cy = cy + sely - yy; + window_copy_update_selection(wp, 1); window_copy_redraw_screen(wp); }